我尝试用三天时间来创作一个语义画面,但似乎无法弄清楚最后几个缺失的部分。
以下是我迄今为止编写的代码,可能不是最优雅的。对于有两个兄弟节点并进行拆分的节点,缺少一些操作,因为\edge[midway,right]
在这种情况下,它的行为不符合我的预期。
\begin{figure}[]
\begin{tikzpicture}[font=\small,
every tree node/.style={inner sep=0.0625cm, circle, draw},
level 1/.style={sibling distance=-50pt},
level 2/.style={sibling distance=10pt},
level 3/.style={sibling distance=2pt},
level 4/.style={sibling distance=10pt},
level 5/.style={sibling distance=18pt},
level 6/.style={sibling distance=12pt},
bold/.style={font=\bf},
level distance=40pt,
scale=0.9,
nodot/.style={draw,fill},
edge from parent/.style=
{draw,
edge from parent path={(\tikzparentnode.south)
-- +(0,-20pt)
-| (\tikzchildnode)}}
]
%end markup
\Tree [.\node[ label=left:{$(\neg(p\wedge(q\vee\neg r)))\leftrightarrow s,p\rightarrow (q\wedge r)$}] (root) {}; %level 0
[.\node[label=left:{$p\wedge r$}] {};%level 1
\edge node[midway,right,bold] {$\wedge L$};
[.\node[label=left:{$q,r$}] {};
[.\node[label=left:{$\neg(p\wedge(q\vee\neg r)),s$}] {};
\edge node[midway,right,bold] {$\neg L$};
[.\node[label=right:{$p\wedge(q\vee\neg r)$}] {};
[.\node[label=right:{$p$}] {};]
[.\node[label=right:{{$\circ q\vee\neg r$}}] {};
\edge node[midway,right,bold] {$\vee R$};
[.\node[label=right:{$q,\neg r$}] {};]
]
]
]
[.\node[label=right:{$\neg(p\wedge(q\vee\neg r)),s$}] {};
\edge node[midway,right,bold] {$\neg R$};
[.\node[label=left:{$p\wedge(q\vee\neg r)$}] {};
\edge node[midway,right,bold] {$\wedge L$};
[.\node[label=left:{$p,q\vee\neg r$}] {};
[.\node[label=left:{$q$}] {};]
[.\node[label=left:{$\neg r$}] {};
\edge node[midway,right,bold] {$\neg R$};
[.\node[label=right:{$r$}] {}; ]
]
]
]
]
]
]
[.\node[label=right:{$p$}] {};%level 1
[.\node[label=left:{$s,\neg(p\wedge(q\vee\neg r))$}] {};
\edge node[midway,right,bold] {$\neg L$};
[.\node[label=right:{$p\wedge(q\vee\neg r)$}] {};
[.\node[label=right:{$p$}] {}; ]
[.\node[label=right:{$p\vee\neg r$}] {};
\edge node[midway,right,bold] {$\vee R$};
[.\node[label=right:{$q,\neg r$}] {};
\edge node[midway,right,bold] {$\neg R$};
[.\node[label=left:{$r$}] {};]
]
]
]
]
[.\node[label=right:{$\neg(p\wedge(q\vee\neg r)),s$}] {};
\edge node[midway,right, bold] {$\neg R$};
[.\node[label=left:{$p\wedge(q\vee\neg r)$}] {};
\edge node[midway,right, bold] {$\wedge L$};
[.\node[label=left:{$p,q\vee\neg r$}] {};]
]
]
]
] \end{tikzpicture}
\end{figure}
这是我的代码生成的输出。黑色表示代码执行的操作,红色表示我想要实现的操作:
我尝试添加更多节点并尝试绝对定位它们,尝试分割路径上的边缘,寻找添加更多标签的方法。
我已经到了看不到森林里的树木的地步,决定寻求帮助。所有帮助都会得到感谢。(也接受新的包裹和建议)
答案1
您提到了使用替代包的可能性。您还提到了沿线某处有一片森林。也许如果您只见树木不见森林,那么您应该画一片森林。
此解决方案基于当前版本的森林derivation tree
。我根据您当前的代码定义了一种样式。它还定义了circular empty nodes
仅指示forest
为空节点绘制圆圈的样式。我认为将其与 的代码分开可能会很有用derivation tree
。
除了可以用来格式化树的各种键之外森林包中,你可以使用蒂克兹样式fork label
并rule label
确定推理规则标签的格式:
\tikzset{
fork label/.style={},
rule label/.style={},
}
rule label
影响不分支的规则。fork label
影响分支的规则。
这些对应两个森林键,fork label
可rule label
用于指定树中分支和非分支规则的标签。fork label
是自定义的森林选项:
declare autowrapped toks={fork label}{},
用于指定边缘路径:
edge path={
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-20pt) node [midway, anchor=west, right, fork label] {$\forestoption{fork label}$} -| (.child anchor)\forestoption{edge label};
},
这里第一次出现的fork label
是 TikZ 样式。第二次出现的是\forestoption{fork label}
。rule label
不需要自定义选项,因为我们可以使用现有选项,只需创建一个森林风格:
rule label/.style={
edge label={node [pos=.5, right, anchor=west, rule label] {$##1$}},
},
rule label
和都将其内容包装在数学环境中,因此在这些情况下fork label
不需要符号。$...$
此外,left label
将在左侧格式化节点标签。right label
将在右侧格式化节点标签。我应该指出,从技术上讲,这些不是节点标签。事实上,它们是树中的附加节点:
left label/.style={
before typesetting nodes={
insert before={[{##1}, no edge, before drawing tree={x+=7.5pt}]}
}
},
right label/.style={
before typesetting nodes={
insert after={[{##1}, no edge, before drawing tree={x-=7.5pt}]}
}
},
我这样做是为了森林而不是根据树中节点的内容计算适当的兄弟间距。这样,树就会根据其内容适当地间隔,而希望在指定树时不需要太多干预。
要使用derivation tree
和circular empty nodes
样式,只需将它们放入环境的前言中forest
:
\begin{forest}
derivation tree,
circular empty nodes,
这将适当地格式化树并启用附加选项和样式。然后您可以说,例如:
[, left label={$p,q\lor \lnot p$},
[, fork label=\lor L, right label={$\lnot p$}
[, rule label=\lor R, left label={$p$}
]
]
[, left label={$q$}
]
]
\end{forest}
生产:
这大大简化了树的规范并使其更容易从源代码读取。
对原始代码进行翻译后,发现其中附加的节点为红色,结果如下:
完整代码:
\documentclass[tikz,border=10pt,multi]{standalone}
\usepackage{forest}
\tikzset{
fork label/.style={},
rule label/.style={},
}
\forestset{
derivation tree/.style={
declare autowrapped toks={fork label}{},
for tree={
l sep+=15pt,
edge path={
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-20pt) node [midway, anchor=west, right, fork label] {$\forestoption{fork label}$} -| (.child anchor)\forestoption{edge label};
},
parent anchor=south,
child anchor=north,
if level=0{}{
if={equal(n_children("!u"),1)}{
before packing={calign with current}
}{
if n=1{
before packing={
!u.calign primary child/.wrap pgfmath arg={##1}{n}
}
}{
before packing={
!u.calign secondary child/.wrap pgfmath arg={##1}{n}
}
}
}
}
},
rule label/.style={
edge label={node [pos=.5, right, anchor=west, rule label] {$##1$}},
},
left label/.style={
before typesetting nodes={
insert before={[{##1}, no edge, before drawing tree={x+=7.5pt}]}
}
},
right label/.style={
before typesetting nodes={
insert after={[{##1}, no edge, before drawing tree={x-=7.5pt}]}
}
},
before packing={
for tree={
tier/.wrap pgfmath arg={tier ##1}{level},
}
}
},
circular empty nodes/.style={
before typesetting nodes={
for tree={
if content={}{circle, draw, anchor=center, inner sep=0pt, minimum size=5pt}{}
}
},
}
}
\begin{document}
\begin{forest}
derivation tree,
circular empty nodes,
% /tikz/rule label/.style={text=blue, font=\bfseries\small},
/tikz/fork label/.style={red},
[, label=left:{$(\lnot(p\land(q\lor\lnot r)))\leftrightarrow s,p\rightarrow (q\land r)$},
[, left label={$p\land r$},
[, left label={$q,r$}, rule label=\land L,
[, left label={$\lnot(p\land(q\lor\lnot r)),s$},
[, right label={$p\land(q\lor\lnot r)$}, rule label=\lnot L,
[, right label={$p$}
]
[, right label={$\circ q\lor\lnot r$}, fork label=\land R
[, right label={$q,\lnot r$}, rule label=\lor R,
]
]
]
]
[, right label={$\lnot(p\land(q\lor\lnot r)),s$}, fork label=\leftrightarrow L
[, left label={$p\land(q\lor\lnot r)$}, rule label=\lnot R,
[, left label={$p,q\lor\lnot r$}, rule label=\land L,
[, left label={$q$},
]
[, left label={$\lnot r$}, fork label=\lor L
[, right label={$r$}, rule label=\lnot R,
]
]
]
]
]
]
]
[, right label={$p$}, fork label=\rightarrow L
[, left label={$s,\lnot(p\land(q\lor\lnot r))$},
[, right label={$p\land(q\lor\lnot r)$}, rule label=\lnot L,
[, right label={$p$},
]
[, right label={$p\lor\lnot r$}, fork label=\lor R
[, right label={$q,\lnot r$}, rule label=\lor R,
[, left label={$r$}, rule label=\lnot R,
]
]
]
]
]
[, right label={$\lnot(p\land(q\lor\lnot r)),s$}, fork label=\leftrightarrow L
[, left label={$p\land(q\lor\lnot r)$}, rule label=\lnot R,
[, left label={$p,q\lor\lnot r$}, rule label=\land L,
]
]
]
]
]
\end{forest}
\end{document}
如果您愿意,您还可以配置样式,以便left label
使用right label
数学模式或提供在左侧和右侧指定推导规则的选项。当然,这些可能性是否对您有用则完全是另一回事。
答案2
基本上,我给每个树节点都起了个名字,最后把这些midway
节点合并成一个\path
。我可能可以想出一个更好的命名协议。
\documentclass{standalone}
\usepackage{tikz-qtree}
\begin{document}
\begin{tikzpicture}[font=\small,
every tree node/.style={inner sep=0.0625cm, circle, draw},
level 1/.style={sibling distance=-50pt},
level 2/.style={sibling distance=10pt},
level 3/.style={sibling distance=2pt},
level 4/.style={sibling distance=10pt},
level 5/.style={sibling distance=18pt},
level 6/.style={sibling distance=12pt},
bold/.style={font=\bf},
level distance=40pt,
scale=0.9,
nodot/.style={draw,fill},
edge from parent/.style=
{draw,
edge from parent path={(\tikzparentnode)% note: removed .south
-- +(0,-20pt)
-| (\tikzchildnode)}}
]
%end markup
\Tree [.\node[ label=left:{$(\neg(p\wedge(q\vee\neg r)))\leftrightarrow s,p\rightarrow (q\wedge r)$}] (root) {}; %level 0
[.\node[label=left:{$p\wedge r$}] (B) {};%level 1
[.\node[label=left:{$q,r$}] (C) {};
[.\node[label=left:{$\neg(p\wedge(q\vee\neg r)),s$}] (D) {};
[.\node[label=right:{$p\wedge(q\vee\neg r)$}] (E) {};
[.\node[label=right:{$p$}] (F) {};]
[.\node[label=right:{{$\circ q\vee\neg r$}}] (G) {};
[.\node[label=right:{$q,\neg r$}] (H) {};]
]
]
]
[.\node[label=right:{$\neg(p\wedge(q\vee\neg r)),s$}] (I) {};
[.\node[label=left:{$p\wedge(q\vee\neg r)$}] (J) {};
[.\node[label=left:{$p,q\vee\neg r$}] (K) {};
[.\node[label=left:{$q$}] (L) {};]
[.\node[label=left:{$\neg r$}] (M) {};
[.\node[label=right:{$r$}] (N) {}; ]
]
]
]
]
]
]
[.\node[label=right:{$p$}] (O) {};%level 1
[.\node[label=left:{$s,\neg(p\wedge(q\vee\neg r))$}] (P) {};
[.\node[label=right:{$p\wedge(q\vee\neg r)$}] (Q) {};
[.\node[label=right:{$p$}] (R) {}; ]
[.\node[label=right:{$p\vee\neg r$}] (S) {};
[.\node[label=right:{$q,\neg r$}] (T) {};
[.\node[label=left:{$r$}] (U) {};]
]
]
]
]
[.\node[label=right:{$\neg(p\wedge(q\vee\neg r)),s$}] (V) {};
[.\node[label=left:{$p\wedge(q\vee\neg r)$}] (W) {};
[.\node[label=left:{$p,q\vee\neg r$}] (X) {};]
]
]
]
]
\path (root) -- +(0pt,-20pt) node[midway,right,bold] {$\rightarrow L$}
(B) -- (C) node[midway,right,bold] {$\wedge L$}
(C) -- +(0pt,-20pt) node[midway,right,bold] {$\rightarrow L$}
(D) -- (E) node[midway,right,bold] {$\neg L$}
(E) -- +(0pt,-20pt) node[midway,right,bold] {$\wedge R$}
(G) -- (H) node[midway,right,bold] {$\vee R$}
(I) -- (J) node[midway,right,bold] {$\neg R$}
(J) -- (K) node[midway,right,bold] {$\wedge L$}
(K) -- +(0,-20pt) node[midway,right,bold] {$\vee L$}
(M) -- (N) node[midway,right,bold] {$\neg R$}
(O) -- +(0,-20pt) node[midway,right,bold] {$\leftrightarrow L$}
(P) -- (Q) node[midway,right,bold] {$\neg L$}
(Q) -- +(0,-20pt) node[midway,right,bold] {$\wedge R$}
(S) -- (T) node[midway,right,bold] {$\vee R$}
(T) -- (U) node[midway,right,bold] {$\neg R$}
(V) -- (W) node[midway,right, bold] {$\neg R$}
(W) -- (X) node[midway,right, bold] {$\wedge L$};
\end{tikzpicture}
\end{document}