森林扩张

森林扩张

我正在尝试将宏扩展为forest树中样式的一部分。

以下是 MWE:

\documentclass[tikz,border=5pt]{standalone}
\usepackage{forest,ifthen}
\begin{document}
\bracketset{action character=@}
\newcount\linesleptcount
\newcounter{lineleaps}
\setcounter{lineleaps}{0}
\newcommand\prooftreeleaping[2]{%
  @@\linesleptcount=1
  \edef\xtemp{[#2]}%
  \whiledo{#1 > \the\linesleptcount}{%
    \advance\linesleptcount1
    \let\oldxtemp\xtemp
    \edef\xtemp{@+[, shape=coordinate, \oldxtemp]}%
  }%
  \expandafter\bracketResume\xtemp
}
\forestset{
  declare count={leaps}{0},
  to line/.style n args=2{
      replace by={
        @+\prooftreeleaping{#1}{#2}
    },
  },
}
\begin{forest}
  [first line
    [second line]
    [staying put,
      @+\prooftreeleaping{3}{moving down}
    ]
    [staying put,
%     to line={3}{getting stuck}
    ]
  ]
\end{forest}
\end{document}

这很好用:

向下移动

但是,如果我取消注释

%     to line={3}{getting stuck}

它不起作用。具体来说,它告诉我它正在插入\csname,然后它抱怨宏中的控制序列不应在内使用\csname... \endcsname

! Missing \endcsname inserted.
<to be read again> 
                   \linesleptcount 
l.41 \end{forest}

? h
The control sequence marked <to be read again> should
not appear between \csname and \endcsname.

预期输出是:

不会卡住

我该如何解决这个问题?

请注意,如果这看起来是一件奇怪的事情,那么这是我正在尝试的一件更大的事情的一部分,而且由于各种原因,这将超出网站对帖子的字符限制,目前这似乎是最没有前途的方法。(基本上,我不想to line要求single branches防护树

答案1

replace by和其他动态树键只需检查参数是否以 开头即可检查其参数是否为节点规范[(请参阅 的定义\forest@nodehandleby@nnb@checkfirst)。 在您的例子中,它不是,因此 forest 尝试将其解释@+\prooftreeleaping{#1}{#2}为节点遍历。

我想这应该在文档中提到。会的。(我认为实施其他检查不值得付出努力。)

一种解决方法可能是重新定义\prooftreeleaping为仅产生节点的内容,即没有外部的[],就像我下面做的那样。请注意,所需的效果不是通过实现的replace by,而是通过实现的。(此外,定义中的append节点是不必要的。)@+\xtemp

\newcommand\prooftreeleaping[2]{%
  @@\linesleptcount=1
  \edef\xtemp{#2}%
  \whiledo{#1 > \the\linesleptcount}{%
    \advance\linesleptcount1
    \let\oldxtemp\xtemp
    \edef\xtemp{, shape=coordinate, [\oldxtemp]}%
  }%
  \expandafter\bracketResume\xtemp
}
\forestset{
  declare count={leaps}{0},
  to line/.style n args=2{
      append={
        [@+\prooftreeleaping{#1}{#2}]
    },
  },
}

答案2

这并不是对问题的直接回答。相反,它说明了涉及这个问题的过程的结果。

phantom编辑:v0.06 取消了指定根节点的需要,尽管如果不使用定理语句,仍然需要留下一个空节点。更重要的是,它提供了一个环境作为forest样式的替代方案。环境确实不是需要一个空根。相反,你只需启动树。语法是

\begin{prooftree}{<options>}
  <proof using bracket notation>
\end{prooftree}

如果使用环境,证明甚至不需要有一个根prooftree。(当然,通常会有一个根。)

要指定定理陈述,您可以使用to prove={<theorem statement>}传递给 的选项中的选项prooftree

强制参数由树的前言组成。它可以是空的,但必须给出。它可能包括提供的选项prooftree以及您原本要放在forest树的前言中的任何内容。通常,选项将是提供的选项prooftree,当然,因为样式非常具体。但是,理论上,您可以prooftree通过覆盖所有操作,就像在前言中<options>指定样式后一样。proof treeforest

例如,以下创建了两对相同的树。第一对使用环境prooftree。第二对使用样式proof tree forest。第一对不包含定理陈述,因此第二对必须以空节点开头,因为它用作proof tree样式forest。然而,第一对以第一个假设开头,因为它使用新prooftree环境。

\documentclass[tikz,border=5pt,multi]{standalone}
\usepackage{etex,prooftrees}
\usepackage{amssymb}
\usepackage{mathtools,turnstile}
\newcommand*{\tnot}{\ensuremath{\mathord{\sim}}}
\begin{document}
  \begin{prooftree}{single branches}
        [$P \vee (Q \vee \lnot R)$, grouped,  just=Ass
        [$P \supset \lnot R$, grouped,  just=Ass
        [$Q \supset \lnot R$, grouped,  just=Ass
        [$\lnot\lnot R$, grouped, just={Negated conclusion}
          [$P$,  just={1 $\vee$ Elim}
            [$\lnot R$,  close, just={2,5 $\supset$ Elim; 5 $\vee$ Elim}
            ]
          ]
          [$Q \vee \lnot R$
            [$Q$
              [$\lnot R$,  close, just={3,6 $\supset$ Elim}
              ]
            ]
            [$\lnot R$, close
            ]
          ]
        ]
        ]
        ]
        ]
  \end{prooftree}
 \begin{forest}
    proof tree,
    single branches,
    [
        [$P \vee (Q \vee \lnot R)$, grouped,  just=Ass
        [$P \supset \lnot R$, grouped,  just=Ass
        [$Q \supset \lnot R$, grouped,  just=Ass
        [$\lnot\lnot R$, grouped, just={Negated conclusion}
          [$P$,  just={1 $\vee$ Elim}
            [$\lnot R$,  close, just={2,5 $\supset$ Elim; 5 $\vee$ Elim}
            ]
          ]
          [$Q \vee \lnot R$
            [$Q$
              [$\lnot R$,  close, just={3,6 $\supset$ Elim}
              ]
            ]
            [$\lnot R$, close
            ]
          ]
        ]
        ]
        ]
        ]
    ]
  \end{forest}

  \begin{prooftree}
    {
      to prove={$(\exists x)(\forall y)(Py \equiv x = y) \vdash (\exists x)((\forall y)(Py \supset x = y) \,\&\, Px)$}
    }
    [{$(\exists x)(\forall y)(Py \equiv x = y)\ \checkmark a$}, just={Premise}
      [{$\tnot (\exists x)((\forall y)(Py \supset x = y) \,\&\, Px)\ \backslash a$}, just={Conclusion negated}
        [{$(\forall y)(Py \equiv a = y)\ \backslash a,b$}, just={From 1}
          [{$\tnot ((\forall y)(Py \supset a = y) \,\&\, Pa)\ \checkmark$}, just={From 2}
            [{$Pa \equiv a = a\ \checkmark$}, just={From 3}
              [{$Pa$}, just={From 5}
                [{$a = a$}, just={From 5}
                  [{$\tnot (\forall y)(Py \supset a = y)\ \checkmark b$}, just={From 4}
                    [{$\tnot (Pb \supset a = b)\ \checkmark$}, just={From 8}
                      [{$Pb$}, just={From 9}
                        [{$a \neq b$}, just={From 9}
                          [{$Pb \equiv a = b\ \checkmark$}, just={From 3}
                            [{$Pb$}, just={From 12}
                              [{$a = b$}, just={From 12}
                                [{$a \neq a$}, just={From 11,14}, close
                                ]
                              ]
                            ]
                            [{$\tnot Pb$}
                              [{$a \neq b$}, close
                              ]
                            ]
                          ]
                        ]
                      ]
                    ]
                  ]
                  [{$\tnot Pa$}, close
                  ]
                ]
              ]
              [{$\tnot Pa$}
                [{$a \neq a$}, close
                ]
              ]
            ]
          ]
        ]
      ]
    ]
  \end{prooftree}
  \begin{forest}
    proof tree,
    [{$(\exists x)(\forall y)(Py \equiv x = y) \vdash (\exists x)((\forall y)(Py \supset x = y) \,\&\, Px)$}
      [{$(\exists x)(\forall y)(Py \equiv x = y)\ \checkmark a$}, just={Premise}
        [{$\tnot (\exists x)((\forall y)(Py \supset x = y) \,\&\, Px)\ \backslash a$}, just={Conclusion negated}
          [{$(\forall y)(Py \equiv a = y)\ \backslash a,b$}, just={From 1}
            [{$\tnot ((\forall y)(Py \supset a = y) \,\&\, Pa)\ \checkmark$}, just={From 2}
              [{$Pa \equiv a = a\ \checkmark$}, just={From 3}
                [{$Pa$}, just={From 5}
                  [{$a = a$}, just={From 5}
                    [{$\tnot (\forall y)(Py \supset a = y)\ \checkmark b$}, just={From 4}
                      [{$\tnot (Pb \supset a = b)\ \checkmark$}, just={From 8}
                        [{$Pb$}, just={From 9}
                          [{$a \neq b$}, just={From 9}
                            [{$Pb \equiv a = b\ \checkmark$}, just={From 3}
                              [{$Pb$}, just={From 12}
                                [{$a = b$}, just={From 12}
                                  [{$a \neq a$}, just={From 11,14}, close
                                  ]
                                ]
                              ]
                              [{$\tnot Pb$}
                                [{$a \neq b$}, close
                                ]
                              ]
                            ]
                          ]
                        ]
                      ]
                    ]
                    [{$\tnot Pa$}, close
                    ]
                  ]
                ]
                [{$\tnot Pa$}
                  [{$a \neq a$}, close
                  ]
                ]
              ]
            ]
          ]
        ]
      ]
    ]
  \end{forest}
\end{document}

第一对树中的第一棵树(第二棵相同):

<code>prooftree</code> 树证明

第二对树中的第一棵树(第二棵是相同的):

<code>prooftree</code> 树证明

软件包代码(v0.06):

%% Copyright 2015 Clea F. Rees
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{svn-prov}
\ProvidesPackageSVN{$Id: prooftrees.sty 3594 2015-06-22 02:12:59Z cfrees $}[v0.06 \filebase \revinfo]
\RequirePackage{forest}
\newcounter{prooftree@countlevels}% count the levels in the proof tree
\setcounter{prooftree@countlevels}{0}
\newcount\prooftree@lcount% count the line numbers (on the left)
\newcount\prooftree@jcount% count the justifications (on the right)
\forestset{
  declare boolean={numbers}{0},% line numbering
  declare boolean={justifiers}{0},% line justifications
  declare boolean={verticals}{0},% single branches
  grouped/.style={% this adjusts the alignment of line numbers and justifications when some levels of the tree are grouped together either whenever the number of children is only 1 or by applying the grouped style to particular nodes when specifying the tree
    before computing xy={
      l=\baselineskip,
      if={\forestove{numbers}==1}{
        if={\forestove{justifiers}==1}{
          node walk={
            every step/.style={l=\baselineskip},
            after walk/.style={l=\baselineskip},
            name/.wrap pgfmath arg={just ##1}{level()},
            name/.wrap pgfmath arg={line no ##1}{level()},
          },
        }{
          node walk={
            after walk/.style={l=\baselineskip},
            name/.wrap pgfmath arg={line no ##1}{level()},
          },
        },
      }{
        if={\forestove{justifiers}==1}{
          node walk={
            after walk/.style={l=\baselineskip},
            name/.wrap pgfmath arg={just ##1}{level()}
          },
        }{},
      },
    },
    no edge,
  },
  close/.style={
    label={[yshift=2.5pt]below:$\otimes$},
  },
  line no/.style={% creates the line numbers on the left
    no edge,
    before typesetting nodes={% page 51
      TeX={\advance\prooftree@lcount1},
      content/.expanded={\the\prooftree@lcount.},% content i.e. the line number
      name/.expanded={line no \the\prooftree@lcount},% name them so they can be moved later
      if={\the\prooftree@lcount>2}{% the initial location of most line numbers is incorrect and they must be moved
        for previous={% move the line number below the previous line number
          append/.expanded={line no \the\prooftree@lcount}
        },
      }{},
    },
  },
  line justification/.style={% creates the justifications on the right but does not yet specify any content
    anchor=base west,
    no edge,
    before typesetting nodes={% page 51
      TeX={\advance\prooftree@jcount1},
      name/.expanded={just \the\prooftree@jcount},% name them so they can be moved
      if={\the\prooftree@jcount>2}{% correct the location as for the line numbers (cf. line no style)
        for previous={
          append/.expanded={just \the\prooftree@jcount}
        },
      }{},
    },
  },
  line numbering/.style={
    for tree={numbers},
  },
  no line numbering/.style={
    for tree={not numbers},
  },
  line justifications/.style={
    for tree={justifiers},
  },
  no line justifications/.style={
    for tree={not justifiers},
  },
  single branches/.style={
    for tree={verticals},
  },
  no single branches/.style={
    for tree={not verticals},
  },
  to prove/.style={
    before typesetting nodes={
      if level=0{
        content={#1},
        phantom=false,
      }{}
    }
  },
  proof tree/.style={
    for tree={
      parent anchor=south,
      line numbering,
      delay={
        where content={}{
          shape=coordinate,
        }{}
      },
    },
    where level=0{
      for children={
        no edge,
      },
      delay={
        if content={}{phantom}{},
        if={(\forestove{numbers}==1) || (\forestove{justifiers}==1)}{% count the levels if necessary
          for descendants={
            if={level()>\value{prooftree@countlevels}}{
              TeX={
                \stepcounter{prooftree@countlevels}
              },
            }{},
          },
        }{},
        if={(\forestove{numbers}==1)}{% create the line numbers if appropriate
          prepend={
            [,
              line no,
              repeat={\value{prooftree@countlevels}-1}{% most are created in the wrong place but line no moves them later
                delay n={\the\prooftree@lcount}{
                    append={[, line no]}
                },
              }
            ]
          },
        }{},
        if={(\forestove{justifiers}==1}{% create the nodes which will hold the justifications, if required
          append={
            [,
              fit=rectangle,
              line justification,
              repeat={\value{prooftree@countlevels}-1}{% most are created in the wrong place but line justification moves them later
                delay n={\the\prooftree@jcount}{
                  append={[, line justification]}
                },
              }
            ]
          }
        }{},
      },
    }{
      delay={
        if={(\forestove{verticals}==0}{% automatically group lines if not using single branches
          if n children=1{
            for children={
              if ={(\forestove{verticals}==0}{
                grouped
              }{},
            }
          }{},
        }{},
      }
    },
    before packing={
      for tree={
        tier/.wrap pgfmath arg={tier ##1}{level()},
      },
    },
  },
  just/.style={
    if={\forestove{justifiers}==0}{
      for root={
        line justifications,
      },
    }{},
      before packing={% puts the content of the justifications into the empty justification nodes on the right; because this is done late, the nodes need to be typeset again
        for={name/.wrap pgfmath arg={just ##1}{level()}}{
          content={#1},
          typeset node
        },
      }
  },
  toing/.style={% this is here so I can easily override no edge when to line={} is used
    edge path={
      \noexpand\path [draw, \forestoption{edge}] (!u.parent anchor) -- (.child anchor)\forestoption{edge label};
    },
  },
  to line/.style={% this option is intended for use with justifications and, although it should not give an error, it will have no effect in other cases (There is simply no reason to typeset a proof with this if not giving justifications, that I can think of)
    if={#1>\value{prooftree@countlevels}}{% ensure that we get enough lines in the tree since #1 may well specify a line which would not otherwise exist
      TeX={
        \setcounter{prooftree@countlevels}{#1}
      },
    }{},
    if={#1>level()}{% only try to move the node if the target line number exceeds the current level
      if={\forestove{justifiers}==0}{% don't do anything if there are no justifications - there is no point in moving things in such a case
      }{
        if={\forestove{verticals}==0}{% if no single branches, get the vertical alignment from the correctly aligned line justification
          before drawing tree={
            y/.wrap pgfmath arg={##1}{y("!name={just #1}")},
            toing
          },
        }{
          before packing={% if single branches, a simple tier alignment suffices
            tier=tier #1,
          },
        },
      },
    }{},
  },
  just to line/.style n args=2{
    if={\forestove{justifiers}==0}{
      for root={
        line justifications,
      },
    }{},
    if={#1>\value{prooftree@countlevels}}{% make sure the tree contains enough lines since #1 may exceed the total line count otherwise
      TeX={
        \setcounter{prooftree@countlevels}{#1}
      },
    }{},
    if={#1>level()}{% only if the target line number exceeds the current level
      before packing={
        for={name={just #1}}{% specify the content of the target line justification and, because this is done late, typeset the node again
          content={#2},
          typeset node
        },
      }
    }{% do nothing if the target line number is less than the current level
      if={#1==level()}{% only if the target line number equals the current level
        just=#2,
      }{},
    },
  },
}
\environbodyname\prooftreebody
\bracketset{action character=@}
\NewEnviron{prooftree}[1]{% \forest/\endforest from egreg's answer at http://tex.stackexchange.com/a/229608/
  \forest
    proof tree,
    #1,
    [@\prooftreebody]
  \endforest}
\endinput
%% end prooftrees.sty

相关内容