4

There are at least 4 different (in code a-d) ways to access items in lists/arrays. Out of curiosity I wanted to see what happens with different combinations. I selected 6 different (in code A-F) input scenarios and tested them 2 levels deep. That means potentially 4*4*6=96 tests.

\documentclass{standalone}
\usepackage{tikz}
\usepackage{ifthen}
\begin{document}

\message{^^J}

\begin{tikzpicture}
  \def \A {{{{9, 8, 7}}, {{6, 5}}}}
  \def \B {{{9, 8, 7}, {6, 5}}}
  \def \C {{9, 8, 7}}
  \def \D {{{9, 8, 7}}, {{6, 5}}}
  \def \E {{9, 8, 7}, {6, 5}}
  \def \F {9, 8, 7}

  \def \tests#1#2#3
  {
    \begingroup
    \edef \depth {3.0}
    \edef \olddepth {#3}
    \def \arecurse {0}
    \def \brecurse {0}
    \def \crecurse {0}
    \def \drecurse {0}

    \pgfmathparse{\olddepth + 1}
    \edef\newdepth{\pgfmathresult}

    \ifthenelse{\equal{\newdepth}{\depth}}{}
    {
      \message{input (#1):}
      \message{#2 ^^J}

      %% a
      \message{ foreach (#1+a):}
      \foreach \x in #2
      {
        \xdef \aa {\x}
        \message{\aa ^^J}
        \breakforeach
      }

      %% b
      \message{ pgfmatharray (#1+b):}
      \pgfmatharray{#2}{0}
      \edef \bb {\pgfmathresult}
      \message{\bb ^^J}

      %% c
      \message{ pgfmathparse + index (#1+c):}
      \ifthenelse{\equal{#1}{Ba} \or
                  \equal{#1}{Da} \or
                  \equal{#1}{F}}
      {
        \def \crecurse {1}
        \message{Error ^^J}
      }{
        \pgfmathparse{#2[0]}
        \edef \cc {\pgfmathresult}
        \message{\cc ^^J}
      }

      %% d
      \message{ pgfmathparse + array (#1+d):}
      \ifthenelse{\equal{#1}{Ad} \or
                  \equal{#1}{Ba} \or
                  \equal{#1}{Bd} \or
                  \equal{#1}{D} \or
                  \equal{#1}{Da} \or
                  \equal{#1}{E} \or
                  \equal{#1}{F}}
      {
        \def \drecurse {1}
        \message{Error ^^J}
      }{
        \pgfmathparse{array(#2, 0)}
        \edef \dd {\pgfmathresult}
        \message{\dd ^^J}
      }

      \ifthenelse{\arecurse = 0}{\tests{#1a}{\aa}{\newdepth}}{}
      \ifthenelse{\brecurse = 0}{\tests{#1b}{\bb}{\newdepth}}{}
      \ifthenelse{\crecurse = 0}{\tests{#1c}{\cc}{\newdepth}}{}
      \ifthenelse{\drecurse = 0}{\tests{#1d}{\dd}{\newdepth}}{}
    }
    \endgroup
  }

  \tests{A}{\A}{0.0}
  \tests{B}{\B}{0.0}
  \tests{C}{\C}{0.0}
  \tests{D}{\D}{0.0}
  \tests{E}{\E}{0.0}
  \tests{F}{\F}{0.0}
\end{tikzpicture}
\end{document}

In output, the performed operations can be deduced from the string inside parentheses. For example (Aa+b) or (Aab) means using input A:{{{{9, 8, 7}}, {{6, 5}}}} to /foreach to select the first item followed by \pgfmatharray to select the first item. Some combinations will produce an error so they are skipped by \ifthenelse for the code to complete.

There are some interesting results. Some of the inputs, I know, are abominable, but curiosity makes me ask why the particular things produce the outputs?

foreach works quite consistently

input:                        foreach:
(A): {{{9, 8, 7}}, {{6, 5}}}  (A+a): {{9, 8, 7}}, {{6, 5}}
(Aa): {{9, 8, 7}}, {{6, 5}}   (Aa+a): {9, 8, 7}
(Ab): {9}{8}{7}               (Ab+a): {9}{8}{7}
(Ac): {{9}{8}{7}}             (Ac+a): {9}{8}{7}
(Ad): {9}{8}{7}               (Ad+a): {9}{8}{7}
(B): {{9, 8, 7}, {6, 5}}      (B+a): {9, 8, 7}, {6, 5}
(Ba): {9, 8, 7}, {6, 5}       (Ba+a): 9, 8, 7
(Bb): {9}{8}{7}               (Bb+a): {9}{8}{7}
(Bc): {{9}{8}{7}}             (Bc+a): {9}{8}{7}
(Bd): {9}{8}{7}               (Bd+a): {9}{8}{7}
(C): {9, 8, 7}                (C+a): 9, 8, 7
(Ca): 9, 8, 7                 (Ca+a): 9
(Cb): 9                       (Cb+a): 9
(Cc): 9                       (Cc+a): 9
(Cd): 9                       (Cd+a): 9                   
(D): {{9, 8, 7}}, {{6, 5}}    (D+a): {9, 8, 7}
(Da): {9, 8, 7}               (Da+a): 9, 8, 7
(Db): {9}{8}{7}               (Db+a): {9}{8}{7}
(Dc): {{9}{8}{7}}{{6}{5}}     (Dc+a): {{9}{8}{7}}{{6}{5}}
(E): {9, 8, 7}, {6, 5}        (E+a): 9, 8, 7
(Ea): 9, 8, 7                 (Ea+a): 9
(Eb): {9}{8}{7}               (Eb+a): {9}{8}{7}
(Ec): {{9}{8}{7}}{6}          (Ec+a): {{9}{8}{7}}{6}
(F): 9, 8, 7                  (F+a): 9
(Fa): 9                       (Fa+a): 9
(Fb): 9                       (Fb+a): 9

There is a definite difference between pgfmath* workings. pgfmatharray and pgfmathparse + array are clearly close to each other. The latter just seems to choke every once a while so the former is preferred.

pgfmathparse + index is clearly the odd one out. It seems somewhat inconsistent, for example the case of (E+c).

The cases where the result is 5,6, or 7 are interesting. Why return the last element if return anything at all when trying to access the first one? It looks like the macro parses the input and just returns the last item that is left.

Why the difference between the pgfmath* versions at all?

The interesting question is which one to use? They obviously return different things even with sane input.

input:                        pgfmatharray:     pgfmathparse + array:   pgfmathparse + index:
(A): {{{9, 8, 7}}, {{6, 5}}}  (A+b): {9}{8}{7}  (A+d): {9}{8}{7}        (A+c): {{9}{8}{7}}
(Aa): {{9, 8, 7}}, {{6, 5}}   (Aa+b): 9         (Aa+d): 9               (Aa+c): 9
(Ab): {9}{8}{7}               (Ab+b): 7         (Ab+d): 7               (Ab+c): 7
(Ac): {{9}{8}{7}}             (Ac+b): 7         (Ac+d): 7               (Ac+c): 7
(Ad): {9}{8}{7}               (Ad+b): 7         (Ad+d): Error           (Ad+c): 7
(B): {{9, 8, 7}, {6, 5}}      (B+b): {9}{8}{7}  (B+d): {9}{8}{7}        (B+c): {{9}{8}{7}}
(Ba): {9, 8, 7}, {6, 5}       (Ba+b): 9         (Ba+d): Error           (Ba+c): Error
(Bb): {9}{8}{7}               (Bb+b): 7         (Bb+d): 7               (Bb+c): 7
(Bc): {{9}{8}{7}}             (Bc+b): 7         (Bc+d): 7               (Bc+c): 7
(Bd): {9}{8}{7}               (Bd+b): 7         (Bd+d): Error           (Bd+c): 7
(C): {9, 8, 7}                (C+b): 9          (C+d): 9                (C+c): 9
(Ca): 9, 8, 7                 (Ca+b): 9         (Ca+d): 9               (Ca+c): 9
(Cb): 9                       (Cb+b): 9         (Cb+d): 9               (Cb+c): 9
(Cc): 9                       (Cc+b): 9         (Cc+d): 9               (Cc+c): 9
(Cd): 9                       (Cd+b): 9         (Cd+d): 9               (Cd+c): 9
(D): {{9, 8, 7}}, {{6, 5}}    (D+b): {9}{8}{7}  (D+d): Error            (D+c): {{9}{8}{7}}{{6}{5}}
(Da): {9, 8, 7}               (Da+b): 9         (Da+d): Error           (Da+c): Error
(Db): {9}{8}{7}               (Db+b): 7         (Db+d): 7               (Db+c): 7
(Dc): {{9}{8}{7}}{{6}{5}}     (Dc+b): 5         (Dc+d): 5               (Dc+c): 5
(E): {9, 8, 7}, {6, 5}        (E+b): {9}{8}{7}  (E+d): Error            (E+c): {{9}{8}{7}}{6}
(Ea): 9, 8, 7                 (Ea+b): 9         (Ea+d): 9               (Ea+c): 9
(Eb): {9}{8}{7}               (Eb+b): 7         (Eb+d): 7               (Eb+c): 7
(Ec): {{9}{8}{7}}{6}          (Ec+b): 6         (Ec+d): 6               (Ec+c): 6
(F): 9, 8, 7                  (F+b): 9          (F+d): Error            (F+c): Error
(Fa): 9                       (Fa+b): 9         (Fa+d): 9               (Fa+c): 9
(Fb): 9                       (Fb+b): 9         (Fb+d): 9               (Fb+c): 9

Same input should give same results. When input is sorted these stand out. There is something going on there.

input:                        pgfmatharray:     pgfmathparse + array:   pgfmathparse + index:
(Ca): 9, 8, 7                 (Ca+b): 9         (Ca+d): 9               (Ca+c): 9
(Ea): 9, 8, 7                 (Ea+b): 9         (Ea+d): 9               (Ea+c): 9
(F): 9, 8, 7                  (F+b): 9          (F+d): Error            (F+c): Error

(C): {9, 8, 7}                (C+b): 9          (C+d): 9                (C+c): 9
(Da): {9, 8, 7}               (Da+b): 9         (Da+d): Error           (Da+c): Error

(Ba): {9, 8, 7}, {6, 5}       (Ba+b): 9         (Ba+d): Error           (Ba+c): Error
(E): {9, 8, 7}, {6, 5}        (E+b): {9}{8}{7}  (E+d): Error            (E+c): {{9}{8}{7}}{6}

(Ab): {9}{8}{7}               (Ab+b): 7         (Ab+d): 7               (Ab+c): 7
(Bb): {9}{8}{7}               (Bb+b): 7         (Bb+d): 7               (Bb+c): 7
(Db): {9}{8}{7}               (Db+b): 7         (Db+d): 7               (Db+c): 7
(Eb): {9}{8}{7}               (Eb+b): 7         (Eb+d): 7               (Eb+c): 7
(Ad): {9}{8}{7}               (Ad+b): 7         (Ad+d): Error           (Ad+c): 7
(Bd): {9}{8}{7}               (Bd+b): 7         (Bd+d): Error           (Bd+c): 7

(Aa): {{9, 8, 7}}, {{6, 5}}   (Aa+b): 9         (Aa+d): 9               (Aa+c): 9
(D): {{9, 8, 7}}, {{6, 5}}    (D+b): {9}{8}{7}  (D+d): Error            (D+c): {{9}{8}{7}}{{6}{5}}

(Ec): {{9}{8}{7}}{6}          (Ec+b): 6         (Ec+d): 6               (Ec+c): 6
(Eca): {{9}{8}{7}}{6}         (Eca+b): 6        (Eca+d): Error          (Eca+c): 6

The original output

input (A): {{{9, 8, 7}}, {{6, 5}}}
 foreach (A+a): {{9, 8, 7}}, {{6, 5}}
 pgfmatharray (A+b): {9}{8}{7}
 pgfmathparse + index (A+c): {{9}{8}{7}}
 pgfmathparse + array (A+d): {9}{8}{7}
input (Aa): {{9, 8, 7}}, {{6, 5}}
 foreach (Aa+a): {9, 8, 7}
 pgfmatharray (Aa+b): 9
 pgfmathparse + index (Aa+c): 9
 pgfmathparse + array (Aa+d): 9
input (Ab): {9}{8}{7}
 foreach (Ab+a): {9}{8}{7}
 pgfmatharray (Ab+b): 7                           % 1. Why last?
 pgfmathparse + index (Ab+c): 7                   % 1. Why last?
 pgfmathparse + array (Ab+d): 7                   % 1. Why last?
input (Ac): {{9}{8}{7}}
 foreach (Ac+a): {9}{8}{7}
 pgfmatharray (Ac+b): 7                           % 1. Why last?
 pgfmathparse + index (Ac+c): 7                   % 1. Why last?
 pgfmathparse + array (Ac+d): 7                   % 1. Why last?
input (Ad): {9}{8}{7}
 foreach (Ad+a): {9}{8}{7}
 pgfmatharray (Ad+b): 7                           % 1. Why last?
 pgfmathparse + index (Ad+c): 7                   % 1. Why last?
 pgfmathparse + array (Ad+d): Error               % 2. Why differ from (Ab+d)?
input (B): {{9, 8, 7}, {6, 5}}
 foreach (B+a): {9, 8, 7}, {6, 5}
 pgfmatharray (B+b): {9}{8}{7}
 pgfmathparse + index (B+c): {{9}{8}{7}}
 pgfmathparse + array (B+d): {9}{8}{7}
input (Ba): {9, 8, 7}, {6, 5}
 foreach (Ba+a): 9, 8, 7
 pgfmatharray (Ba+b): 9
 pgfmathparse + index (Ba+c): Error
 pgfmathparse + array (Ba+d): Error
input (Bb): {9}{8}{7}
 foreach (Bb+a): {9}{8}{7}
 pgfmatharray (Bb+b): 7                           % 1. Why last?
 pgfmathparse + index (Bb+c): 7                   % 1. Why last?
 pgfmathparse + array (Bb+d): 7                   % 1. Why last?
input (Bc): {{9}{8}{7}}
 foreach (Bc+a): {9}{8}{7}
 pgfmatharray (Bc+b): 7                           % 1. Why last?
 pgfmathparse + index (Bc+c): 7                   % 1. Why last?
 pgfmathparse + array (Bc+d): 7                   % 1. Why last?
input (Bd): {9}{8}{7}
 foreach (Bd+a): {9}{8}{7}
 pgfmatharray (Bd+b): 7                           % 1. Why last?
 pgfmathparse + index (Bd+c): 7                   % 1. Why last?
 pgfmathparse + array (Bd+d): Error               % 2. Why differ from (Bb+d)?
input (C): {9, 8, 7}
 foreach (C+a): 9, 8, 7
 pgfmatharray (C+b): 9
 pgfmathparse + index (C+c): 9
 pgfmathparse + array (C+d): 9
input (Ca): 9, 8, 7
 foreach (Ca+a): 9
 pgfmatharray (Ca+b): 9
 pgfmathparse + index (Ca+c): 9
 pgfmathparse + array (Ca+d): 9
input (Cb): 9
 foreach (Cb+a): 9
 pgfmatharray (Cb+b): 9
 pgfmathparse + index (Cb+c): 9
 pgfmathparse + array (Cb+d): 9
input (Cc): 9
 foreach (Cc+a): 9
 pgfmatharray (Cc+b): 9
 pgfmathparse + index (Cc+c): 9
 pgfmathparse + array (Cc+d): 9
input (Cd): 9
 foreach (Cd+a): 9
 pgfmatharray (Cd+b): 9
 pgfmathparse + index (Cd+c): 9
 pgfmathparse + array (Cd+d): 9
input (D): {{9, 8, 7}}, {{6, 5}}
 foreach (D+a): {9, 8, 7}
 pgfmatharray (D+b): {9}{8}{7}
 pgfmathparse + index (D+c): {{9}{8}{7}}{{6}{5}}
 pgfmathparse + array (D+d): Error                % 3. Why differ from (D+c)?
input (Da): {9, 8, 7}
 foreach (Da+a): 9, 8, 7
 pgfmatharray (Da+b): 9
 pgfmathparse + index (Da+c): Error
 pgfmathparse + array (Da+d): Error
input (Db): {9}{8}{7}
 foreach (Db+a): {9}{8}{7}
 pgfmatharray (Db+b): 7                           % 1. Why last?
 pgfmathparse + index (Db+c): 7                   % 1. Why last?
 pgfmathparse + array (Db+d): 7                   % 1. Why last?
input (Dc): {{9}{8}{7}}{{6}{5}}
 foreach (Dc+a): {{9}{8}{7}}{{6}{5}}
 pgfmatharray (Dc+b): 5                           % 1. Why last?
 pgfmathparse + index (Dc+c): 5                   % 1. Why last?
 pgfmathparse + array (Dc+d): 5                   % 1. Why last?
input (E): {9, 8, 7}, {6, 5}
 foreach (E+a): 9, 8, 7
 pgfmatharray (E+b): {9}{8}{7}
 pgfmathparse + index (E+c): {{9}{8}{7}}{6}       % 4. Strange. Why?
 pgfmathparse + array (E+d): Error                % 3. Why differ from (E+c)?
input (Ea): 9, 8, 7
 foreach (Ea+a): 9
 pgfmatharray (Ea+b): 9
 pgfmathparse + index (Ea+c): 9
 pgfmathparse + array (Ea+d): 9
input (Eb): {9}{8}{7}
 foreach (Eb+a): {9}{8}{7}
 pgfmatharray (Eb+b): 7                           % 1. Why last?
 pgfmathparse + index (Eb+c): 7                   % 1. Why last?
 pgfmathparse + array (Eb+d): 7                   % 1. Why last?
input (Ec): {{9}{8}{7}}{6}
 foreach (Ec+a): {{9}{8}{7}}{6}
 pgfmatharray (Ec+b): 6                           % 1. Why last?
 pgfmathparse + index (Ec+c): 6                   % 1. Why last?
 pgfmathparse + array (Ec+d): 6                   % 1. Why last?
input (F): 9, 8, 7
 foreach (F+a): 9
 pgfmatharray (F+b): 9
 pgfmathparse + index (F+c): Error
 pgfmathparse + array (F+d): Error
input (Fa): 9
 foreach (Fa+a): 9
 pgfmatharray (Fa+b): 9
 pgfmathparse + index (Fa+c): 9
 pgfmathparse + array (Fa+d): 9
input (Fb): 9
 foreach (Fb+a): 9
 pgfmatharray (Fb+b): 9
 pgfmathparse + index (Fb+c): 9
 pgfmathparse + array (Fb+d): 9

Does there exist a badge for the longest post without comments?

1 Answer 1

4

No but there must be a badge for the most intertwined question though. Why you ever need a recursion for this I don't know :)


If I remember correctly, you are, knowingly or not, hacking into an intermediate step of the syntax for multidimensional arrays, example,

\pgfmathparse{\A[0][0]}

renders the \A[0], {9}{8}{7} before it moves to the next bracket. But please note that, the second brackets should be immediate.

If the array is defined to have multiple dimensions, then the array access operators can be immediately repeated.

Now you can argue this is not nice or buggy and I agree but that's a choice. So if you don't comply with it, the results can obviously be inconsistent. This rules out the nested use of the two other than the index notation.

And there is some stack operation involved. That's the part I didn't check it precisely, but there is some stack emulation with the parser of pgfmath. If you push the resulting token and pop the top one, it is going to be 7, though 8 and 9 would still be there theoretically. I don't have time to decode it but you can check it at pgfmathparser.code.tex around line 750.

I think we can group your cases to

"Why Last"s

That's most probably the push-pop stack operation of an invalid syntax.

"Why differ from"'s

Actually all this long text can be summarized as why the following two lines are different

\pgfmatharray{{9}{8}{7}}{0}\pgfmathresult\\           % Ad + b
\pgfmathparse{array({9}{8}{7},0)}\pgfmathresult\\     % Ad + d

It is the first one that should throw an error but doesn't. The reason for that is inline parsing has an additional operand parsing (that strips braces too) and it correctly sees that there is no comma separated array there. The other one is tricked because the parsing is bypassed. Another evidence is that

\pgfmathdim{{9}{8}{7}}

gives 1. So it is not a triplet.


more later...

2
  • "This rules out the nested use of the two other than the index notation" - that is nice one to know. The "Why Last" case disappears if I use xdef in b,c,d but other cases stay essentially the same.
    – karu
    Jul 16, 2014 at 11:11
  • In pgfmathparser.code.text the array is stripped from extraneous braces and converted to a sequence of macro arguments. In short, the result of one bgfmath* array operation is not designed to be fed into another. Have I got it right?
    – karu
    Jul 16, 2014 at 12:38

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.