РЕДАКТИРОВАТЬ

РЕДАКТИРОВАТЬ

Мне нужно набрать в документе несколько семантических таблиц, похожих на пример ниже.

Семантическая таблица

Первой моей идеей было использовать 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}

Понятно, что это не тот результат, который нужен. Края должны начинаться под и заканчиваться над \circs, и они должны иметь прямые углы, чтобы диаграмму можно было немного сжать.

Рисование таких диаграмм для меня совершенно новое занятие, так что можете ли вы дать мне несколько полезных рекомендаций? Есть ли у вас какие-либо советы или приемы для создания этих семантических таблиц в целом? Пакеты вроде forestили qtreeproduce проще использовать для такого рода деревьев?


Редактировать: Ответ @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 labels без того, чтобы по сути воспроизвести код, который Forest использует для labelизначально. Поскольку, похоже, в этом нет никаких преимуществ, возникает соблазн переопределить labelвместо этого, добавив следующий код в преамбулу документа:

\forestset{% Sašo Živanović won't like this ...
  label/.style={%
    tikz+={%
      \path[late options={%
        name=\forestoption{name},label={#1}}
      ];
    }
  },
}

Вот +что имеет значение. Теперь labels будут накапливаться, а не перезаписывать друг друга и/или любые предыдущие использования 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.

Связанный контент