答案1
你可以使用森林绘制树。由于它要求在括号符号中指定树,因此它至少看起来是潜在的合适的。
与现有解决方案不同,此解决方案不需要 LuaTeX。下面的示例是使用 pdfTeX 编译的,但任何引擎都应该可以运行。
我提出两个版本:
这原版需要你写
[]
一个点。我认为这样更安全,也不太可能发生奇怪的事情。这新版本允许您像平常一样编写内容
[.,.]
。我认为它更危险,更有可能做出奇怪的事情。然而,在最低限度的测试中,它似乎确实能完成工作,所以如果你不尝试任何过于冒险的事情,它可能是安全的。
我从新版本开始,它允许使用更自然的语法。
新版本
如果您希望理解代码,而不是简单地使用它,请在尝试遵循我的解释之前先参阅下面原始版本的解释,因为如果您首先了解如何非动态地创建树,则更容易理解动态树的创建。
森林包括以下概念动态的在处理过程中构建的树。这允许您更改节点的内容、添加节点、移动节点、复制节点和替换节点等。这可以针对单个节点或整个子树进行。
这意味着我们可以设置我们的树来检查.
节点内容,并用空值替换该节点,同时附加一个额外的节点。所以,基本上,
[.]
会变成
[[]]
当树被编译时。
代码如下
delay={
if content={.}{
content=,
append={[]}
}{}
}
这会延迟,以便测试完成时正确设置节点的内容。
但这还不够,因为我们仍然不能写
[.,.]
因为森林会尝试将第二个点解释为键,但它并不是键。
为了解决这个问题,我们定义一个新的森林样式.
如下:
./.style={
delay+={append={[]},}
},
这会将另一个节点附加到现有节点。为了使效果累积,我们需要增加延迟。因此,我们需要delay+
这里而不是简单地delay
。
这将使节点到位,但它不能完全完成工作,因为我们应用于节点的格式(circle, fill
等等)现在是在创建附加节点之前应用的,这意味着这些节点的样式不正确。
为了解决这个问题,我们可以延迟添加这些设置,直到节点排版之前,通过将它们移出初始节点for tree=...
并在适当的阶段将它们应用到树中:
before typesetting nodes={
for tree={
circle,
fill,
minimum width=3pt,
inner sep=0pt,
},
},
现在我们可以写
\[
\Bseries{
[[.,.][[[.]]]]
}
=
[
\Bseries{
[.,.]
}
,
\Bseries{
[[.]]
}
]
=
[
[
\Bseries{
[]
}
,
\Bseries{
[]
}
]
,
[
\Bseries{
[.]
}
]
]
=
[
[
\Bseries{
[]
}
,
\Bseries{
[]
}
]
,
[
[
\Bseries{
[]
}
]
]
]
\]
产生与使用原始版本的原始示例相同的输出:
新版完整代码:
\documentclass{article}
\usepackage{forest}
\forestset{
./.style={
delay+={append={[]},}
},
Bseries/.style={
for tree={
grow'=90,
parent anchor=center,
child anchor=center,
s sep=2.5pt,
if level=0{
baseline
}{},
delay={
if content={.}{
content=,
append={[]}
}{}
}
},
before typesetting nodes={
for tree={
circle,
fill,
minimum width=3pt,
inner sep=0pt,
},
},
before computing xy={
for tree={
l=5pt,
}
}
}
}
\newcommand\Bseries[1]{\Forest{Bseries #1}}
\begin{document}
\[
\Bseries{
[[.,.][[[.]]]]
}
=
[
\Bseries{
[.,.]
}
,
\Bseries{
[[.]]
}
]
=
[
[
\Bseries{
[]
}
,
\Bseries{
[]
}
]
,
[
\Bseries{
[.]
}
]
]
=
[
[
\Bseries{
[]
}
,
\Bseries{
[]
}
]
,
[
[
\Bseries{
[]
}
]
]
]
\]
\end{document}
谢谢符号 1建议解析.如果我们添加
\usepackage{xparse}
那么我们可以定义\Bseries
如下:
\DeclareDocumentCommand\Bseries{o}{\Forest{Bseries [#1]}}
这允许我们为同一系列指定输入,如下所示:
\[
\Bseries
[[.,.][[[.]]]]
=
[
\Bseries
[.,.]
,
\Bseries
[[.]]
]
=
[
[
\Bseries
[]
,
\Bseries
[]
]
,
[
\Bseries
[.]
]
]
=
[
[
\Bseries
[]
,
\Bseries
[]
]
,
[
[
\Bseries
[]
]
]
]
\]
原版
我们首先指定一个森林风格,Bseries
因为否则,我们的树木会太大、太瘦长,无法达到舒适的美感。
\forestset{
Bseries/.style={
将下面的内容应用到整棵树:
for tree={
长大:
grow'=90,
将父锚点和子锚点设置在中心,以便边缘可以绘制到圆形节点的中心和从圆形节点的中心绘制:
parent anchor=center,
child anchor=center,
确保我们的节点不会太小的因为它们是空的:
minimum width=3pt,
消除inner sep
,这样它们就不会太大的:
inner sep=0pt,
为兄弟姐妹设定合理的最小间隔:
s sep=2.5pt,
确保所有节点都是实心的圆圈:
circle,
fill,
将树锚定在根节点(零级):
if level=0{
baseline
}{}
},
默认的级别分离会导致树散乱。我们希望整个树的级别之间的距离更小。我们延迟此操作是为了确保包的默认打包机制的结果不会覆盖我们的设置:
before computing xy={
for tree={
l=5pt,
}
}
}
}
我们可以按原样使用这种样式,但定义一个专用命令来应用它会更方便。因此我们\Bseries{<tree specification>}
为此定义:
\newcommand\Bseries[1]{\Forest{Bseries #1}}
然后我们可以说
\[
\Bseries{
[[[][]][[[[]]]]]
}
=
[
\Bseries{
[[][]]
}
,
\Bseries{
[[[]]]
}
]
=
[
[
\Bseries{
[]
}
,
\Bseries{
[]
}
]
,
[
\Bseries{
[[]]
}
]
]
=
[
[
\Bseries{
[]
}
,
\Bseries{
[]
}
]
,
[
[
\Bseries{
[]
}
]
]
]
\]
生产
原版完整代码:
\documentclass{article}
\usepackage{forest}
\forestset{
Bseries/.style={
for tree={
grow'=90,
parent anchor=center,
child anchor=center,
minimum width=3pt,
inner sep=0pt,
s sep=2.5pt,
circle,
fill,
if level=0{
baseline
}{}
},
before computing xy={
for tree={
l=5pt,
}
}
}
}
\newcommand\Bseries[1]{\Forest{Bseries #1}}
\begin{document}
\[
\Bseries{
[[[][]][[[[]]]]]
}
=
[
\Bseries{
[[][]]
}
,
\Bseries{
[[[]]]
}
]
=
[
[
\Bseries{
[]
}
,
\Bseries{
[]
}
]
,
[
\Bseries{
[[]]
}
]
]
=
[
[
\Bseries{
[]
}
,
\Bseries{
[]
}
]
,
[
[
\Bseries{
[]
}
]
]
]
\]
\end{document}
答案2
基本思想是使用 Ti钾Z 的图形绘制机制。它接受类似
\graph{/--{/--{/,/},/}};
画一个图。下一步是翻译
[
是/--{
]
是}
,
是,
.
是/
这是相当困难的,因为 Ti钾Z不喜欢
\graph\bgroup/--\bgroup/--\bgroup/,/\egroup,/\egroup\egroup;
(内部每一对{
和}
都将成为某些宏的参数,在这种情况下\bgroup
和\egroup
不是可选项)
因此我定义\Bseries
将内容写入文件并稍后将其包括在内。
PS 需要 LuaLaTeX。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{graphs,graphdrawing}
\usegdlibrary{layered}
\begin{document}
\newwrite\tempbseries
\def\Bseries{
\bgroup
\immediate\openout\tempbseries=\jobname.bseries
\immediate\write\tempbseries{\string\tikz[yscale=-.2,xscale=.2]\string\graph[layered layout,nodes={circle,fill,inner sep=1}]\string^\string^;}
\catcode`\[=\active
\catcode`\]=\active
\catcode`\,=\active
\catcode`\.=\active
\catcode`\;=\active
\def\par{\tikzerror{Giving up on this path. Did you forget a semicolon?}}
}
{
\catcode`\[=\active\gdef[{\immediate\write\tempbseries{/--\string^\string^;}}
\catcode`\]=\active\gdef]{\immediate\write\tempbseries{\string^\string^=}}
\catcode`\,=\active\gdef,{\immediate\write\tempbseries{\string,}}
\catcode`\.=\active\gdef.{\immediate\write\tempbseries{/\string,}}
\catcode`\;=\active\gdef;{\immediate\write\tempbseries{\string^\string^=\string;}\immediate\closeout\tempbseries\egroup\input{\jobname\string.bseries}}
}
\[
\Bseries[[.,.],[[.]]];
=
[
\Bseries[.,.];
,
\Bseries[[.]];
]
=
[
[
\Bseries.;
,
\Bseries.;
]
,
[
\Bseries[.];
]
]
=
[
[
\Bseries.;
,
\Bseries.;
]
,
[
[
\Bseries.;
]
]
]
\]
\end{document}
答案3
Symbol1 答案的变体,不需要辅助文件。但是,由于技术原因,*
使用 a 代替句点。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{graphs,graphdrawing}
\usegdlibrary{layered}
\newcommand{\setupbseriesactive}{%
\begingroup\lccode`~=`[ \lowercase{\endgroup\def~{/--\iftrue{\else}\fi}}%
\begingroup\lccode`~=`] \lowercase{\endgroup\def~{\iffalse{\else}\fi}}%
\begingroup\lccode`~=`* \lowercase{\endgroup\def~{/}}%
\catcode`[=\active \catcode`]=\active \catcode`*=\active
}
\newcommand\Bseries{\begingroup\setupbseriesactive\Bseriesaux}
\def\Bseriesaux#1;{%
\edef\Bseriestemp{%
\noexpand\tikz[yscale=-.2,xscale=.2]%
\noexpand\graph[layered layout,nodes={circle,fill,inner sep=1}]{#1};%
}\,\Bseriestemp\,%
\endgroup
}
\begin{document}
\[
\Bseries[[*,*],[[*]]];
=
[
\Bseries[*,*];
,
\Bseries[[*]];
]
=
[
[
\Bseries*;
,
\Bseries*;
]
,
[
\Bseries[*];
]
]
=
[
[
\Bseries*;
,
\Bseries*;
]
,
[
[
\Bseries*;
]
]
]
\]
\end{document}