
Мне нужно набрать в документе несколько семантических таблиц, похожих на пример ниже.
Первой моей идеей было использовать tikz
это, поэтому я создал следующего монстра:
\documentclass[convert]{standalone}
\usepackage{tikz,amssymb}
\usetikzlibrary{positioning}
\newcommand{\lnec}{\Box}
\begin{document}
\begin{tikzpicture}[scale=2]
\node[label=right:$(\lnec p\to\lnec q)\to\lnec(p\to q)$] (n1) {$\circ_1$};
\node[label=left:$\lnec p\to\lnec q$, label=right:$\lnec(p\to q)$, below=of n1] (n2) {$\circ_1$};
\node[label=left:$\lnec q$, label=right:$\lnec(p\to q)$, below left=of n2] (n3) {$\circ_1$};
\node[label=right:{$\lnec p, \lnec(p\to q)$}, below right=of n2] (n4) {$\circ_1$};
\node[label=left:$q$, label=right:$\lnec(p\to q)$, below=of n3] (n5) {$\circ_2$};
\node[label=right:$p$, below left=of n4] (n6) {$\circ_3$};
\node[label=right:$p\to q$, below right=of n4] (n7) {$\circ_4$};
\node[label=left:$p$, label=right:$q$, below=of n7] (n8) {$\circ_4$};
\draw[-] (n1) to (n2);
\draw[-] (n2) to (n3);
\draw[-] (n2) to (n4);
\draw[-, dotted] (n3) to (n5);
\draw[-, dotted] (n4) to (n6);
\draw[-, dotted] (n4) to (n7);
\draw[-] (n7) to (n8);
\end{tikzpicture}
\end{document}
Понятно, что это не тот результат, который нужен. Края должны начинаться под и заканчиваться над \circ
s, и они должны иметь прямые углы, чтобы диаграмму можно было немного сжать.
Рисование таких диаграмм для меня совершенно новое занятие, так что можете ли вы дать мне несколько полезных рекомендаций? Есть ли у вас какие-либо советы или приемы для создания этих семантических таблиц в целом? Пакеты вроде forest
или qtree
produce проще использовать для такого рода деревьев?
Редактировать: Ответ @cfr ниже многообещающий, поэтому я хотел бы поработать над ним forest
и доработать его стиль tableaux
. Я пытался сделать это сам в течение последних двух дней, но понимание всех forest
расширенных опций в документации оказалось невозможным для новичка вроде меня. Поэтому я хотел бы назначить вознаграждение тому, кто сможет сделать для меня доработку. Это означает
- расстояние между WFF и
\circ
сепаратором должно быть уменьшено, - края должны быть выровнены по центру разделителей
\circ
, игнорируя возможные нижние индексы, - Вышеуказанное также должно работать, когда не
\circ
указан нижний индекс для разделителя.
решение1
Этот ответ использует совершенно другой подход, поскольку код, к сожалению, был утерян из оригинальной версии вопроса. Он может быть менее полезен, поскольку не основан на этом коде, но я оставлю его здесь, поскольку он может пригодиться кому-то в какой-то момент.
Вот базовый стиль Forest, tableaux
который можно использовать для такого рода диаграмм.
Проблема с использованием label
заключается в том, что он не учитывается при позиционировании узлов относительно друг друга. tableaux
вместо этого создает дополнительные узлы для этого контента, которые указываются вместе с узлом «main». Это позволяет правильно выровнять вещи с «main» кругом, оставляя достаточно места для wffs.
Единственный реальный недостаток этого заключается в том, что необходимо создать дополнительный phantom
корневой узел, так как в противном случае у нас будет 2 или 3 корня (главный узел на верхнем уровне и wffs на каждой стороне). Это невозможно. Отсюда и фантомный корневой узел.
Если вы делаете много подобных вещей, можно избежать необходимости добавлять фантомный корень самостоятельно, создав новую среду, которая сделает это автоматически. ( environ
Для этого можно использовать пакет с пользовательским именем для тела среды.)
edges
Для обеспечения стиля используется библиотека Фореста forked edges
.
Тонкая настройка оставлена в качестве упражнения для читателя. Например, может показаться лучше отрегулировать расстояния между братьями и сестрами, чтобы приблизить wffs.
\documentclass[tikz,multi,border=10pt]{standalone}
\usepackage[edges]{forest}
\usepackage{amssymb}
\begin{document}
\forestset{%
declare toks={F}{},
declare toks={T}{},
tableaux/.style={%
forked edges,
for tree={
math content,
parent anchor=children,
child anchor=parent,
},
where level=0{%
for children={no edge},
phantom,
}{%
delay={%
content/.wrap value={\circ_{##1}},
insert before/.wrap pgfmath arg={%
[{##1}, no edge, math content]
}{T()},
insert after/.wrap pgfmath arg={%
[{##1}, no edge, math content]
}{F()},
},
if={n_children("!u")==1}{%
before packing={calign with current edge},
}{}
},
}
}
\newcommand*{\necc}{\ensuremath{\mathbin{\Box}}}
\newcommand*{\lif}{\ensuremath{\mathbin{\rightarrow}}}
\begin{forest}
tableaux
[
[1, F=(\necc p \lif \necc q) \lif \necc (p \lif q)
[1, T=\necc p \lif \necc q, F=\necc (p \lif q)
[1, T=\necc q, F=\necc (p \lif q)
[2, T=q, F=p \lif q, edge=densely dotted
[2, T={p, q}, F=q, label=below:$\otimes$]
]
]
[1, F={\necc p, \necc(p \lif q)}
[3, F=p, edge=densely dotted]
[4, F=p \lif q, edge=densely dotted
[4, F=q, T=p]
]
]
]
]
]
\end{forest}
\end{document}
РЕДАКТИРОВАТЬ
Это решает 3 дополнительных требования, добавленных к вопросу. Мы избегаем влияния индексов на выравнивание, отображая их как метки, а не как часть узлов. Мы корректируем расстояние до wff перед рисованием дерева, поскольку мы не хотим уменьшать расстояния между соседними элементами в целом, а только расстояние между кругами и связанными wff. Это прекрасно с индексами и без них.
В зависимости от вашего фактического использования, семейства шрифтов и размера и т. д., вы можете захотеть настроить конкретные размеры, используемые в настройках. Это -3.5pt
и 3.5pt
для нижних индексов и 7.5pt
и -7.5pt
для wffs в MWE ниже.
\documentclass[tikz,multi,border=10pt]{standalone}
\usepackage[edges]{forest}
\usepackage{amssymb}
\begin{document}
\forestset{%
declare toks={T}{},
declare toks={F}{},
tableaux/.style={%
forked edges,
for tree={
math content,
parent anchor=children,
child anchor=parent,
},
where level=0{%
for children={no edge},
phantom,
}{%
before typesetting nodes={%
content/.wrap value={\circ},
},
delay={%
my label/.wrap pgfmath arg={{[inner sep=0pt, xshift=-3.5pt, yshift=3.5pt, anchor=north west, font=\scriptsize]-45:$##1$}}{content()},
insert before/.wrap pgfmath arg={%
[{##1}, no edge, math content, before drawing tree={x'+=7.5pt}]
}{T()},
insert after/.wrap pgfmath arg={%
[{##1}, no edge, math content, before drawing tree={x'-=7.5pt}]
}{F()},
},
if={n_children("!u")==1}{%
before packing={calign with current edge},
}{}
},
}
}
\newcommand*{\necc}{\ensuremath{\mathbin{\Box}}}
\newcommand*{\lif}{\ensuremath{\mathbin{\rightarrow}}}
\begin{forest}
tableaux
[
[1, F=(\necc p \lif \necc q) \lif \necc (p \lif q)
[1, T=\necc p \lif \necc q, F=\necc (p \lif q)
[1, T=\necc q, F=\necc (p \lif q)
[2, T=q, F=p \lif q, edge=densely dotted
[2, T={p, q}, F=q, label=below:$\otimes$]
]
]
[1, F={\necc p, \necc(p \lif q)}
[3, F=p, edge=densely dotted]
[4, F=p \lif q, edge=densely dotted
[4, F=q, T=p
[99, F=X!, T=XX!!
[, F=XXX!!!, T=XXXX!!!!]
]
]
]
]
]
]
]
\end{forest}
\end{document}
ИЗМЕНИТЬ ИЗМЕНИТЬ
Как указано в комментарии, моя правка привела к исчезновению замыканий. Это потому, что они созданы с помощью label
, а числа в правом верхнем углу узлов также были добавлены с помощью label
. Хотя метки запрашиваются в разных местах и были бы в порядке в обычном коде TikZ, Forest определяет label
таким образом, что на узел разрешена только одна. Более того,label
такжеперезаписывает любые более ранние аннотации, указанные с помощью tikz
или pin
. Из forest.sty
:
label/.style={tikz={\path[late options={%
name=\forestoption{name},label={#1}}];}},
pin/.style={tikz={\path[late options={%
name=\forestoption{name},pin={#1}}];}},
Каждый вызов tikz
переопределяет любую предыдущую настройку. Таким образом, код не накапливается, а вместо этого заменяет существующий код.
Я не уверен, по какой причине автор сделал такой выбор, поэтому я не совсем уверен, как лучше всего к этому подойти. Одним из вариантов было бы использовать afterthought
для чисел, что должно позволить использовать label
в самом дереве. В этом случае, однако, мы не могли бы указать числа как TikZ label
s без того, чтобы по сути воспроизвести код, который Forest использует для label
изначально. Поскольку, похоже, в этом нет никаких преимуществ, возникает соблазн переопределить label
вместо этого, добавив следующий код в преамбулу документа:
\forestset{% Sašo Živanović won't like this ...
label/.style={%
tikz+={%
\path[late options={%
name=\forestoption{name},label={#1}}
];
}
},
}
Вот +
что имеет значение. Теперь label
s будут накапливаться, а не перезаписывать друг друга и/или любые предыдущие использования pin
, tikz
или tikz+
. Как указано, я не могу себе представить, что это то, что я должен делать, поэтому я не рекомендую это, даже если это работает:
Более сложная альтернатива — использовать это:
\forestset{%
my label/.style={%
tikz+={%
\path[late options={%
name=\forestoption{name},label={#1}}
];
}
}
}
Тогда размещение цифр просто использует my label
вместо label
. Полная конфигурация:
\forestset{%
declare toks={T}{},
declare toks={F}{},
my label/.style={%
tikz+={%
\path[late options={%
name=\forestoption{name},label={#1}}
];
}
},
tableaux/.style={%
forked edges,
for tree={
math content,
parent anchor=children,
child anchor=parent,
},
where level=0{%
for children={no edge},
phantom,
}{%
before typesetting nodes={%
content/.wrap value={\circ},
},
delay={%
my label/.wrap pgfmath arg={{[inner sep=0pt, xshift=-3.5pt, yshift=3.5pt, anchor=north west, font=\scriptsize]-45:$##1$}}{content()},
insert before/.wrap pgfmath arg={%
[{##1}, no edge, math content, before drawing tree={x'+=7.5pt}]
}{T()},
insert after/.wrap pgfmath arg={%
[{##1}, no edge, math content, before drawing tree={x'-=7.5pt}]
}{F()},
},
if={n_children("!u")==1}{%
before packing={calign with current edge},
}{}
},
}
}
что дает тот же результат, что и выше, но без переопределения стиля Фореста label
.