\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 stage
Forest 命令是。此命令尊重 nodewalk 样式的内容,该内容告诉它实际绘制哪些节点(以及边和额外的 tikz 材料)(以及按什么顺序)。通常,此 nodewalk 只是,因此绘制了整个树。如果我们将其设置为“小于”树的值,则只会绘制树的一部分,我们可以使用它来产生(潜在的)分页点。在下面的第一个示例中,nodewalk严重依赖于树不分支的事实,因为它只绘制所选节点的祖先作为输出的第一部分。tikzpicture
draw tree
draw tree processing order
tree
draw tree processing order
更新:深入解释如何实现对齐。我们测量x
树中每个节点的最小和最大位置(x
是x
节点锚点的位置,min_x
是节点在以节点锚点为原点的坐标系中的范围)。我们使用max_x
和聚合函数来计算整个树的最小/最大值。结果存储在临时维度寄存器中。Style将适当宽度的虚拟路径添加到节点的额外 tikz 材料中,从而创建对齐。x
.min
.max
to 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}