0

I'm currently working on a somewhat automatic way to generate B+ trees.

Thus I introduced a new macro to generate the content of a matrix of nodes which should also generate the labels automatically. This macro calls another macro to do this. I've added one \expandafter before to expand \x.

But I'm unable to get it to work correctly with the counter \ga. The value of the counter seems to be 4 in every case. So referencing to l1-n1-p4 works fine, but all other references (i.e. l1-n1-p2) cause an error.

Here's my code I have so far:

\documentclass{article}
\usepackage{tikz}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{etoolbox}
\usetikzlibrary{arrows}
\usetikzlibrary{shapes.multipart}
\usetikzlibrary{matrix, fit, calc}

\begin{document}

\newcount\ga
\ga = 1%

\newcommand{\drawkeymatrixnode}[4] {
    |(l#4-n#3-p#2) [fill=gray!50]| \vphantom{1} \&
    \ifx&#1&
        % empty argument #1
        |(l#4-n#3-k#2) [text width = 0.5cm, align = center]| \vphantom{1} \&
    \else
        % #1 not empty
        |(l#4-n#3-k#2) [text width = 0.5cm, align = center]| #1 \&
    \fi
}

\newcommand{\drawpointermatrixnode}[3] {
    |(l#3-n#2-p#1) [fill=gray!50]| \vphantom{1} \&
}

\newcommand{\btreematrixnode}[3]{%
    % #1 ... the level of the node
    % #2 ... number of node of level #1
    % #3 ... values as comma separated list

    \ga = 1%
    \let\mymatrixnodecontent\empty
    \foreach \x in #3 {%
        \expandafter\gappto\expandafter\mymatrixnodecontent\expandafter{\expandafter\drawkeymatrixnode\expandafter{\x}{\the\ga}{#2}{#1}}%
        \global\advance\ga by1
    }
    \expandafter\gappto\expandafter\mymatrixnodecontent\expandafter{\expandafter\drawpointermatrixnode\expandafter{\the\ga}{#2}{#1}}%
    \gappto\mymatrixnodecontent{\\}%
}

\begin{center}
\begin{tikzpicture}[
        scale = 1.0,
        ->,
        >=stealth',
        level 1/.style = {
            sibling distance = 7cm,
            level distance = 1.5cm
        },
        level 2/.style = {
            sibling distance = 3.5cm,
            level distance = 1.5cm
        },
        edge from parent/.style = {}, % no connecting arrows
        bnode/.style = {
            matrix,
            matrix of nodes,
            ampersand replacement=\&,
            nodes = {draw, rectangle, minimum height = 0.5cm}
        }
    ] 

    \btreematrixnode{1}{1}{{1, 2, 3}}
    \let\cLOne\mymatrixnodecontent
    \btreematrixnode{2}{1}{{4, 5, 6}}
    \let\cLTwoNOne\mymatrixnodecontent
    \btreematrixnode{2}{2}{{7, 8, 9}}
    \let\cLTwoNTwo\mymatrixnodecontent

    \node[bnode] (root) {\cLOne}
    child {
        node[bnode] {\cLTwoNOne}
    }
    child {
        node[bnode] {\cLTwoNTwo}
    };

    % should be \draw (l1-n1-p2) -- (l2-n1-k2);
    \draw (l1-n1-p4) -- (l2-n1-k4);
\end{tikzpicture}
\end{center}
\end{document}

So I'd like to generate labels of the form l<levelnr>-n<nodenr>-k<keynr> and l<levelnr>-n<nodenr>-p<pointernr> respectively. So for a node containing 3 keys and 4 pointers in node 1 of the first level, I'd like to get the l1-n1-p1, l1-n1-k1, l1-n1-p2, l1-n1-k2, l1-n1-p3, l1-n1-k3, l1-n1-p4. But it seems that I only l1-n1-p4 get generated because I get a no shape named l1-n1-p2 is known error.

I've already read some threads I found searching for 'expandafter multiple arguments' but I've not figured out by now how to get it to work.

1

You have to expand the \the\ga argument. For example:

...
\newcommand{\btreematrixnode}[3]{%
    % #1 ... the level of the node
    % #2 ... number of node of level #1
    % #3 ... values as comma separated list
    \ga = 1%
    \let\mymatrixnodecontent\empty
    \foreach \x in #3 {%
        \edef\tmp{{\x}{\the\ga}}%
        \expandafter\gappto\expandafter\mymatrixnodecontent\expandafter
            {\expandafter\drawkeymatrixnode\tmp{#2}{#1}}%
        \global\advance\ga by1
    }
    \expandafter\gappto\expandafter\mymatrixnodecontent\expandafter
        {\expandafter\drawpointermatrixnode\expandafter{\the\ga}{#2}{#1}}%
    \gappto\mymatrixnodecontent{\\}%
}
...
    % should be \draw (l1-n1-p2) -- (l2-n1-k2);
    %    \draw (l1-n1-p4) -- (l2-n1-k4);
\draw (l1-n1-p2) -- (l2-n1-k2);
...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.