나는 Stern-Brocot 트리(합리성의 열거)를 구축하려고 합니다.
결과는 거의 만족스럽습니다만, 다음과 같은 점에서는 여전히 불만족스럽습니다.
- 부모 노드의 가장자리는 위쪽 테두리가 아닌 자식 노드의 가운데로 이동합니다.
- 명령은 각 반복에서 인수를 (재)평가하지 않습니다(
1+1+1
대신 유지합니다3
). - 재귀 호출에서는
\bt@n
and 를 사용할 수 없습니다 . 왜냐하면 그것들이 어떻게든 엉망이 되기 때문입니다(왜?).\bt@d
- 내 노드에 이름을 지정해야 하는데 이는 쓸모가 없지만 LaTeX는 없이는 컴파일되지 않습니다.
코드는 다음과 같습니다.
\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\newcommand{\eval}[1]{\pgfmathparse{int(#1)}\pgfmathresult}
\makeatletter % We can use the `@` symbol in macro names
\def\mybtree#1#2#3#4#5{%
\pgfextra{ % Allows us to use non-drawing commands
\pgfmathtruncatemacro\bt@depth{#5} % Current depth
\pgfmathtruncatemacro\bt@ndepth{\bt@depth - 1} % Next depth
\pgfmathtruncatemacro\bt@n{#1+#3}
\pgfmathtruncatemacro\bt@d{#2+#4}
%% Calculate the sibling distance
% distance = 2^{remaining depth}
\pgfmathsetmacro\bt@sdistance{pow( 2, \bt@depth)}
}
node (\bt@n/\bt@d) {$\frac{\eval{#1+#3}}{ \eval{#2+#4}}$}
\ifnumgreater{\bt@depth}{0}{% if( depth > 0 ) then:
child [sibling distance=\bt@sdistance*2em] {
\mybtree{#1}{#2}{#1+#3}{#2+#4}{\bt@ndepth}
}
child [sibling distance=\bt@sdistance*2em] {
\mybtree{#1+#3}{#2+#4}{#3}{#4}{\bt@ndepth}
}
}{% else:
%% Do nothing
}
}
\newcommand*{\btree}[1]{\mybtree{0}{1}{1}{0}{#1}}
\makeatother
\begin{document}
%% Now we can draw our tree
\begin{tikzpicture}
\draw \btree{3};
\end{tikzpicture}
\end{document}
그러니 어떤 도움이라도 환영합니다.
답변1
제가 당신에게 제안해도 될까요?forest
?
암호
\documentclass[tikz]{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
Stern Brocot/.style n args={5}{%
content=$\frac{\number\numexpr#1+#3\relax}{\number\numexpr#2+#4\relax}$,
if={#5>0}{% true
append={[,Stern Brocot={#1}{#2}{#1+#3}{#2+#4}{#5-1}]},
append={[,Stern Brocot={#1+#3}{#2+#4}{#3}{#4}{#5-1}]}
}{}}% false (empty)
[,Stern Brocot={0}{1}{1}{0}{3}]
\end{forest}
\end{document}
산출
코드(더 많은 내용 포함)
\documentclass[tikz]{standalone}
\usepackage{forest}
\makeatletter
\pgfmathdeclarefunction{strrepeat}{2}{%
\begingroup\pgfmathint{#2}\pgfmath@count\pgfmathresult
\let\pgfmathresult\pgfutil@empty
\pgfutil@loop\ifnum\pgfmath@count>0\relax
\expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult#1}%
\advance\pgfmath@count-1\relax
\pgfutil@repeat\pgfmath@smuggleone\pgfmathresult\endgroup}
\makeatother
\tikzset{
Stern Brocot at/.style={at/.wrap 2 pgfmath args={([rotate around=180:(!##1)] !##22)}
{strrepeat("#1",\SBLevel)}{strrepeat("#1",\SBLevel-1)}},
Stern Brocot at*/.style n args={3}{
at/.wrap pgfmath arg={(!##1-|SB@#3)}{strrepeat("#1",#2)},
/forest/if={#2<\SBLevel}{append after command=
(\tikzlastnode) edge[densely dotted] (SB@#3@\the\numexpr\SBLLoop+1\relax)}{}}}
\forestset{
Stern Brocot*/.style n args={2}{
content=$\frac{#1}{#2}$,
edge=densely dotted,
if={level()<\SBLevel}{append={[,Stern Brocot*={#1}{#2}]}}{}},
Stern Brocot/.style n args={5}{
/utils/exec=\edef\SBLevel{#5},@Stern Brocot={#1}{#2}{#3}{#4}},
@Stern Brocot/.style n args={4}{
/utils/exec=\edef\SBTop {\number\numexpr#1+#3\relax}% eTeX instead of PGFmath
\edef\SBBottom{\number\numexpr#2+#4\relax},
content/.expanded=$\frac{\SBTop}{\SBBottom}$,
if/.expanded={level()<\SBLevel}{% true
append={[,@Stern Brocot={#1}{#2}{\SBTop}{\SBBottom}]},
append={[,Stern Brocot*={\SBTop}{\SBBottom}]},
append={[,@Stern Brocot={\SBTop}{\SBBottom}{#3}{#4}]}
}{}}}% false (empty)
\begin{document}
\begin{forest}[,Stern Brocot={0}{1}{1}{0}{3}]
\coordinate[Stern Brocot at=1] (SB@left) coordinate[Stern Brocot at=3] (SB@right);
\foreach \SBLLoop in {\SBLevel, ..., 0}
\path node[Stern Brocot at*={1}{\SBLLoop}{left}] (SB@left@\SBLLoop) {$\frac01$}
node[Stern Brocot at*={3}{\SBLLoop}{right}] (SB@right@\SBLLoop) {$\frac10$};
\end{forest}
\end{document}
출력(더 많은 내용 포함)
답변2
다음은 Metapost 버전입니다. 주로 재귀가 luamplib
.
\documentclass[border=10mm]{standalone}
\usepackage{unicode-math}
\setmainfont{TeX Gyre Schola}
\usepackage{luamplib}
\mplibtextextlabel{enable}
\begin{document}
\begin{mplibcode}
path S; S = superellipse(9 right, 12 up, 9 left, 12 down,0.79);
def connect(expr a,b) =
draw a -- b cutbefore S shifted a cutafter S shifted b
enddef;
def putfrac(expr num, den, pos) =
draw (left--right) scaled 4 shifted pos;
label.top(decimal num,pos);
label.bot(decimal den,pos);
enddef;
vardef mediant(expr a,b,c,d, depth, L, R) =
save m,n, p; pair p;
p = ((L+R)/2,depth * v);
m = a+c; n = b+d;
if depth > 1:
connect(p, mediant(a,b,m,n,depth-1, L, xpart p)) withcolor .53 red;
connect(p, mediant(m,n,c,d,depth-1, xpart p, R)) withcolor .53 blue;
connect(p, p shifted (0,-v)) dashed withdots scaled 1/2;
connect((L, ypart p), (L,ypart p-v)) dashed withdots scaled 1/2;
if d=0:
connect((R, ypart p), (R,ypart p-v)) dashed withdots scaled 1/2;
fi
fi
if depth > 0:
putfrac(m,n,p);
putfrac(a,b,(L,ypart p));
if d=0:
putfrac(c,d,(R,ypart p));
fi
fi
p
enddef;
beginfig(1);
v = 1.618cm;
z0 = mediant(0,1,1,0, 5, 0,220mm);
endfig;
\end{mplibcode}
\end{document}
답변3
재미삼아 여기서는 TeX
주어진 유리수의 전임자를 계산하는 데 사용되었습니다. 주의하세요.~ 아니다질문에 대한 답변입니다.
다음과 같은 이유로 2013년 9월부터 버전을 업데이트하고 있습니다.
이제 명시적으로 로드해야 합니다
xinttools
.이 방법은 연속된 분수의 계수 계산, 마지막 분수의 계수 감소, 분수의 재구성 및 반복을 거치므로 매우 비효율적입니다.
결과를 보면 구현에 버그가 있다는 것을 깨달았습니다. 마지막 계수 하나만큼 감소한 것이 올바르게 버팀대되지 않았으므로 일부 연속된 분수 계수가 적어도
10
:-(((
새로운 구현은 연속 분수의 계수가 아닌 수렴으로 진행됩니다. 그것은 그것들을 단번에 계산합니다. 그들은 주어진 분수의 조상 중 하나이지만, 모든 조상을 찾으려면 더 많은 분수를 추가해야 합니다. 레시피는 코드 주석에 설명되어 있습니다. 수렴은 트리를 위로 이동할 때 방향이 바뀌는 위치에 해당합니다.
\documentclass{article}
\usepackage{xintcfrac, xinttools}
\makeatletter
\newcommand*\defSBAncestors [1]{%
% we first compute all convergents of a positive fraction
% we need to reverse the order, then we will scan and
% add the needed intermediate fractions.
% \SBA@i will see p/q.p'/q'....... n/1.\relax
% The ending n/1 is 0/1 if original fraction was <1.
% We need to add intermediate (p-p')/(q-q'), (p-2p')/(q-2q'), ...
\def\SBAncestors{}%
\expandafter\SBA@i
\romannumeral0\xintlistwithsep.{\xintRevWithBraces{\xintFtoCv{#1}}}.\relax
}
\def\SBA@i #1/#2.{\if1\xintiiIsOne{#1}\xintdothis\SBA@D\fi
\if1\xintiiIsOne{#2}\xintdothis\SBA@N\fi
\xintorthat\SBA@ii #1/#2.}
\def\SBA@ii #1/#2.#3/#4.{%
\edef\SBAncestors{\SBAncestors{#1/#2}}%
\edef\SBA@P {\xintiiSub{#1}{#3}}%
\edef\SBA@Q {\xintiiSub{#2}{#4}}%
\if1\xintiiGtorEq {#3}{\SBA@P}\xintdothis\SBA@i\fi
\xintorthat{\SBA@ii \SBA@P/\SBA@Q.}#3/#4.}
% Treat the special situations N/1 or 1/D
\def\SBA@D 1/#1.#2\relax {\edef\SBAncestors{\SBAncestors
\xintApply{1/\@firstofone}{\xintSeq[-1]{#1}{1}}}}
\def\SBA@N #1/#2\relax {\edef\SBAncestors{\SBAncestors\xintSeq[-1]{#1}{1}}}
\makeatother
\newcommand*\STRUT{\rule[4pt]{0pt}{9pt}} % line spacing
% #1 must evaluate to a **positive** fraction. It will be reduced to smalles
% terms initially.
\newcommand*\ShowParents [1]{%
\defSBAncestors {#1}%
$\xintListWithSep{\to}{\xintApply{\STRUT\xintFrac}\SBAncestors}$%
}
\begin{document}
\ShowParents {5}
\ShowParents {1/5}
\ShowParents {23/16}
\ShowParents {355/113}
\ShowParents {137197119/2110810820}
\end{document}