4

Constraints

  • I want to use the same name for inner and outer loop.
  • I am reluctant to append @ and make use of \makeatletter...\makeatother.

Is there any name-spacing construct to use?

MWE

The following code will not produce the correct result as the two \i clash.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\SpecialCoor
\def\Triangle(#1)#2{{\rput(#1){\multido{\i=0+1}{#2}{\multips(\i,0)(!.5 3 sqrt 2 div){\numexpr#2-\i\relax}{\pspolygon(1,0)(!.5 3 sqrt 2 div)}}}}}


\usepackage[nomessages]{fp}
\FPset\N{4}
\FPeval\Width{(N-1)*(N+2)/2+N}
\FPeval\Height{round(root(2,3)*N/2:6)}

\begin{document}
\begin{pspicture}(\Width,\Height)
    \multido{\i=1+1}{\N}{\Triangle(!\i\space 1 sub \i\space 2 add mul 2 div 0){\i}}
\end{pspicture}
\end{document}

The correct output is as follows.

enter image description here

  • You know you can use \iA and \iB... – Werner Nov 20 '13 at 0:29
  • @Werner: \A!=\iB that disobeys the given constraint. I know this. – kiss my armpit Nov 20 '13 at 0:31
  • Strange request though, since using two different counters (\iA and \iB, say) is far easier than completely redefining the inner-workings of \multido to keep track of the nesting, don't you think? – Werner Nov 20 '13 at 0:34
  • 1
    @Werner: This question concentrates more on the theoretical aspect than the current practical use. I want to avoid remembering the already used variables when using nested multido. I also don't want to clutter the code with @ that consumes more keystrokes. :-) – kiss my armpit Nov 20 '13 at 0:39
  • 3
    Would you use the same index for a summation inside a summation? I bet not. Different variables should have different symbols. – egreg Nov 20 '13 at 7:59
2

Avoiding name clashes is achieved by using unique names for each identifier in the loop. However, in this case, passing arguments directly on to the inner \multido means they're not expanded until used, at which time they also need to be set. "Pre-expansion" (declaring macros that contain an expanded version of the arguments) helps avoid this:

enter image description here

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}% http://ctan.org/pkg/multido
\SpecialCoor
\def\Triangle(#1)#2{%
  \edef\firstarg{#1}\edef\secondarg{#2}% pre-expand #1 and #2
  \rput(\firstarg){\multido{\i=0+1}{\secondarg}{\multips(\i,0)(!.5 3 sqrt 2 div){\numexpr\secondarg-\i\relax}{\pspolygon(1,0)(!.5 3 sqrt 2 div)}}}}

\usepackage[nomessages]{fp}% http://ctan.org/pkg/fp
\FPset\N{4}
\FPeval\Width{(N-1)*(N+2)/2+N}
\FPeval\Height{round(root(2,3)*N/2:6)}

\begin{document}
\begin{pspicture}(\Width,\Height)
  \multido{\i=1+1}{\N}{\Triangle(!\i\space 1 sub \i\space 2 add mul 2 div 0){\i}}
\end{pspicture}
\end{document}
2

You can use the \xintFor loop from package xinttools. One does not have to worry then about the name used for the iterated variable.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{xinttools}
\SpecialCoor

% inside a macro, the # for an \xintFor must be doubled
%
\def\Triangle(#1)#2{{\rput(#1)%
                    {\xintFor* ##1 in {\xintSeq {0}{#2-1}}\do
                     {\multips(##1,0)(!.5 3 sqrt 2 div)%
                         {\numexpr#2-##1\relax}%
                         {\pspolygon(1,0)(!.5 3 sqrt 2 div)}}}}}


\usepackage[nomessages]{fp}
\FPset\N{4}
\FPeval\Width{(N-1)*(N+2)/2+N}
\FPeval\Height{round(root(2,3)*N/2:6)}

\begin{document}
\begin{pspicture}(\Width,\Height)
    \xintFor* #1 in {\xintSeq{1}{\N}} \do
    {\Triangle(!#1 1 sub #1 2 add mul 2 div 0){#1}}
\end{pspicture}
\end{document}

triangles

One can furthermore compute in real time \Width and \Height with xintexpr.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{xintexpr}% loads xinttools automatically
\SpecialCoor

% inside a macro, the # for an \xintFor must be doubled
%
\def\Triangle(#1)#2{{\rput(#1)%
                    {\xintFor* ##1 in {\xintSeq {0}{#2-1}}\do
                     {\multips(##1,0)(!.5 3 sqrt 2 div)%
                         {\numexpr#2-##1\relax}%
                         {\pspolygon(1,0)(!.5 3 sqrt 2 div)}}}}}

\providecommand\firstofone [1]{#1}

\begin{document}
\def\N {4}
%
% we use \xintthenumexpr for the width as it guarantees 
% integer format on output
%
% we use \firstofone to hide parentheses and other things from pspicture
% 
\begin{pspicture}(\firstofone{\xintthenumexpr (\N-1)*(\N+2)/2+\N\relax},%
                  \firstofone{\xinttheexpr round(sqrt(3)*\N/2,6)\relax})
    \xintFor* #1 in {\xintSeq{1}{\N}} \do
    {\Triangle(!#1 1 sub #1 2 add mul 2 div 0){#1}}
\end{pspicture}
\end{document}

A \firstofone trick had to be used to hide the parentheses. For some reason, putting the whole xintexpr-essions inside braces does not work with pspicture. Braces inside \xintexpr .. \relax have special meaning, one could do \xintthenumexpr{\xinttheexpr..\relax}\relax for the width for example but this is admittedly complicated.

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.