TransWikia.com

Can tikz plot a recurrence relation using `foreach` and no global definitions?

TeX - LaTeX Asked on July 11, 2021

I would like to know you to plot a recurrence relation using foreach, which requires updating a variable inside the loop. To make this concrete without copying over a bunch of code, please consider this existing example, which uses copy/paste rather than foreach. Can this example be changed to update a variable in a foreach loop, without introducing a definition at document scope. If not, why not?

As another concrete illustration, this answer uses foreach but introduces a global definition (see the line with newcommand{x}{.1}). I don’t want to introduce any definitions at document scope. Surely this is some way to use the TikZ registers instead? If not, can you say why not?

Abstractly, the problem involves an initial condition, a sequence produced by function iteration, and the plotting of coordinates produced from each adjacent pair in the sequence. For example, given x0 and then x1=f(x0), plot a point at (x0,x1). Then with x2=f(x1), plot a point at (x1,x2). And so on, as many times as requested.

2 Answers

You can do floating point computations (with greater accuracy than with TikZ) using expl3.

documentclass{article}
usepackage[usenames,dvipsnames]{xcolor}
usepackage{tikz,fullpage}
usetikzlibrary{arrows}
usepackage{xfp}

ExplSyntaxOn
NewDocumentCommand{xforeach}{mmm}
 {
  int_step_inline:nnn { #1 } { #2 } { #3 }
 }
NewDocumentCommand{setfpvar}{mm}
 {
  fp_zero_new:c { l__alan_fpvar_#1_fp }
  fp_set:cn { l__alan_fpvar_#1_fp } { #2 }
 }
NewExpandableDocumentCommand{usefpvar}{m}
 {
  fp_use:c { l__alan_fpvar_#1_fp }
 }
ExplSyntaxOff

begin{document}

begin{tikzpicture}[scale=10,>=latex']  
  draw[color=blue,samples at={0,0.01,...,1.07}] plot (x,{cos(x r)});  
  draw[color=green](0,0)--(1,1);
  draw[->](0,0)--(0,1) node[above]{$y$};
  draw[->](0,0)--(1,0) node[right]{$x$};
  % initialize “x”
  setfpvar{x}{.2}
  % the main loop
  xforeach{1}{7}{%
    setfpvar{y}{cos(usefpvar{x})}
    draw[color=magenta](usefpvar{x},usefpvar{x})--
                        (usefpvar{x},usefpvar{y})--
                        (usefpvar{y},usefpvar{y});
    draw[color=orange,dotted,line width=0.8pt]
      (usefpvar{x},usefpvar{x})--(usefpvar{x},0) node[below=8pt]{$u_{#1}$};
    draw[color=blue,dotted,line width=0.8pt]%
      (usefpvar{x},usefpvar{y})--(0,usefpvar{y}) node[left=8pt] {$u_{inteval{#1+1}}$};
    % in the next cycle “x” will take the current value of “y”
    setfpvar{x}{usefpvar{y}}
  }
end{tikzpicture}

end{document} 

No global declaration needed, because the loop cycles don't need to be run in groups. The loop variable is denoted #1. The arguments to xforeach are the starting point, the end point and the code to run.

Actually the variables' names are declared globally, but that's not a problem, because they live in their own namespace.

enter image description here

Answered by egreg on July 11, 2021

The following replicates the cobweb diagram in this answer as does the code of @egreg (above). I consider my proposed answer simpler and closer to my question, unless I've missed something, because it only uses the fp package. However, it does exploit the remember option of foreach in a way that I cannot deduce from the documentation, so hopefully I'm using an intentional feature rather than an implementation detail. (Can anyone confirm?) The crucial trick is to redefine the loop variable at the end of the loop, so that the new definition becomes the "remembered" value. See the last line in the loop body.

begin{tikzpicture}[scale=10,>=latex']  
  draw[color=blue,samples at={0,0.01,...,1.07}] plot (x,{cos(x r)});  
  draw[color=green!50](0,0)--(1,1);
  draw[<->](0,1) node[above]{$y$} |- (1,0) node[right]{$x$};
  foreach i [remember=i as x (initially 0.2)] in {1,...,7}{%
    FPevaly{cos x}
    draw[color=magenta](x,x)--(x,y)--(y,y);
    draw[color=orange,dotted,line width=0.8pt]%
            (x,x)--(x,0) node[below=8pt]{$u_i$};
    draw[color=blue,dotted,line width=0.8pt] (x,y)--(0,y) node[left=8pt]
         {$u_{pgfmathparse{int(i+1)}pgfmathresult}$};
    FPevali{y}
  }
end{tikzpicture}

Btw, one thing I discovered while exploring this is that math parsing must be close to pgfmathresult, because this also holds the results of other computations being done by TikZ.

Answered by Alan on July 11, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP