Drawing nonuniform Cantor set

Using lindenmeyer systems, there is a nice way to make a uniform Cantor set using the following code.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\pgfdeclarelindenmayersystem{cantor set}{
\rule{F -> FfF}
\rule{f -> fff}
}
\begin{document}
\begin{tikzpicture}
\foreach \order in {0,...,4}
\draw[yshift=-\order*10pt]  l-system[l-system={cantor set, axiom=F, order=\order, step=100pt/(3^\order)}];
\end{tikzpicture}
\end{document}


This is the usual 1/3, 1/3 Cantor set. I can easily modify this to make a 1/5,1/5,1/5 Cantor set, etcetera. But I would like to make a nonuniform Cantor set, like 1/4, 1/2. And the modification of this doesn't work:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\pgfdeclarelindenmayersystem{cantor set}{
\rule{F -> FfFF}
\rule{f -> ffff}
}
\begin{document}
\begin{tikzpicture}
\foreach \order in {0,...,4}
\draw[yshift=-\order*10pt]  l-system[l-system={cantor set, axiom=F, order=\order, step=100pt/(4^\order)}];
\end{tikzpicture}
\end{document}


The first step is correct, but the fractal is no longer self-similar after that step. Does anyone know what I'm missing?

• I added the images that your code produces. This helps to understand the question and my (unsatisfactory) answer. – JLDiaz Aug 31 '17 at 20:05

The problem is that your rule F -> FfFF has two F's after the f gap. This produces the intended result of one line twice as long as the normal F line, but as a side effect it also is expanded (by the same rule) twice, producing two "gaps" at the right segment, instead a single one.

What you need is some way to express a rule F -> FfG, being F a drawn segment, f a non-drawn (move) segment, and G a new segment with a length different than F length. But then you have to write a rule about how to expand G for the next step, and what we need is some way to express "Let G be F for the next expansion", but this cannot be expressed with a Lyndenmayer grammar.

So, in my opinion, a non-uniform Cantor set cannot be expressed with Lyndenmayer grammar. At least I was unable to do so after one hour of unsucessful attemps. See this for example:

\documentclass[margin=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{lindenmayersystems}
\pgfdeclarelindenmayersystem{cantor set}{
\symbol{G}{\pgflsystemdrawforward\pgflsystemdrawforward}
\rule{F -> FfG}
\rule{f -> ffff}
\rule{G -> FfG}  % Doesn't work
}
\begin{document}
\begin{tikzpicture}
\foreach \order in {0,...,4}
\draw[yshift=-\order*10pt]  l-system[l-system={cantor set, axiom=F, order=\order, step=100pt/(4^\order)}];
\end{tikzpicture}
\end{document}


Here I defined the symbol G to draw a line twice as long as F. This works for the first expansion, and for the expansion of the "left branch", but then I failed to find a rule to express how the "right branch" should be expanded (i.e: the expansion rule for G). This is the result:

The combinatory of the uniform and the nonuniform Cantor sets are the same. So the only thing that we should keep track is the scale factor. So in place of the standard F -> F f F we can use F -> AF Bf CF D where A,B, C and D just set the proper scale factor.

The left factor and right factor should be set appropriately.

\documentclass[tikz,border=7pt]{standalone}
\usetikzlibrary{lindenmayersystems,decorations.pathreplacing,calc}

\tikzset{
% starting options for the Cantor systems
cantor/.style = {
l-system={Cantor, axiom=F, order=#1, step=1cm},
},
% define the Cantor factors, the uniform case is 1/3,1/3,1/3
left factor/.store in=\leftfactor, left factor = {1/3},
right factor/.store in=\rightfactor, right factor = {1/3},
% calculate the middle factor
cantor/.append code={\pgfmathsetmacro{\midfactor}{1-\leftfactor-\rightfactor}}
}
% define the cantor system
\pgfdeclarelindenmayersystem{Cantor}{
\symbol{A}{\pgftransformscale{\leftfactor}}
\symbol{B}{\pgftransformscale{(\midfactor)/(\leftfactor)}}
\symbol{C}{\pgftransformscale{(\rightfactor)/(\midfactor)}}
\symbol{D}{\pgftransformscale{1/(\rightfactor)}}
\rule{F -> AF Bf CF D}
}
\begin{document}
\begin{tikzpicture}[xscale=10, line width=1mm, purple]
\draw[left factor=1/4,right factor=2/3]
foreach \order in {0,...,4}{
[yshift=\order*2mm] l-system [cantor=\order]
};
\end{tikzpicture}
\end{document}


BUT: There is a precision problem starting from order 5 :( Here is the image for 7 levels.

Another but, with 1/4,1/4,1/2 factors, it is ok up to order 7 ;)