[Tex/LaTex] Programming simple functions using TikZ arithmetic

programmingtikz-pgf

How do you do program simple functions using the TikZ arithmetic engine?

I love the idea of using TikZ in order to “program” my pictures, being able to write code once and reuse, get precise coordinates and intersections, being able to change just one number and get the whole picture to automagically update whatever depended on that number. That is amazing.

However, maybe because I am extremely used to more traditional programming languages, and I think in a more procedural (rather than a “macro expansiony” way), I tend to get quickly frustrated as soon as I need even basic stuff such as an if or a while loop. I got hold of the TikZ \foreach command which works wonders; but why aren't similar commands for if and while defined? (Or there are, but I'm missing them?)

You will probably point me to other packages that do define such commands, but I find it non-trivial (and headache producing) to write the correct code to switch between TikZ arithmetic expressions and strings, tokens, (un)expanded macros or whatever the hell these packages do actually compare in their conditionals.

This is what I think should be essential to have:

  • \ifmath{expr}{true}{false} — evaluates expr and if true (e.g. not 0), continues executing the code in the true part; otherwise it continues with the false part.
  • \whilemath{expr}{code} — repeatedly executes code while the expr yields a true value.

I had sort of written versions of these, but I would like to see what you can come up with.

Now, that was the basic, but what I would really really be able to do, is to easily define new functions that can be also used within an expr. For example, suppose that I want to write a wee tiny function that simply takes two numbers and returns their gcd. This is some simple pseudocode of what I want to write:

function gcd(a, b) {
  while (b) {
    t = b;
    b = a mod b;
    a = t;
  }
  return a;
}

How would I go about to write such kind of code in TikZ to compute gcd, and furthermore, being able to write things like 4 + gcd(15,6) as further TikZ expressions? Please note, I'm not asking how to write some token-expansion magic to compute the gcd of two numbers; I'm asking whether if it is possible to actually write simple functions such like this one (using plain if's, while's and assignments).

And now that I'm in the mood of wishing for everything, how do you deal with variables? In TikZ examples I've seen its common to simply store values inside macros, and TikZ expressions seem to be pretty happy working with those. However, I also had to write my own command to evaluate a TikZ expr and store the result in a macro of my choosing (\pgfmathsetmacro didn't work as expected, for example \pgfmathsetmacro{\a}{int(0)}\a produces 0.0 rather than 0).

Furthermore, by using just plain macro names, like \v, I worry all the time that I might accidentally redefine some important pre-existing macro; but I don't want to call all my variables \mya, \myb, \myc. Sometimes I feel temped to change the cat code of : so that :a, :b, :c become macro names… but experience tells me that every time one messes with cat-codes everything breaks.

Best Answer

Thanks all for the comments, and Altermundus for your alternative answer. However, I really think that for users that would like to enjoy a higher level of abstraction (as opposed to low-level macro hackery) a much better interface for defining such simple functions could be implemented. We don't really have to go down to low-level TeX coding.

For the moment I'll forget about the issue with variable namespaces, but with your help and some tinkering with macros, reading the TikZ sources and lots of trial and error, I was already able to provide something much closer to what I'm looking for.

\documentclass{article}
\usepackage{tikz}
\usepackage{etoolbox} % for \ifdefstring

\makeatletter
\newcommand{\setmath}[2]{\pgfmathparse{#2}\edef#1{\pgfmathresult}}
\newcommand{\domath}[1]{\pgfmathparse{#1}\pgfmathresult}
\newcommand{\ifmath}[1]{\pgfmathparse{equal(#1,0)}\ifdefstring\pgfmathresult{0}}
\newcommand{\whilemath}[2]{\ifmath{#1}{#2\whilemath{#1}{#2}}{}}
\newcommand{\returnmath}[1]{\pgfmathparse{#1}\pgfmath@smuggleone\pgfmathresult}
\newcommand{\newmathfunction}[3]{\pgfmathdeclarefunction{#1}{#2}{\begingroup#3\endgroup}}
\makeatother

\newmathfunction{mygcd}{2}{%
  \setmath\a{#1}%
  \setmath\b{#2}%
  \whilemath{\b}{%
    \setmath\t{\b}%
    \setmath\b{mod(\a,\b)}%
    \setmath\a{\t}%
  }%
  \returnmath{int(\a)}%
}

\begin{document}
\setmath\a{15}
\setmath\b{6}
gcd(\a,\b) = \domath{mygcd(\a,\b)}.
\end{document}

Now you can actually read the code to compute the gcd, which was pretty much translated line by line from my original pseudocode. I know that this might be grossly inefficient but, who cares, I just want to compute the coordinates for a few points, I'm not trying to do sophisticated physics simulations here.

I would greatly appreciate any comments and suggestions to the programming interface that I propose; in particular using etoolbox just to compare against the token 0 seems like an overkill, but etoolbox was something that I could also easily learn.