0

I got the following errors when compiling the following MWE. How to fix it?

Paragraph ended before \verbatim@ was complete. ...

First MWE

\documentclass{article}
\usepackage{sagetex}


\newcount\i
\i=10


\begin{document}
\loop
%==================== BEGIN ===========================
\begin{sageblock}
    f(x) = exp(x) * sin(\i*x)
\end{sageblock}

The second derivative of $f$ is
\[
  \frac{\mathrm{d}^{2}}{\mathrm{d}x^{2}} \sage{f(x)} =
  \sage{diff(f, x, 2)(x)}.
\]

Here's a plot of $f$ from $-1$ to $1$:

\begin{center}
    \sageplot{plot(f, -1, 1)}
\end{center}
%=================== END ==============================
\advance \i -1
\ifnum \i>8
\repeat
\end{document}

Second MWE

% secondMWE.tex
\documentclass[preview,border=12pt,12pt]{standalone}
\usepackage{sagetex}
\newcount\i
\i=10

\begin{document}
\loop
    \begin{preview}
        \sageplot[width=0.75\linewidth]{plot(sin(\the\i*x),x,0,2*pi)}
    \end{preview}
    \advance \i -1
    \ifnum \i>7
\repeat
\end{document}

enter image description here

The expected output shows 3 sine plots with different frequencies.

Edit

Having read the existing answers, I come with the following idea which might be not difficult for TeX experts to implement. For the sake of simplicity, let me use the second MWE (secondMWE.tex).

The building process takes 4 steps instead of 3 steps.

  • First, do pdflatex secondMWE, a new complete TeX file, for example secondMWE_complete.tex, is generated behind the scene. It contains something like

    % secondMWE_complete.tex
    \documentclass[preview,border=12pt,12pt]{standalone}
    \usepackage{sagetex}
    \begin{document}
    \begin{preview}
       \sageplot[width=0.75\linewidth]{plot(sin(10*x),x,0,2*pi)}
    \end{preview}
    \begin{preview}
       \sageplot[width=0.75\linewidth]{plot(sin(9*x),x,0,2*pi)}
    \end{preview}
    \begin{preview}
       \sageplot[width=0.75\linewidth]{plot(sin(8*x),x,0,2*pi)}
    \end{preview}
    \end{document}
    
    • Second, do pdflatex secondMWE_complete
    • Third, do sage secondMWE_complete.sagetex.sage
    • Fourth, do pdflatex secondMWE_complete.tex again
Display Name
  • 46,933

2 Answers2

3

I never bothered to learn the harder-than-Python-and-less-useful-than-Python-syntax so I'm not 100% sure but I don't think it's possible to mix with sagetex the way you are attempting without getting into expl3 like was done in frougon's answer here, and that's way outside of what I know or want to learn. The problem you're up against is that compilation of LaTeX is a 3 stage process. First, LaTeX runs and essentially some space is set aside for where Sage calculations are needed. Second, Sage runs and the boxes are filled in. Third stage is that LaTeX is run on LaTeX plus Sage generated from the first two steps. That's creates the final document. When you use \loop it seems like you're assuming that LaTeX and Sage are working together so that i is getting passed to Sage and Sage keeps changing the functions based on a changing i. This is not following the 3 step compilation process so I see no way to make that work.

I would attempt to work completely in Python as follows:

\documentclass{article}
\usepackage{sagetex}
\begin{document}
%==================== BEGIN ===========================
\begin{sagesilent}
output = r""
for i in range(10,7,-1):
    f(x) = exp(x)*sin(i*x)
    output += r"The function is $f(x)= %s$."%(latex(f(x)))
    output += r" The second derivative of $f(x)$ is \[ \frac{\mathrm{d}^{2}}{\mathrm{d}x^{2}} %s = %s.\]"%(latex(f(x)),latex(diff(f, x, 2)(x)))
    output += r"Here's a plot of $f$ from $-1$ to $1$:\\"
    output += r"\begin{center}"
    output += r"\sageplot[width=8cm]{plot(%s,-1,1)}"%(f(x))
    output += r"\end{center}"
    output += r"\vspace{.15in}"
\end{sagesilent}
%=================== END ==============================
\sagestr{output}
\end{document}

The output in Cocalc is: enter image description here

Note: 1. r"" is for raw strings which allows us to put in "bad" things like \ without problems. The string is then built up as the loop runs. It's finally inserted completely with \sagestr. That means the first pass through the document is empty. The second pass through the string is created. The third pass through has the entire code which can go through LaTeX without a problem. 2. The use of latex(f(x)) cleans up the presentation; for example, the multiplication symbols are gone. Try removing any latex( ) from the code and you'll see the difference. 3. Finally, we can control the width of our plot to make the document look nicer; this was done with the option [width=8cm] in \sageplot. It takes a little bit of time to adjust to working with strings but it solves most of the issues where sagetex is giving you problems.

DJP
  • 12,451
  • I sometimes have problems with running code when I shouldn't. I delete all files but the .tex file and compile again. It seems like this forces the creation of .sage and .sout files which solves the problem. It's almost as if it uses the old files without recompiling. – DJP May 11 '20 at 15:03
  • Thank you again. – Display Name May 11 '20 at 16:02
2

As DJP explained, this is really difficult to do the way you want because sageblock uses some kind of verbatim, and the latter doesn't mix well at all with LaTeX code (by definition).

Just to show what can be done when one understands a bit the underlying mechanisms behind verbatim, though, here is a hacky way to make your first example work with your \loop construct. It's a mix of LaTeX2e style and expl3 style because I started it in LaTeX2e but decided to use a convenient expl3 trick in the end from an answer by Bruno Le Floch.

\documentclass{article}
\usepackage{sagetex}
\usepackage{xparse}

\ExplSyntaxOn
\makeatletter

\NewDocumentEnvironment { mysageblock } { m +b }
  {
    \def\my@contents##1{#2}%
    \edef\my@tmpvalue{\number\csname #1\endcsname}%
    \edef\my@contents{%
      \unexpanded\expandafter\expandafter\expandafter{%
        \expandafter\my@contents\expandafter{\my@tmpvalue}}}%
    % Trick from <https://tex.stackexchange.com/a/25753/73317>
    \exp_args:Nx \scantokens
      {
        \token_to_str:N \begin{sageblock}
        \exp_not:V \my@contents
        \token_to_str:N \end{sageblock}
      }
  }
  { }

\makeatother
\ExplSyntaxOff

\newcount\i
\i=10

\begin{document}

\loop
%==================== BEGIN ===========================
\begin{mysageblock}{i}
    f(x) = exp(x) * sin(##1*x)
\end{mysageblock}

The second derivative of $f$ is
\[
  \frac{\mathrm{d}^{2}}{\mathrm{d}x^{2}} \sage{f(x)} =
  \sage{diff(f, x, 2)(x)}.
\]

Here's a plot of $f$ from $-1$ to $1$:

\begin{center}
    \sageplot{plot(f, -1, 1)}
\end{center}
%=================== END ==============================
\advance \i -1
\ifnum \i>8
\repeat

\end{document}

enter image description here

For the second example, since sageplot doesn't use verbatim, there is no such complication. Your code works as is for me. You can make the frequency changes more visible to convince yourself:

\documentclass[preview,border=12pt,12pt]{standalone}
\usepackage{sagetex}
\newcount\i
\i=3

\begin{document}
\loop
    \begin{preview}
        \sageplot[width=0.75\linewidth]{plot(sin(\the\i*x),x,0,2*pi)}
    \end{preview}
    \advance \i -1
    \ifnum \i>0
\repeat
\end{document}

enter image description here

Note: maybe you should avoid using single-letter variable names like \i, which normally is for typesetting a dotless i.

frougon
  • 24,283
  • 1
  • 32
  • 55
  • You're welcome. I've removed a harmless but unneeded group. – frougon May 11 '20 at 11:10
  • 1
    AFAICT, your second example works as is. No such complication appears to be needed (see my update). – frougon May 11 '20 at 11:54
  • 1
    My pleasure. I added a missing pair of braces in the first piece of code that was causing the \makeatother to be silently eaten (it's easy to forget, because when using a b argument type with \NewDocumentEnvironment, the end part of the definition isn't useful; moreover, \NewEnviron from the environ package has no end part for this very reason). – frougon May 11 '20 at 21:36