编辑

编辑
\documentclass[oneside,12pt]{article}
\usepackage{geometry}
\usepackage{microtype}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}

\usepackage{enumitem}
\setlist[enumerate,1]{label=\bfseries\Alph*,align=left,leftmargin=*,
  labelsep=1.5em}
\setlist[enumerate,2]{label=\arabic*.,labelindent=1em,labelsep=1.5em,
  leftmargin=*}

\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{amsthm}
\theoremstyle{definition}
\newtheorem*{sol}{Solution}

\usepackage{forest}
\forestset{
  ass/.append style={
    before computing xy={l=\baselineskip},
    no edge
  },
  prooftree/.style={
    for tree={
      child anchor=north,
      parent anchor=south
    }
  }
}

\begin{document}
\subsection*{Exercises 29}
\begin{enumerate}
\item Use QL trees to evaluate the entailment claims (1) to (10) in Exercises
  28A.
  \begin{enumerate}
  \item $\forall x(Fx\supset Gx)\vDash\forall x(Gx\supset Fx)$

    \begin{forest}
      prooftree
      [$\forall x(Fx\supset Gx)$
      [$\neg\forall x(Gx\supset Fx)\checkmark$,ass
      [$\exists x\neg(Gx\supset Fx)\checkmark$,ass
      [$\neg(Ga\supset Fa)\checkmark$,ass
      [$Ga$,ass
      [$\neg Fa$,ass
      [$(Fa\supset Ga)\checkmark$,ass
      [$\neg Fa$] [$Ga$]]]]]]]]
    \end{forest}

    $\neg Fa$ and $Ga$ make the premisses and the negation of conclusion true.
    Thus, the entailment is invalid.
  \item $\forall x(Fx\supset Gx)\vDash\forall x(\neg Gx\supset\neg Fx)$

    \begin{forest}
      prooftree
      [$\forall x(Fx\supset Gx)$
      [$\neg\forall x(\neg Gx\supset\neg Fx)\checkmark$,ass
      [$\exists x\neg(\neg Gx\supset\neg Fx)\checkmark$,ass
      [$\neg(\neg Ga\supset\neg Fa)\checkmark$,ass
      [$\neg Ga$,ass
      [$\neg\neg Fa$,ass
      [$(Fa\supset Ga)\checkmark$,ass
      [$\neg Fa$ [*,ass]] [$Ga$ [*,ass]]]]]]]]]
    \end{forest}

    Since the tree closes, the entailment is valid.
  \item $\forall x\exists yLxy\vDash\forall y\exists xLyx$

    \begin{forest}
      prooftree
      [$\forall x\exists yLxy$
      [$\neg\forall y\exists xLyx\checkmark$,ass
      [$\exists y\neg\exists xLyx\checkmark$,ass
      [$\neg\exists xLax\checkmark$,ass
      [$\forall x\neg Lax$,ass
      [$\exists yLay\checkmark$,ass
      [$Lab$,ass]]]]]]]
    \end{forest}

    \begin{forest}
      prooftree
      [$\neg Lab$,ass [*,ass]]
    \end{forest}
  \item $\forall x((Fx\wedge Gx)\supset Hx)\vDash\forall
    x(Fx\supset(Gx\supset Hx))$
  \item $(\forall xFx\vee\forall xGx)\vDash\forall(Fx\vee Gx)$
  \item $\forall x(Fx\supset Gx),\forall x(\neg Gx\supset Hx)\vDash
    \forall x(Fx\supset\neg Hx)$
  \item $\exists x(Fx\wedge Gx),\forall x(\neg Hx\supset\neg Gx)\vDash
    \exists x(Fx\wedge Hx)$
  \item $\forall x\exists y(Fy\supset Gx)\vDash\forall y\exists x(Gx\supset
    Fy)$
  \item $\forall x\forall y(Lxy\supset Lyx)\vDash\forall xLxx$
  \item $\forall x(\exists yLxy\supset\forall zLzx)\vDash\forall x\forall y
    (Lxy\supset Lyx)$
  \end{enumerate}
\end{enumerate}
\end{document}

通常,我必须手动将森林树分成两部分,以模拟森林树中的分页。但是,第二棵树并不与第一棵树垂直对齐,如下图所示。我怎样才能将它们垂直对齐在一起?@cfr

在此处输入图片描述

答案1

我认为,如果证明树的两部分不是由同一个环境生成的,垂直对齐将很难自动实现forest。因此,计划有两个:自定义draw tree stage生成两张tikz图片,并在较窄的那张图片上添加一条不可见的路径来创建对齐。

更新:警告:此解决方案仅适用于 Forest v2。下面使用的 v2 的新功能是:draw tree通过处理顺序节点遍历进行自定义;聚合函数;寄存器。

更新:深入解释自定义。实际生成包含绘图说明的draw tree stageForest 命令是。此命令尊重 nodewalk 样式的内容,该内容告诉它实际绘制哪些节点(以及边和额外的 tikz 材料)(以及按什么顺序)。通常,此 nodewalk 只是,因此绘制了整个树。如果我们将其设置为“小于”树的值,则只会绘制树的一部分,我们可以使用它来产生(潜在的)分页点。在下面的第一个示例中,nodewalk严重依赖于树不分支的事实,因为它只绘制所选节点的祖先作为输出的第一部分。tikzpicturedraw treedraw tree processing ordertreedraw tree processing order

更新:深入解释如何实现对齐。我们测量x树中每个节点的最小和最大位置(xx节点锚点的位置,min_x是节点在以节点锚点为原点的坐标系中的范围)。我们使用max_x和聚合函数来计算整个树的最小/最大值。结果存储在临时维度寄存器中。Style将适当宽度的虚拟路径添加到节点的额外 tikz 材料中,从而创建对齐。x.min.maxto widest

\def\hiddenparcommand{\par}
\begin{forest}
  before drawing tree={
    tempdima/.min={x()+min_x()}{tree},
    tempdimb/.max={x()+max_x()}{tree},
  },
  to widest/.style={
    tikz+={\path (\forestregister{tempdima}, \forestoption{y}) -- (\forestregister{tempdimb}, \forestoption{y});},
  },
  draw tree stage/.style={
    for nodewalk={draw tree processing order/.style={fake={name=break page before}, ancestors}}{},
    for root'={draw tree},
    TeX={\hiddenparcommand},
    for nodewalk={draw tree processing order/.style={tree}}{},
    for name={break page before}{to widest,draw tree},        
  },
  prooftree
  [$\forall x\exists yLxy$
  [$\neg\forall y\exists xLyx\checkmark$,ass
  [$\exists y\neg\exists xLyx\checkmark$,ass
  [$\neg\exists xLax\checkmark$,ass
  [$\forall x\neg Lax$,ass
  [$\exists yLay\checkmark$,ass
  [$Lab$,ass,
  [$\neg Lab$,ass,alias=break page before,
  [*,ass
  ]]]]]]]]]
\end{forest}

更新:分支树的情况。这里唯一真正的区别在于draw tree processing order节点行走。在下面的示例中,断点由level节点的(层次深度)决定。(根据树的外观以及我们想要实现的目标(想想动画!),人们可能会采用各种技巧来“划分”树。)

\documentclass{article}

\usepackage{forest}

\begin{document}
\def\hiddenparcommand{\par}
\begin{forest}
  where n children={1}{
    l sep=0,for children={no edge,l=0}
  }{
    parent anchor=south,for children={child anchor=north}
  },
  to widest/.style={
    tikz+={\path (\forestregister{tempdima}, \forestoption{y}) -- (\forestregister{tempdimb}, \forestoption{y});},
  },
  draw tree stage/.style={
    for root'={
      tempdima/.min={x()+min_x()}{tree},
      tempdimb/.max={x()+max_x()}{tree},
      for tree={to widest},
    },
    for nodewalk={draw tree processing order/.style={level<=1}}{},
    for root'={draw tree},
    TeX={\hiddenparcommand---pagebreak---\hiddenparcommand},
    for nodewalk={draw tree processing order/.style={level>=2}}{},
    for root'={draw tree},        
  },
  [R
    [AAAA1[A2[A3]]]
    [B1[B2[B3]]]
  ]
\end{forest}
\end{document}

更新:森林 v1 解决方案。想法是一样的,但实现起来稍微困难一些。最小和最大x位置必须手动计算(使用 v1 手册首页树中的技巧)。哪些节点在哪个部分绘制由 控制phantom;由于一个我以前没有注意到的错误,还有一个额外的复杂因素:tikz即使节点是 ,也会排版额外的材料phantom

\documentclass{article}
\usepackage{forest}

\begin{document}
\def\hiddenparcommand{\par}
\begin{forest} % v1
  where n children={1}{
    l sep=0,for children={no edge,l=0}
  }{
    parent anchor=south,for children={child anchor=north}
  },
  to widest/.style={
    tikz+/.wrap 3 pgfmath args={\path (##1pt,##3pt) -- (##2pt,##3pt);}{x("leftmost")+min_x("leftmost")}{x("rightmost")+max_x("rightmost")}{y},
  },
  draw tree stage/.style={
    for root'={
      alias=leftmost, alias=rightmost,
      for descendants={
        if={x()+min_x()<x("leftmost")+min_x("leftmost")}{alias=leftmost}{},
        if={x()+max_x()>x("rightmost")+max_x("rightmost")}{alias=rightmost}{},
      },
      where={level()<=1}{to widest}{phantom=true},
      draw tree,
      TeX={\hiddenparcommand---pagebreak---\hiddenparcommand},
      where={level()<=1}{tikz={},phantom=true}{to widest,phantom=false},
      draw tree,
    }
  },
  [R
    [AAAA1[A2[A3]]]
    [B1[B2[B3]]]
  ]
\end{forest}
\end{document}

答案2

这是Sašo Živanović 的回答变成了一种风格。该风格会自动选择级别。它需要一个可选参数,即在恢复树的绘制之前要排版的内容。如果分支要继续或继续,则会标记它们,尽管显然这种东西是可选的,取决于您需要/想要什么。(现在,它告诉您树以无数种方式继续,这无疑是过度的。)

\documentclass{article}
\usepackage{forest}
% Sašo Živanović: https://tex.stackexchange.com/a/296771/
\def\hiddenparcommand{\par}
\forestset{%
  declare count register={split here level},
  declare toks register={split here interject},
  split here level'=-1,
  split here interject={},
  to widest/.style={
    tikz+={\path (\forestregister{tempdima}, \forestoption{y}) -- (\forestregister{tempdimb}, \forestoption{y});},
  },
  split here/.style={%
    split here level'/.option=level,
    split here interject={#1},
    split tree
  },
  split tree/.code={%
    \forestset{%
      draw tree stage/.style={
        for root'={
          tempdima/.min={x()+min_x()}{tree},
          tempdimb/.max={x()+max_x()}{tree},
          for tree={%
            to widest,
            if level/.wrap pgfmath arg={{####1}{label={[text=gray, anchor=north, font=\scriptsize]below:{[cont.]}}}{}}{split_here_level},
            if level/.wrap pgfmath arg={{####1}{edge={densely dotted, gray}, edge label={node [font=\scriptsize, pos=0, anchor=south, text=gray] {[cont.]}}}{}}{int((split_here_level)+1)},
          },
        },
        for nodewalk/.wrap pgfmath arg={{draw tree processing order/.style={level<=####1}}{}}{split_here_level},
        for root'={draw tree},
        TeX/.wrap pgfmath arg={\hiddenparcommand ####1\hiddenparcommand}{split_here_interject},
        for nodewalk/.wrap pgfmath arg={{draw tree processing order/.style={level>=####1}}{}}{(split_here_level)+1},
        for root'={draw tree},
      },
    }
  }
}
\begin{document}
\begin{forest}
  [R
    [AAAA1[A2[A3]]]
    [B1[B2[B3]]]
  ]
\end{forest}

\begin{forest}
  [R
    [AAAA1[A2, split here={to be continued \dots}[A3]]]
    [B1[B2[B3]]]
  ]
\end{forest}

\begin{forest}
  [R
    [AAAA1, split here={to be continued \dots}[A2[A3]]]
    [B1[B2[B3]]]
  ]
\end{forest}

\begin{forest}
  [R
    [AAAA1[A2[A3]]]
    [B1[B2, split here={to be continued \dots}[B3]]]
  ]
\end{forest}

\end{document}

在这里分裂

编辑

概念验证版本允许多次分割,例如用于解释。

\documentclass[12pt]{article}
\usepackage{geometry}
\usepackage{microtype}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{enumitem}
\setlist[enumerate,1]{label=\bfseries\Alph*,align=left,leftmargin=*, labelsep=1.5em}
\setlist[enumerate,2]{label=\arabic*.,labelindent=1em,labelsep=1.5em, leftmargin=*}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{amsthm}
\theoremstyle{definition}
\newtheorem*{sol}{Solution}
\usepackage{forest}
 % Sašo Živanović: https://tex.stackexchange.com/a/296771/
\newcommand\hiddenparcommand{\par\noindent}
\newcommand\hiddencommacommand{, }
\forestset{%
  declare keylist register={split here levels},
  declare keylist register={split here interjects},
  declare toks register=split here toks,
  split here levels={},
  split here interjects={},
  to widest/.style={
    tikz+={\path (\forestregister{tempdima}, \forestoption{y}) -- (\forestregister{tempdimb}, \forestoption{y});},
  },
  hide commas/.style={%
    split here toks+={\hiddencommacommand},
    split here toks+={#1},
  },
  split here/.style={%
    split here levels+/.option=level,
    split={#1}{,}{split here toks,hide commas},
    split here interjects/.register=split here toks,
    split tree
  },
  split tree/.code={%
    \forestset{%
      draw tree stage/.style={
        for root'={
          tempdima/.min={x()+min_x()}{tree},
          tempdimb/.max={x()+max_x()}{tree},
          for tree={%
            to widest,
          },
        },
        tempcountb'=-1,
        do until={%
          strequal((split_here_levels),"")
        }{%
          tempkeylistb'={},
          tempkeylista'={},
          split register={split here levels}{,}{tempcounta,tempkeylistb+},
          split register={split here interjects}{,}{temptoksa,tempkeylista+},
          split here levels'/.register=tempkeylistb,
          split here interjects'/.register=tempkeylista,
          % Sašo Živanović: http://chat.stackexchange.com/transcript/message/28484520#28484520
          for nodewalk/.wrap 2 pgfmath args={{draw tree processing order/.style={filter={level<=########1}{level()>########2}}}{}}{tempcounta}{tempcountb},
          for root'={draw tree},
          TeX/.wrap pgfmath arg={\hiddenparcommand ########1\hiddenparcommand}{temptoksa},
          tempcountb'/.register=tempcounta,
        },
        for nodewalk/.wrap pgfmath arg={{draw tree processing order/.style={level>=####1}}{}}{(tempcountb)+1},
        for root'={draw tree},
      },
    }
  },
  ass/.append style={
    before computing xy={l=\baselineskip},
    no edge
  },
  prooftree/.style={
    for tree={
      child anchor=north,
      parent anchor=south
    }
  },
}

\begin{document}
\subsection*{Exercises 29}
\begin{enumerate}
\item Use QL trees to evaluate the entailment claims (1) to (10) in Exercises
  28A.
  \begin{enumerate}
  \item $\forall x(Fx\supset Gx)\vDash\forall x(Gx\supset Fx)$

    \begin{forest}
      prooftree
      [$\forall x(Fx\supset Gx)$
      [$\neg\forall x(Gx\supset Fx)\checkmark$,ass
      [$\exists x\neg(Gx\supset Fx)\checkmark$,ass
      [$\neg(Ga\supset Fa)\checkmark$,ass
      [$Ga$,ass
      [$\neg Fa$,ass
      [$(Fa\supset Ga)\checkmark$,ass
      [$\neg Fa$] [$Ga$]]]]]]]]
    \end{forest}

    $\neg Fa$ and $Ga$ make the premisses and the negation of conclusion true.
    Thus, the entailment is invalid.
  \item $\forall x(Fx\supset Gx)\vDash\forall x(\neg Gx\supset\neg Fx)$

    \begin{forest}
      prooftree
      [$\forall x(Fx\supset Gx)$
      [$\neg\forall x(\neg Gx\supset\neg Fx)\checkmark$,ass
      [$\exists x\neg(\neg Gx\supset\neg Fx)\checkmark$,ass
      [$\neg(\neg Ga\supset\neg Fa)\checkmark$,ass
      [$\neg Ga$,ass
      [$\neg\neg Fa$,ass
      [$(Fa\supset Ga)\checkmark$,ass
      [$\neg Fa$ [*,ass]] [$Ga$ [*,ass]]]]]]]]]
    \end{forest}

    Since the tree closes, the entailment is valid.
  \item $\forall x\exists yLxy\vDash\forall y\exists xLyx$

    \begin{forest}
      prooftree
      [$\forall x\exists yLxy$
      [$\neg\forall y\exists xLyx\checkmark$,ass, split here={This tree gets split later but not quite yet, as you see.}
      [$\exists y\neg\exists xLyx\checkmark$,ass
      [$\neg\exists xLax\checkmark$,ass
      [$\forall x\neg Lax$,ass, split here={Continued}
      [$\exists yLay\checkmark$,ass
      [$Lab$,ass
      [$\neg Lab$,ass [*,ass]]]]]]]]
      ]
    \end{forest}

  \item $\forall x((Fx\wedge Gx)\supset Hx)\vDash\forall
    x(Fx\supset(Gx\supset Hx))$
  \item $(\forall xFx\vee\forall xGx)\vDash\forall(Fx\vee Gx)$
  \item $\forall x(Fx\supset Gx),\forall x(\neg Gx\supset Hx)\vDash
    \forall x(Fx\supset\neg Hx)$
  \item $\exists x(Fx\wedge Gx),\forall x(\neg Hx\supset\neg Gx)\vDash
    \exists x(Fx\wedge Hx)$
  \item $\forall x\exists y(Fy\supset Gx)\vDash\forall y\exists x(Gx\supset
    Fy)$
  \item $\forall x\forall y(Lxy\supset Lyx)\vDash\forall xLxx$
  \item $\forall x(\exists yLxy\supset\forall zLzx)\vDash\forall x\forall y
    (Lxy\supset Lyx)$
  \end{enumerate}
\end{enumerate}
\end{document}

多重分裂树

相关内容