绘制康托函数

绘制康托函数

我想知道是否有一种(简单的?)方法可以使用 LaTeX 绘制康托函数(魔鬼楼梯)。

使用 TikZ 手动进行绘制似乎有点疯狂,而且我对使用 TikZ 进行绘制的了解也非常有限。话虽如此,我在数学脚本中多次看到过绘制,那么它是如何完成的呢?有人知道吗?

以下是对康托函数

答案1

我也建议使用外部解决方案。但当然,在 TeX 中也是可行的。只是需要一点时间。

由于这是一个递归解决方案,它可能比非递归解决方案花费更多时间,但递归解决方案相对容易实现。

如果定义了cantor 2 edge/.style={move to}对角线部分,则不会绘制。(它不是edgeTikZ 路径运算符的一种方式。)

您可以像往常一样使用\draw您想要的任何选项开始您的路径,然后插入另一个选项:

cantor start={<lower x>}{<upper x>}{<lower y>}{<upper y>}{<level>}

有价值键

  • /tikz/lower cantor以及/tikz/upper cantor
  • /tikz/y cantor

我不知道这个y cantor值有多大意义,所以我把它添加为一个“有趣”的定义。在正确的阶梯定义中y cantor等于 0.5。(但是,我会使用这样标记的定义。)

代码

\documentclass[tikz]{standalone}
\tikzset{
  if/.code n args=3{\pgfmathparse{#1}\ifnum\pgfmathresult=0
    \pgfkeysalso{#3}\else\pgfkeysalso{#2}\fi},
  lower cantor/.initial=.3333, upper cantor/.initial=.6667, y cantor/.initial=.5,
  declare function={
    cantor_l(\lowerBound,\upperBound)=
      (\pgfkeysvalueof{/tikz/lower\space cantor})*(\upperBound-\lowerBound)+\lowerBound;
    cantor_u(\lowerBound,\upperBound)=
      (\pgfkeysvalueof{/tikz/upper\space cantor})*(\upperBound-\lowerBound)+\lowerBound;
    cantor(\lowerBound,\upperBound)=% fun definition
      (\pgfkeysvalueof{/tikz/y\space cantor})*(\upperBound-\lowerBound)+\lowerBound;},
  cantor start/.style n args=5{%
    insert path={(#1,#3)},
    cantor={#1}{#2}{#3}{#4}{#5}{0},
    insert path={to[every cantor edge/.try, cantor 1 edge/.try] (#2,#4)}},
  cantor/.style n args=6{%
    /utils/exec=%
      \pgfmathsetmacro\lBx{cantor_l(#1,#2)}%
      \pgfmathsetmacro\uBx{cantor_u(#1,#2)}%
%      \pgfmathsetmacro\y{.5*(#3+#4)},% proper definition
      \pgfmathsetmacro\y{cantor(#3,#4)},% fun
    style/.expanded={
      if={#6<#5}{cantor={#1}{\lBx}{#3}{\y}{#5}{#6+1}}{},
      insert path={
        to[every cantor edge/.try, cantor 1 edge/.try] (\lBx,\y)
        to[every cantor edge/.try, cantor 2 edge/.try] (\uBx,\y)},
      if={#6<#5}{cantor={\uBx}{#2}{\y}{#4}{#5}{#6+1}}{}}}}
\begin{document}
\foreach \level in {0,...,5}{
\begin{tikzpicture}[line join=round] % cantor 1 edge/.style={move to}
  \useasboundingbox[draw, scale=6, help lines]
    (0,0) grid[xstep=1/9, ystep=.25] (1,1);
  \draw[thick, cantor start={0}{6}{0}{6}{\level}{0}];
\end{tikzpicture}}
\foreach \val[evaluate={\lc=1/\val;\uc=(\val-1)/\val;}] in {2,...,9}{
\begin{tikzpicture}[line join=round, lower cantor=\lc, upper cantor=\uc]
%  \useasboundingbox[draw, scale=6, help lines]
%    (0,0) grid[xstep=\lc*\lc, ystep=.25] (1,1);
  \draw[thick, cantor start={0}{6}{0}{6}{6}{0}];
  \node [anchor=north west] at (0,6) {$\frac1\val$};
\end{tikzpicture}}
\foreach \val in {1,...,9}{
\begin{tikzpicture}[line join=round, y cantor=.\val, cantor 1 edge/.style={move to}]
  \draw[thick, cantor start={0}{6}{0}{6}{6}{0}];
  \node[anchor=north west] at (0,6) {$.\val$};
\end{tikzpicture}}
\end{document}

输出

在此处输入图片描述 在此处输入图片描述在此处输入图片描述

答案2

我很想看到有人直接在 LaTeX 中做到这一点,但与此同时,最简单的方法可能是使用其他方法生成数据并绘制生成的数据文件。

cantor下面是一个使用以下函数的Python 脚本https://stackoverflow.com/a/17810389/1456857生成数据文件:

def cantor(n):
    return [0.] + cant(0., 1., n) + [1.]

def cant(x, y, n):
    if n == 0:
        return []

    new_pts = [2.*x/3. + y/3., x/3. + 2.*y/3.]
    return cant(x, new_pts[0], n-1) + new_pts + cant(new_pts[1], y, n-1)

x = np.array(cantor(5))
y = np.cumsum( np.ones(len(x))/(len(x)-2) ) - 1./(len(x)-2)
y[-1] = 1

np.savetxt('cantor.dat', np.vstack([x,y]).T)

cantor.dat然后可以使用 PGFPlots 绘制该文件:

\documentclass{standalone}
\usepackage{pgfplots}
\begin{document}
    \begin{tikzpicture}
        \begin{axis}
        \addplot [const plot] table {cantor.dat};
        \end{axis}
    \end{tikzpicture}
\end{document}

答案3

n这是首次使用 MetaPost 的尝试,可以随意选择迭代次数,本例中为 10 次。

它确实需要改进,但无论如何它都表明它可以完成。使用 LuaLaTeX 进行排版。

编辑第二个是递归实现,更加精致。

vardef cantor(expr A, B, n) =
  if n = 0 : A -- B
  else: 
    save C, D; pair C, D; 
    C = (1/3[xpart A, xpart B], .5[ypart A, ypart B]); 
    D = (2/3[xpart A, xpart B], ypart C);
    cantor(A, C, n-1) -- cantor(D, B, n-1)
  fi
enddef;

现在,在后续的应用中,n 等于 15,但我猜测此实现可能会有更多处理。

編輯之二为了更好地呈现,我添加了一个类似于 Qrrbrbirlbel 的网格。

\documentclass[border=2mm]{standalone}
\usepackage{amsmath, luamplib}
  \mplibtextextlabel{enable}
  \mplibnumbersystem{double}
\begin{document}
  \begin{mplibcode}
    u  := 10cm;
    vardef cantor(expr A, B, n) =
      if n = 0 : A -- B
      else: 
        save C, D; pair C, D; 
        C = (1/3[xpart A, xpart B], .5[ypart A, ypart B]); 
        D = (2/3[xpart A, xpart B], ypart C);
        cantor(A, C, n-1) -- cantor(D, B, n-1)
      fi
    enddef;
    beginfig(1);
      % Grid and axes
      for i = 1 upto 9: draw (i*u/9, 0) -- (i*u/9, u) withcolor .8white; endfor
      for j = 1 upto 4: draw (0, j*u/4) -- (u, j*u/4) withcolor .8white; endfor
      drawarrow origin -- (1.1u, 0); drawarrow origin -- (0, 1.1u);
      % The function
      draw cantor(origin, (1, 1), 15) scaled u;
      % labels
      label.llft("$O$", origin); label.bot("$1$", (u, 0)); label.lft("$1$", (0, u));
      label.bot("$x$", (1.1u, 0)); label.lft("$y$", (0, 1.1u));
      label.bot("$\dfrac{1}{3}$", (1/3u, 0)); label.bot("$\dfrac{2}{3}$", (2/3u, 0));
      label.lft("$\dfrac{1}{2}$", (0, .5u));
    endfig;
  \end{mplibcode}
\end{document}

在此处输入图片描述

答案4

一个Asymptote MWE

// Cantor.asy    

settings.tex="pdflatex";
import graph;
real w=8cm,h=w; size(w,h);
import fontsize;defaultpen(fontsize(9pt));
texpreamble("\usepackage{lmodern}");     
xaxis(0,1,RightTicks(Step=0.20,step=0.1));
yaxis(0,1,LeftTicks (Step=0.20,step=0.1));
real eps=1e-10;
real fn (real x,int n){
  real u;
  if(n>0){
    if(0   <=x && x<=1/3) u=0.5fn(3x,n-1);
    if(1/3 < x && x<=2/3) u=0.5;
    if(2/3 < x && x<=1  ) u=0.5*(1+fn(3x-2,n-1));
  }else u=x;
  return u;
}
real f (real x){
  real u, v; int n=1;
  u=fn(x,0); v=fn(x,n);
  while(abs(u-v)>eps){ ++n; u=v; v=fn(x,n);}
  return u;
}
draw(graph(f,0,1,n=1000),darkblue+0.6bp+linejoin(0));
shipout(bbox(Fill(paleyellow)));

// To get Cantor.pdf, run
// asy Cantor.asy
//

在此处输入图片描述

相关内容