diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/sagetex |
Initial commit
Diffstat (limited to 'macros/latex/contrib/sagetex')
-rw-r--r-- | macros/latex/contrib/sagetex/CONTRIBUTORS | 21 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/PKG-INFO | 12 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/README | 53 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/example.pdf | bin | 0 -> 285125 bytes | |||
-rw-r--r-- | macros/latex/contrib/sagetex/example.tex | 644 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/py-and-sty.dtx | 1575 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/remote-sagetex.dtx | 438 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/sagetex.dtx | 1225 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/sagetex.ins | 124 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/sagetex.pdf | bin | 0 -> 499983 bytes | |||
-rw-r--r-- | macros/latex/contrib/sagetex/scripts.dtx | 520 | ||||
-rw-r--r-- | macros/latex/contrib/sagetex/setup.py | 32 |
12 files changed, 4644 insertions, 0 deletions
diff --git a/macros/latex/contrib/sagetex/CONTRIBUTORS b/macros/latex/contrib/sagetex/CONTRIBUTORS new file mode 100644 index 0000000000..bd489e1dc9 --- /dev/null +++ b/macros/latex/contrib/sagetex/CONTRIBUTORS @@ -0,0 +1,21 @@ +Listed below, in no particular order, are people that have contributed +to SageTeX -- code, documentation, suggestions, or anything else. + +If you have contributed to SageTeX and aren't listed below, please +contact the maintainers and we'll add you to the list. + +Gonzalo Tornaria +Joe Wetherell +Harald Schilly +Dan Drake +Jason Grout +Rob Beezer +Nicolas Thiéry +Volker Braun +Maxim Cournoyer +Jan Groenewald +Dima Pasechnik +Paul Masson +Frédéric Chapoton +Karl-Dieter Crisman +Jérôme Benoit diff --git a/macros/latex/contrib/sagetex/PKG-INFO b/macros/latex/contrib/sagetex/PKG-INFO new file mode 100644 index 0000000000..e3840db7b3 --- /dev/null +++ b/macros/latex/contrib/sagetex/PKG-INFO @@ -0,0 +1,12 @@ +Metadata-Version: 1.0 +Name: sagetex +Version: 3.2 +Summary: Embed Sage code and plots into LaTeX +Home-page: https://github.com/sagemath/sagetex +Author: SageMath developers +Author-email: sage-devel@googlegroups.com +License: GPLv2+ +Description: The SageTeX package allows you to embed code, + results of computations, and plots from the Sage mathematics + software suite (http://sagemath.org) into LaTeX documents. +Platform: UNKNOWN diff --git a/macros/latex/contrib/sagetex/README b/macros/latex/contrib/sagetex/README new file mode 100644 index 0000000000..fb35a8b4e8 --- /dev/null +++ b/macros/latex/contrib/sagetex/README @@ -0,0 +1,53 @@ +This is the SageTeX package. It allows you to embed code, results of +computations, and plots from the Sage mathematics software suite +(http://sagemath.org) into LaTeX documents. +==================================================================== + +SageTeX is included with Sage, so to use it, you only need to make the +file sagetex.sty known to TeX; that file will be in +SAGE_ROOT/local/share/texmf/tex/latex/sagetex, along with +documentation and examples. See the Sage tutorial at +http://doc.sagemath.org/html/en/tutorial/sagetex.html +for a quick usage introduction, and for complete installation +instructions later on the same page at +http://doc.sagemath.org/html/en/tutorial/sagetex.html#sec-sagetex-install + +The complete documentation is in sagetex.pdf, in +the SAGE_ROOT/... directory mentioned above. + +If you want to extract any of SageTeX's files from the .dtx sources, you +can do + + 0. Run `latex sagetex.ins' + +To regenerate the documentation, do + + 1. Run `latex sagetex.dtx' + 2. Run `sage sagetex.sage' + 3. Run the indexing commands that the .ins file told you about. + 4. Run `latex sagetex.dtx' again. + +You can skip step 3 if you don't care about the index. You will need the +pgf and tikz packages installed to typeset the figures. + +The file example.tex has, as you likely guessed, a bunch of examples +showing you how this package works. You can compile it using a another +latex-sage-latex cycle as in steps 1-2-4 above. Note that example.tex +includes some PNG graphics which latex cannot use; to see those, use +pdflatex instead of regular latex or enable the imagemagick option. (See +the documentation.) + +To use the SageTeX package with your own documents, see the +"Installation" section of the documentation. + +This work builds on a lot of work by others; see the CONTRIBUTORS file +and the "Credits" section of the documentation for credits. The source +code may be modified and distributed under the terms of the GPL, version +2 or later; the documentation may be modified and distributed under a +Creative Commons Attribution - Share Alike 3.0 License. See the "Copying +and licenses" section of the documentation. + +Please let me know if you find any bugs or have any ideas for +improvement! + +- Dan Drake <dr.dan.drake at gmail> diff --git a/macros/latex/contrib/sagetex/example.pdf b/macros/latex/contrib/sagetex/example.pdf Binary files differnew file mode 100644 index 0000000000..4894f323b6 --- /dev/null +++ b/macros/latex/contrib/sagetex/example.pdf diff --git a/macros/latex/contrib/sagetex/example.tex b/macros/latex/contrib/sagetex/example.tex new file mode 100644 index 0000000000..2c04afdd02 --- /dev/null +++ b/macros/latex/contrib/sagetex/example.tex @@ -0,0 +1,644 @@ +% General example LaTeX file for including Sage calculations and plots +% Build with: +% +% (pdf)latex example.tex; sage example.sagetex.sage; pdflatex example.tex +% +% Please read README and the documentation of the SageTeX package for +% more information! +% + +\documentclass{article} +\title{Examples of embedding Sage in \LaTeX{} with \textsf{Sage\TeX}} +\author{Dan Drake and others} +\usepackage{hyperref} +% If you want to see the examples in the section "Plotting +% (combinatorial) graphs with TikZ" remove the \begin{comment} +% and \end{comment} in that section and uncomment the following line. +%\usepackage{tkz-berge} + + +\usepackage{sagetex} +% +% If you want SageTeX to use Imagemagick's `convert' utility to make eps +% files from png files when generating a dvi file, add the "imagemagick" +% option above: +% +% \usepackage[imagemagick]{sagetex} + +\setlength{\sagetexindent}{10ex} + +\begin{document} +\maketitle + +\section{Inline Sage, code blocks} + +This is an example $2+2=\sage{2+2}$. If you raise the current year mod +$100$ (which equals $\sage{mod(\the\year, 100)}$) to the power of the +current day ($\the\day$), you get $\sage{Integer(mod(\the\year, +100))^\the\day}$. Also, $\the\year$ modulo $42$ is $\sage{\the\year +\percent 42}$. + +Code block which uses a variable \texttt{s} to store the solutions: +\begin{sageblock} + 1+1 + var('a,b,c') + eqn = [a+b*c==1, b-a*c==0, a+b==5] + s = solve(eqn, a,b,c) +\end{sageblock} + +Solutions of $\mbox{eqn}=\sage{eqn}$: +\[ +\sage{s[0]} +\] +\[ +\sage{s[1]} +\] + +Now we evaluate the following block: +\begin{sageblock} +E = EllipticCurve("37a") +\end{sageblock} +You can't do assignment inside \verb|\sage| macros, since Sage doesn't +know how to typeset the output of such a thing. So you have to use a +code block. The elliptic curve $E$ given by $\sage{E}$ has discriminant +$\sage{E.discriminant()}$. + +You can do anything in a code block that you can do in Sage and/or +Python. Here we save an elliptic curve into a file. +\begin{sageblock} +try: + E = load('E2') +except IOError: + E = EllipticCurve([1,2,3,4,5]) + E.anlist(100000) + E.save('E2') +\end{sageblock} + +The 9999th Fourier coefficient of $\sage{E}$ is +$\sage{E.anlist(100000)[9999]}$. + +The following code block doesn't appear in the typeset file\dots +\begin{sagesilent} + e = 2 + e = 3*e + 1 +\end{sagesilent} +but we can refer to whatever we did in that code block: $e=\sage{e}$. + +\begin{sageblock} + var('x') + f(x) = log(sin(x)/x) +\end{sageblock} +The Taylor Series of $f$ begins: $\sage{ f.taylor(x, 0, 10) }$. + +\section{Plotting} + +Here's a very large plot of the elliptic curve $E$. + +\sageplot{E.plot(-3,3)} + +\begin{sagesilent} + # the var line is unecessary unless you've defined x to be something + # other than a symbolic variable + var('x') + f(x) = -x^3+3*x^2+7*x-4 +\end{sagesilent} + +You can use variables to hold plot objects and do stuff with them. +\begin{sageblock} + p = plot(f, x, -5, 5) +\end{sageblock} + +Here's a small plot of $f$ from $-5$ to $5$, which I've centered: + +\begin{center} \sageplot[scale=.2]{p} \end{center} + +On second thought, use a size of $3/4$ the \verb|\textwidth| and don't +use axes: + +\sageplot[width=.75\textwidth]{p, axes=False} + +Remember, you're using Sage, and can therefore call upon any of the +software packages Sage is built out of. +\begin{sageblock} +f = maxima('sin(x)^2*exp(x)') +g = f.integrate('x') +\end{sageblock} +Plot $g(x)$, but don't typeset it. +\begin{sagesilent} + # g is a Maxima thingy, it needs to get converted into a Sage object + plot1 = plot(g.sage(),x,-1,2*pi) +\end{sagesilent} + +You can specify a file format and options for \verb|includegraphics|. +The default is for EPS and PDF files, which are the best choice in +almost all situations. (Although see the section on 3D plotting.) + +\sageplot[angle=45, width=.5\textwidth][png]{plot1} + +If you use regular \verb|latex| to make a DVI file, you'll see a box, +because DVI files can't include PNG files. If you use \verb|pdflatex| +that will work. See the documentation for details. + +When using \verb|\sageplot|, you can pass in just about anything that +Sage can call \verb|.save()| on to produce a graphics file: + +\begin{center} +\sageplot[width=.7\textwidth]{plot1 + plot(f.sage(),x,-1,2*pi,rgbcolor=hue(0.4)), figsize=[5,3]} +\end{center} + +To fiddle with aspect ratio, first save the plot object: + +\begin{sageblock} + p = plot(x, 0, 1) + circle((0,0), 1) + p.set_aspect_ratio(1) +\end{sageblock} + +Now plot it and see the circular circle and nice 45 degree angle: + +\sageplot[scale=.33]{p} + +Indentation and so on works fine. +\begin{sageblock} + s = 7 + s2 = 2^s + P.<x> = GF(2)[] + M = matrix(parent(x),s2) + for i in range(s2): + p = (1+x)^i + pc = p.coefficients(sparse=False) + a = pc.count(1) + for j in range(a): + idx = pc.index(1) + M[i,idx+j] = pc.pop(idx) + + matrixprogram = matrix_plot(M,cmap='Greys') +\end{sageblock} +And here's the picture: + +\sageplot[scale=.5]{matrixprogram} + +Reset \texttt{x} in Sage so that it's not a generator for the polynomial +ring: \sage{var('x')} + + +\subsection{Plotting (combinatorial) graphs with TikZ} +\label{sec:plotting-graphs-with} + +Sage now includes some nice support for plotting graphs using +\href{http://www.texample.net/tikz/}{TikZ}. Here, we mean things with +vertices and edges, not graphs of a function of one or two variables. + +The graphics in this section depends on the \texttt{tkz-berge} package, +which is generally only available in newer \TeX{} distributions (for +example, \TeX Live 2011 and newer). That package depends in turn on +TikZ 2.0, which is also only available in newer \TeX{} distributions. +Installing both of those is in some cases nontrivial, so this section is +disabled by default. + +If you have TikZ and \texttt{tkz-berge} and friends, remove the +\texttt{comment} environments below. + +\begin{comment} + +First define our graph: + +\begin{sageblock} + g = graphs.PetersenGraph() + g.set_latex_options(tkz_style='Art') +\end{sageblock} + +Now just do \verb|\sage{}| on it to plot it. You'll need to use the +\texttt{tkz-berge} package for this to work; that package in turn +depends on \texttt{tkz-graph} and TikZ. See +\href{http://altermundus.fr/pages/tkz.html}{\texttt{altermundus.fr/pages/tkz.html}}; +if you're using a recent version of \TeX Live, you can use its package +manager to install those packages, or get them from CTAN: +\href{http://www.ctan.org/pkg/tkz-berge}{\texttt{www.ctan.org/pkg/tkz-berge}}. +See +\href{http://doc.sagemath.org/html/en/reference/sage/graphs/graph_latex.html}{``\LaTeX{} + Options for Graphs''} in the Sage reference manual for more details. + +\begin{center} + \sage{g} +\end{center} + +The above command just outputs a \texttt{tikzpicture} environment, and +you can control that environment using anything supported by +TikZ---although the output of \verb|\sage{g}| explicitly hard-codes a +lot of things and cannot be flexibly controlled in its current form. + +\tikzstyle{every picture}=[rotate=45, scale=1/2] + +\begin{center} + \sage{g} +\end{center} + +\tikzstyle{every picture}=[] + +Here's some more graphs, plotted using the usual plot routines. + +\sageplot[scale=.5]{graphs.FlowerSnark().plot()} + +\begin{sageblock} +G4 = DiGraph({1:[2,2,3,5], 2:[3,4], 3:[4], 4:[5,7], 5:[6]},\ + multiedges=True) +G4plot = G4.plot(layout='circular') +\end{sageblock} + +\sageplot[scale=.5]{G4plot, axes=False} + +\end{comment} + +\subsection{3D plotting} + +3D plotting right now (Sage version 4.3.4) is problematic because +there's no convenient way to produce vector graphics. We can make PNGs, +though, so if you pass \verb|sageplot| a graphics object that cannot be +saved to EPS or PDF format, we will automatically save to a PNG file, +which can be used when typesetting a PDF file, but not when creating a +DVI file. However, you can specify the ``\texttt{imagemagick}'' option, +which will use the Imagemagick \texttt{convert} utility to make EPS +files. See the documentation for details. + +% FIXME: not sure this works with remote sagetex + +\begin{sagesilent} + x, y = var('x y') +\end{sagesilent} + +Here's a 3D plot whose format we do not specify; it will automatically +get saved as a PNG file and won't work when using \texttt{latex} to make +a DVI file. + +\sageplot[scale=.5]{plot3d(sin(pi*(x^2+y^2))/2,(x,-1,1),(y,-1,1))} + +Here's the (perhaps-not-so-) famous Sage cube graph in 3D. + +\begin{sageblock} + G = graphs.CubeGraph(5) +\end{sageblock} + +% need empty [] so sageplot knows you want png format, and aren't +% passing an option to includegraphics +\sageplot[][png]{G.plot3d()} + +\section{Pausing Sage\TeX} +\label{sec:pausing-sagetex} + +Sometimes you want to ``pause'' for a bit while writing your document if +you have embedded a long calculation or just want to concentrate on the +\LaTeX{} and ignore any Sage stuff. You can use the \verb|\sagetexpause| +and \verb|\sagetexunpause| macros to do that. + +\sagetexpause + +A calculation: $\sage{factor(2^325 + 1)}$ and a code environment that +simulates a time-consuming calculation. While paused, this will get +skipped over. +\begin{sageblock} + import time + time.sleep(15) +\end{sageblock} + +Graphics are also skipped: \sageplot{plot(2*sin(x^2) + x^2, (x, 0, 5))} + +\sagetexunpause + +\section{Make Sage write your \LaTeX{} for you} + +With \textsf{Sage\TeX}, you can not only have Sage do your math for you, +it can write parts of your \LaTeX{} document for you! For example, I +hate writing \texttt{tabular} environments; there's too many fiddly +little bits of punctuation and whatnot\ldots and what if you want to add +a column? It's a pain---or rather, it \emph{was} a pain. Just write a +Sage/Python function that outputs a string of \LaTeX{} code, and use +\verb|\sagestr|. Here's how to make Pascal's triangle. + +\begin{sageblock} +def pascals_triangle(n): + # start of the table + s = [r"\begin{tabular}{cc|" + "r" * (n+1) + "}"] + s.append(r" & & $k$: & \\") + # second row, with k values: + s.append(r" & ") + for k in [0..n]: + s.append("& {0} ".format(k)) + s.append(r"\\") + # the n = 0 row: + s.append(r"\hline" + "\n" + r"$n$: & 0 & 1 & \\") + # now the rest of the rows + for r in [1..n]: + s.append(" & {0} ".format(r)) + for k in [0..r]: + s.append("& {0} ".format(binomial(r, k))) + s.append(r"\\") + # add the last line and return + s.append(r"\end{tabular}") + return ''.join(s) + +# how big should the table be? +n = 8 +\end{sageblock} + +Okay, now here's the table. To change the size, edit \texttt{n} above. +If you have several tables, you can use this to get them all the same +size, while changing only one thing. + +\begin{center} + \sagestr{pascals_triangle(n)} +\end{center} + +\section{Include doctest-like examples in your document} + +Here are some examples of using the \texttt{sageexample} environment: +\begin{sageexample} + sage: 2+2 + 4 + sage: print('middle') + middle + sage: factor(x^2 + 2*x + 1) + (x + 1)^2 +\end{sageexample} +Note above that no output from the \texttt{print} statement appears. +That is because we have to use Python's \texttt{exec} to execute that +statement (and not \texttt{eval()}), and we can't get the output from +that. + +That said, if you want to see the plain-text output you put into your +\verb|.tex| file as well as the Sage-computed typeset output, renew the +\texttt{sageexampleincludetextoutput} command to True: +\begin{verbatim} + \renewcommand{\sageexampleincludetextoutput}{True} +\end{verbatim} +\renewcommand{\sageexampleincludetextoutput}{True} +This can be useful to check that the two outputs are consistent. Here's +the print statement with text output included: +\begin{sageexample} + sage: print('middle') + middle +\end{sageexample} +When typesetting your document, the validity of the outputs is not +checked. In fact, the provided outputs are completely ignored: +\renewcommand{\sageexampleincludetextoutput}{True} +\begin{sageexample} + sage: is_prime(57) + toothpaste +\end{sageexample} +\renewcommand{\sageexampleincludetextoutput}{False}% +Multiline statements with the ``\verb|....:|'' continuation marks are +supported, as are triple-quoted strings delimited by single quotes +(double quotes won't work): +\begin{sageexample} + sage: gcd([5656565656, + ....: 4747474747, + ....: 123456789]) + 1 + sage: mystr = '''my + ....: string + ....: has + ....: several + ....: lines.''' + sage: len(mystr) + 28 + sage: def f(a): + ....: '''This function is really quite nice, + ....: although perhaps not very useful.''' + ....: print("f called with a = {}".format(a)) + ....: y = integrate(SR(cyclotomic_polynomial(10)) + a, x) + ....: return y + 1 + sage: f(x) + f called with a = x + 1/5*x^5 - 1/4*x^4 + 1/3*x^3 + x + 1 +\end{sageexample} +Note that the ``$f$ called with\ldots'' stuff doesn't get typeset, since +when running Sage on \texttt{example.sagetex.sage}, that gets printed to the +terminal. + +Typesetting your document produces a file named +\texttt{example\_doctest.sage} containing all the doctest-like examples, +and you can have Sage check them for you with: +\begin{verbatim} + $ sage -t example_doctest.sage +\end{verbatim} +You should get a doctest failure from the ``toothpaste'' line above. The +line numbers from \texttt{sage -t} refer to the ``\verb|_doctest.sage|'' +file. + +Beware that \texttt{sage -t} does not really handle file names with +special characters in them, particularly dashes, dots, and spaces---this +ultimately comes from the way Python interprets \texttt{import} +statements. Also, running doctests on files outside the main Sage +library does not always work, so contact \texttt{sage-support} if you +run into troubles. + +Some more examples. This environment is implemented a little bit +differently than the other environments, so it's good to make sure that +definitions are preserved across multiple uses. This will correctly +define $a$, but not print its output because the statement is made up of +a sequence of expressions and we can't use Python's \texttt{eval()}; we +have to use \texttt{exec} and we can't capture the output from that. +\begin{sageexample} + sage: 1; 2; a=4; 3; a + 1 + 2 + 3 + 4 +\end{sageexample} +However, after that, Sage should remember that $a = \sage{a}$ and be +able to use that in future \texttt{sageexample} blocks: +\begin{sageexample} + sage: f(a) + f called with a = 4 + 1/5*x^5 - 1/4*x^4 + 1/3*x^3 - 1/2*x^2 + 5*x + 1 +\end{sageexample} + +\section{Plotting functions in Ti\emph{k}Z with Sage\TeX} + +(The code in this section should work with any reasonable version of +Ti\emph{k}Z, which means it should work with all but the most terribly +out-of-date \TeX{} installations---but to make sure we can accomodate +everyone, the code here is commented out. You can almost certainly +uncomment and run them. Make sure you do \verb|\usepackage{tikz}| in the +preamble.) + +\begin{comment} + +The wonderful graphics package TikZ has the ability to plot functions by +reading in a sequence of points from an external file---see chapter 18, +page 193 of the TikZ manual. This facility is designed around files +produced by Gnuplot, but the file format is so simple that it's very +easy to use Sage\TeX{} to generate them. First you need a function that +will evaluate functions and write the results into a file: + + +% set up plotting stuff +\begin{sageblock} + def gnuplot(x, y, tvals_, fn): + """ + Write out a gnuplot-style file of points x(t), y(t). + """ + tvals = list(tvals_) + lines = ['#This is a gnuplot-style file written by SageTeX.', + '#x: {0}'.format(x), + '#y: {0}'.format(y), + '#Curve 0, {0} points'.format(len(tvals)), + '#x y type'] + fmt = lambda _: _.n().str(no_sci=2) + for t in tvals: + try: + lines.append('{0} {1} i'.format(fmt(x(t)), fmt(y(t)))) + except ValueError, ZeroDivisonError: + pass + with open(fn, 'w') as f: + f.write('\n'.join(lines) + '\n') +\end{sageblock} + +There probably should be some more exceptions in that list, and the +above code doesn't check to make sure it's writing real values, but then +again, this is just a file of examples! + +Then you define callable functions x and y and pass them in, along with +a sequence of values and a file name. Here's a plot that I used on a +calculus exam: + +\begin{sageblock} + r(t) = 1 - 2*sin(3*t) + x(t) = r(t)*cos(t) + y(t) = r(t)*sin(t) + gnuplot(x, y, srange(0, 2*pi + .05, .05), 'example-tikz1.table') +\end{sageblock} + +(Usually you would do that in sagesilent environments, I guess.) + +Then you call TikZ with your plot. + +\begin{tikzpicture} + \draw[very thin,->] (-3.25,0) -- (3.25,0); + \draw[very thin,->] (0,-3.25) -- (0,3.25); + \draw[smooth] plot file {example-tikz1.table}; +\end{tikzpicture} + +For regular Cartesian plots, just pass in the identity function for x: + +\begin{sageblock} + x = lambda t: t + y(t) = t*sin(1/t) + gnuplot(x, y, [0.01, 0.02..(0.5)] + [0.55, 0.6..2], 'example-tikz2.table') +\end{sageblock} + +\begin{center} +\begin{tikzpicture}[scale=3] + \draw[very thin,->] (-0.25,0) -- (2,0); + \draw[very thin,->] (0,-1/3) -- (0,1); + \draw[smooth, red] plot file {example-tikz2.table}; +\end{tikzpicture} +\end{center} + +This style of plotting will become even more useful and powerful when +the new TikZ Data Visualization library is available---you will be able +to feed TikZ a bunch of data points, and it automatically make a very +nice plot for you, including axes, labels, and so on. + +\end{comment} + +\section{The \texttt{sagecommandline} environment} + +When writing a \TeX{} document about Sage, you may want to show some +examples of commands and their output. But naturally, you are lazy and +don't want to cut and paste the output into your document. ``Why should +I have to do anything? Why can't Sage and \TeX{} cooperate and do it for +me?'' you may cry. Well, they \emph{can} cooperate: + +\begin{sagecommandline} + sage: 1+1 + sage: is_prime(57) + sage: if is_prime(57): + ....: print('prime') + ....: else: + ....: print('composite') +\end{sagecommandline} + +Note that the output of the commands is not included in the source file, +but are included in the typeset output. + +Because of the way the environment is implemented, not everything is +exactly like using Sage in a terminal: the two commands below (and the +``if is prime'' one above, did you notice that?) would produce some +output, but don't here: + +\begin{sagecommandline} + sage: x = 2010; len(x.divisors()) + sage: print('Hola, mundo!') +\end{sagecommandline} + +The difference lies in the Python distinction between statements and +expressions; we can use \texttt{eval()} for an expression and get its +output, but we must use \texttt{exec} for a statement and can't get the +output, if any. + +One nice thing is that you can set labels by using an @ sign: + +\begin{sagecommandline} + sage: l = matrix([[1,0,0],[3/5,1,0],[-2/5,-2,1]]) + sage: d = diagonal_matrix([15, -1, 4]) #@\label{diagonal} + sage: u = matrix([[1,0,1/3],[0,1,2],[0,0,1]]) #@\label{anotherlabel} \# foo + sage: l*d*u # this is a comment +\end{sagecommandline} + +And then refer to that label: it was on line \ref{diagonal}, which is on +page \pageref{diagonal}. Note that the other text after the hash mark on +that line does not get typeset as a comment, and that you cannot have +any space between the hash mark and the~@. You will also need to typeset +your document \emph{twice} + +You can also typeset the output by changing the value of +\verb|\sagecommandlinetextoutput| to False: +\renewcommand{\sagecommandlinetextoutput}{False} +\begin{sagecommandline} + sage: l*d*u + sage: x = var('x') + sage: (1-cos(x)^2).trig_simplify() +\end{sagecommandline} + +\renewcommand{\sagecommandlinetextoutput}{True} + +The Sage input and output is typeset using the \texttt{listings} package +with the styles \texttt{SageInput} and \texttt{SageOutput}, +respectively. If you don't like the defaults you can change them. It is +recommended to derive from \texttt{DefaultSageInput} and +\texttt{DefaultSageOutput}, for example\ldots +\lstdefinestyle{SageInput}{style=DefaultSageInput,basicstyle={\color{red}}} +\lstdefinestyle{SageOutput}{style=DefaultSageOutput,basicstyle={\color{green}}} +makes things overly colorful: +\begin{sagecommandline} + sage: pi.n(100) +\end{sagecommandline} +\lstdefinestyle{SageInput}{style=DefaultSageInput} +\lstdefinestyle{SageOutput}{style=DefaultSageOutput} + +Plotting things doesn't automatically pull in the plot, just the text +representation of the plot (the equivalent of applying \texttt{str()} to +it): + +\begin{sagecommandline} + sage: plot(sin(x), (x, 0, 2*pi)) +\end{sagecommandline} + +You can include output, but it will be ignored. This is useful for +doctesting, as all the \texttt{sagecommandline} environment things get +put into the ``\texttt{\_doctest.sage}'' file. However, note that if you +don't include any output, then the corresponding doctest will fail if +the command produces output. The doctest output from this file will have +lots of failures because not many of the commands have output included +in the source \texttt{.tex} file. + +The command below has incorrect output included in the \texttt{.tex} +file; in the PDF, you see the correct Sage-computed answer, but if you +do \texttt{sage -t example\_doctest.sage} you will get a genuine doctest +failure. +\begin{sagecommandline} + sage: factor(x^2 + 2*x + 1) + (x + 999)^2 +\end{sagecommandline} + +\end{document} diff --git a/macros/latex/contrib/sagetex/py-and-sty.dtx b/macros/latex/contrib/sagetex/py-and-sty.dtx new file mode 100644 index 0000000000..a27dbc5bd8 --- /dev/null +++ b/macros/latex/contrib/sagetex/py-and-sty.dtx @@ -0,0 +1,1575 @@ +% \section{Implementation} +% \label{sec:implementation} +% +% There are two pieces to this package: a \LTX style file, and a +% Python module. They are mutually interdependent, so it makes sense to +% document them both here. +% +% \subsection{The style file} +% \label{sec:sty-file} +% +% \iffalse +% tell docstrip to put code into the .sty file +%<*latex> +% \fi +% +% All macros and counters intended for use internal to this package +% begin with ``|ST@|''. +% +% \subsubsection{Initialization} +% +% Let's begin by loading some packages. The key bits of |sageblock| and +% friends are stol---um, adapted from the |verbatim| package manual. So +% grab the |verbatim| package. We also need the |fancyvrb| package for +% the |sageexample| environment +% \begin{macrocode} +\RequirePackage{verbatim} +\RequirePackage{fancyvrb} +% \end{macrocode} +% and |listings| for the |sagecommandline| environment. +% \begin{macrocode} +\RequirePackage{listings} +\RequirePackage{color} +\lstdefinelanguage{Sage}[]{Python} + {morekeywords={False,sage,True},sensitive=true} +\lstdefinelanguage{SageOutput}[]{} + {morekeywords={False,True},sensitive=true} +\lstdefinestyle{DefaultSageInputOutput}{ + nolol, + identifierstyle=, + name=sagecommandline, + xleftmargin=5pt, + numbersep=5pt, + aboveskip=0pt, + belowskip=0pt, + breaklines=true, + numberstyle=\footnotesize, + numbers=right +} +\lstdefinestyle{DefaultSageInput}{ + language=Sage, + style=DefaultSageInputOutput, + basicstyle={\ttfamily\bfseries}, + commentstyle={\ttfamily\color{dgreencolor}}, + keywordstyle={\ttfamily\color{dbluecolor}\bfseries}, + stringstyle={\ttfamily\color{dgraycolor}\bfseries}, +} +\lstdefinestyle{DefaultSageOutput}{ + language=SageOutput, + style=DefaultSageInputOutput, + basicstyle={\ttfamily}, + commentstyle={\ttfamily\color{dgreencolor}}, + keywordstyle={\ttfamily\color{dbluecolor}}, + stringstyle={\ttfamily\color{dgraycolor}}, +} +\lstdefinestyle{SageInput}{ + style=DefaultSageInput, +} +\lstdefinestyle{SageOutput}{ + style=DefaultSageOutput, +} +\definecolor{dbluecolor}{rgb}{0.01,0.02,0.7} +\definecolor{dgreencolor}{rgb}{0.2,0.4,0.0} +\definecolor{dgraycolor}{rgb}{0.30,0.3,0.30} +% \end{macrocode} +% Unsurprisingly, the |\sageplot| command works poorly without graphics +% support. +% \begin{macrocode} +\RequirePackage{graphicx} +% \end{macrocode} +% The |makecmds| package gives us a |\provideenvironment| which we need, +% and we use |ifpdf| and |ifthen| in |\sageplot| so we know what kind of +% files to look for. Since |ifpdf| doesn't detect running under XeTeX +% (which defaults to producing PDFs), we need |ifxetex|. Hopefully the +% |ifpdf| package will get support for this and we can drop |ifxetex|. +% We also work around ancient \TeX{} distributions that don't have +% |ifxetex| and assume that they don't have XeTeX. +% \begin{macrocode} +\RequirePackage{makecmds} +\RequirePackage{ifpdf} +\RequirePackage{ifthen} +\IfFileExists{ifxetex.sty}{ + \RequirePackage{ifxetex} +}{ + \newboolean{xetex} + \setboolean{xetex}{false}} +% \end{macrocode} +% +% Next set up the counters, default indent, and flags. +% \begin{macrocode} +\newcounter{ST@inline} +\newcounter{ST@plot} +\newcounter{ST@cmdline} +\setcounter{ST@inline}{0} +\setcounter{ST@plot}{0} +\setcounter{ST@cmdline}{0} +\newlength{\sagetexindent} +\setlength{\sagetexindent}{5ex} +\newif\ifST@paused +\ST@pausedfalse +% \end{macrocode} +% Set up the file stuff, which will get run at the beginning of the +% document, after we know what's happening with the |final| option. +% First, we open the |.sage| file: +% \begin{macrocode} +\AtBeginDocument{\@ifundefined{ST@final}{% +\newwrite\ST@sf% +\immediate\openout\ST@sf=\jobname.sagetex.sage% +% \end{macrocode} +% \begin{macro}{\ST@wsf} +% We will write a lot of stuff to that file, so make a convenient +% abbreviation, then use it to put the initial commands into the +% |.sage| file. The hash mark below gets doubled when written to the +% file, for some obscure reason related to parameter expansion. It's +% valid Python, though, so I haven't bothered figuring out how to get +% a single hash. We are assuming that the extension is |.tex|; see the +% |initplot| documentation on page~\pageref{initplot} for discussion +% of file extensions. (There is now the \texttt{currfile} package +% (\url{http://www.ctan.org/pkg/currfile/}) which can figure out file +% extensions, apparently.) The ``|(\jobname.sagetex.sage)|'' business +% is there because the comment below will get pulled into the +% autogenerated |.py| file (second order autogeneration!) and I'd like +% to reduce possible confusion if someone is looking around in those +% files. Finally, we check for version mismatch and bail if the .py +% and .sty versions don't match and the user hasn't disabled checking. +% Note that we use |^^J| and not |^^J%| when we need indented lines. +% Also, |sagetex.py| now includes a |version| variable which +% eliminates all the irritating string munging below, and later we can +% remove this stuff and just use |sagetex.version|. +% \changes{v2.2.4}{2010/02/15}{Add version mismatch checking.} +% \changes{v2.3.3}{2012/01/13}{Improve version mismatch checking, +% include Mercurial revision in version string.} +% \begin{macrocode} +\newcommand{\ST@wsf}[1]{\immediate\write\ST@sf{#1}}% +\ST@wsf{% +# -*- encoding: utf-8 -*-^^J% +# This file (\jobname.sagetex.sage) was *autogenerated* from \jobname.tex with +sagetex.sty version \ST@ver.^^J% +import sagetex^^J% +_st_ = sagetex.SageTeXProcessor('\jobname', version='\ST@ver', version_check=\ST@versioncheck)}}% +% \end{macrocode} +% On the other hand, if the |ST@final| flag is set, don't bother with +% any of the file stuff, and make |\ST@wsf| a no-op. +% \begin{macrocode} +{\newcommand{\ST@wsf}[1]{\relax}}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ST@dodfsetup} +% The |sageexample| environment writes stuff out to a different file +% formatted so that one can run doctests on it. We define a macro that +% only sets this up if necessary. +% \begin{macrocode} +\newcommand{\ST@dodfsetup}{% +\@ifundefined{ST@diddfsetup}{% +\newwrite\ST@df% +\immediate\openout\ST@df=\jobname_doctest.sage% +\immediate\write\ST@df{r"""^^J% +This file was *autogenerated* from \jobname.tex with sagetex.sty^^J% +version \ST@ver. It contains the contents of all the^^J% +sageexample environments from \jobname.tex. You should be able to^^J% +doctest this file with "sage -t \jobname_doctest.sage".^^J% +^^J% +It is always safe to delete this file; it is not used in typesetting your^^J% +document.^^J}% +\AtEndDocument{\immediate\write\ST@df{"""}}% +\gdef\ST@diddfsetup{x}}% +{\relax}} +% \end{macrocode} +% \changes{v2.2.5}{2010/03/25}{Write sageexample environment contents to +% a separate file, formatted for doctesting} +% \end{macro} +% +% \begin{macro}{\ST@wdf} +% This is the compansion to |\ST@wsf|; it writes to the doctest file, +% assuming that is has been set up. We ignore the |final| option here +% since nothing in this file is relevant to typesetting the document. +% \begin{macrocode} +\newcommand{\ST@wdf}[1]{\immediate\write\ST@df{#1}} +% \end{macrocode} +% \end{macro} +% +% Now we declare our options, which mostly just set flags that we check +% at the beginning of the document, and when running the |.sage| file. +% \changes{v2.0}{2008/04/04}{Add \texttt{epstopdf} option} +% \changes{v2.0}{2008/12/16}{Add \texttt{final} option} +% +% The |final| option controls whether or not we write the |.sage| file; +% the |imagemagick| and |epstopdf| options both want to write something +% to that same file. So we put off all the actual file stuff until the +% beginning of the document---by that time, we'll have processed the +% |final| option (or not) and can check the |\ST@final| flag to see what +% to do. (We must do this because we can't specify code that runs if an +% option \emph{isn't} defined.) +% +% For |final|, we set a flag for other guys to check, and if there's no +% |.sout| file, we warn the user that something fishy is going on. +% \begin{macrocode} +\DeclareOption{final}{% + \newcommand{\ST@final}{x}% + \IfFileExists{\jobname.sagetex.sout}{}{\AtEndDocument{\PackageWarningNoLine{sagetex}% + {`final' option provided, but \jobname.sagetex.sout^^Jdoesn't exist! No Sage + input will appear in your document. Remove the `final'^^Joption and + rerun LaTeX on your document}}}} +% \end{macrocode} +% For |imagemagick|, we set two flags: one for \LTX and one for Sage. +% It's important that we set |ST@useimagmagick| \emph{before} the +% beginning of the document, so that the graphics commands can check +% that. We do wait until the beginning of the document to do file +% writing stuff. +% \begin{macrocode} +\DeclareOption{imagemagick}{% + \newcommand{\ST@useimagemagick}{x}% + \AtBeginDocument{% + \@ifundefined{ST@final}{% + \ST@wsf{_st_.useimagemagick = True}}{}}} +% \end{macrocode} +% For |epstopdf|, we just set a flag for Sage. +% \begin{macrocode} +\DeclareOption{epstopdf}{% +\AtBeginDocument{% +\@ifundefined{ST@final}{% + \ST@wsf{_st_.useepstopdf = True}}{}}} +% \end{macrocode} +% By default, we check to see if the .py and .sty file versions match. +% But we let the user disable this. +% \begin{macrocode} +\newcommand{\ST@versioncheck}{True} +\DeclareOption{noversioncheck}{% + \renewcommand{\ST@versioncheck}{False}} +\ProcessOptions\relax +% \end{macrocode} +% The |\relax| is a little incantation suggested by the ``\LaTeXe{} for +% class and package writers'' manual, section 4.7. +% +% Pull in the |.sout| file if it exists, or do nothing if it doesn't. I +% suppose we could do this inside an |AtBeginDocument| but I don't see +% any particular reason to do that. It will work whenever we load it. If +% the |.sout| file isn't found, print the usual \TeX-style message. This +% allows programs +% (\href{http://www.phys.psu.edu/~collins/software/latexmk-jcc/}{\texttt{Latexmk}}, for example) +% that read the |.log| file or terminal output to detect +% the need for another typesetting run to do so. If the ``\texttt{No +% file foo.sout}'' line doesn't work for some software package, please +% let me know and I can change it to use |PackageInfo| or whatever. +% \begin{macrocode} +\InputIfFileExists{\jobname.sagetex.sout}{} +{\typeout{No file \jobname.sagetex.sout.}} +% \end{macrocode} +% \changes{v2.1.1}{2009/05/14}{Add typeout if .sout file not found} +% +% The user might load the |hyperref| package after this one (indeed, the +% |hyperref| documentation insists that it be loaded last) or not at +% all---so when we hit the beginning of the document, provide a dummy +% |NoHyper| environment if one hasn't been defined by the |hyperref| +% package. We need this for the |\sage| macro below. +% \begin{macrocode} +\AtBeginDocument{\provideenvironment{NoHyper}{}{}} +% \end{macrocode} +% +% \subsubsection{The \texttt{\protect\bslash sage} and +% \texttt{\protect\bslash sagestr} macros} +% \label{sec:sagemacro} +% +% \begin{macro}{\ST@sage} +% \changes{v2.1.1}{2009/05/14}{Add ST@sage, sagestr, and refactor.} +% This macro combines |\ref|, |\label|, and Sage all at once. First, we +% use Sage to get a \LTX representation of whatever you give this +% function. The Sage script writes a |\newlabel| line into the |.sout| +% file, and we read the output using the |\ref| command. Usually, |\ref| +% pulls in a section or theorem number, but it will pull in arbitrary +% text just as well. +% +% The first thing it does it write its argument into the |.sage| file, +% along with a counter so we can produce a unique label. We wrap a +% try/except around the function call so that we can provide a more +% helpful error message in case something goes wrong. (In particular, we +% can tell the user which line of the |.tex| file contains the offending +% code.) Note the difference between |^^J| and |^^J%|: the newline +% immediately after the former puts a space into the output, and the +% percent sign in the latter supresses this. +% \begin{macrocode} +\newcommand{\ST@sage}[1]{\ST@wsf{% +try:^^J + _st_.current_tex_line = \the\inputlineno^^J + _st_.inline(\theST@inline, #1)^^J% +except:^^J + _st_.goboom(\the\inputlineno)}% +% \end{macrocode} +% The |inline| function of the Python module is documented on page +% \pageref{inlinefn}. Back in \LTX-land: if paused, say so. +% \begin{macrocode} +\ifST@paused + \mbox{(Sage\TeX{} is paused)}% +% \end{macrocode} +% Otherwise\ldots our use of |\newlabel| and |\ref| seems awfully clever +% until you load the |hyperref| package, which gleefully tries to +% hyperlink the hell out of everything. This is great until it hits one +% of our special |\newlabel|s and gets deeply confused. Fortunately the +% |hyperref| folks are willing to accomodate people like us, and give us +% a |NoHyper| environment. +% \begin{macrocode} +\else + \begin{NoHyper}\ref{@sageinline\theST@inline}\end{NoHyper}% +% \end{macrocode} +% Now check if the label has already been defined. (The internal +% implementation of labels in \LTX involves defining a macro called +% ``|r@@labelname|''.) If it hasn't, we set a flag so that we can tell +% the user to run Sage on the |.sage| file at the end of the run. +% \begin{macrocode} + \@ifundefined{r@@sageinline\theST@inline}{\gdef\ST@rerun{x}}{}% +\fi +% \end{macrocode} +% In any case, the last thing to do is step the counter. +% \begin{macrocode} +\stepcounter{ST@inline}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sage} +% This is the user-visible macro; it runs Sage's |latex()| on its +% argument. +% \begin{macrocode} +\newcommand{\sage}[1]{\ST@sage{latex(#1)}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sagestr} +% Like above, but doesn't run |latex()| on its argument. +% \begin{macrocode} +\newcommand{\sagestr}[1]{\ST@sage{#1}} +% \end{macrocode} +% +% \end{macro} +% +% \begin{macro}{\percent} +% A macro that inserts a percent sign. This is more-or-less stolen from the +% \textsf{Docstrip} manual; there they change the catcode inside a group +% and use |gdef|, but here we try to be more \LaTeX y and use +% |\newcommand|. +% \begin{macrocode} +\catcode`\%=12 +\newcommand{\percent}{%} +\catcode`\%=14 +% \end{macrocode} +% \end{macro} +% +% \subsubsection{The \texttt{\protect\bslash sageplot} macro and friends} +% \label{sec:sageplotmacro} +% +% Plotting is rather more complicated, and requires several helper +% macros that accompany |\sageplot|. +% +% \begin{macro}{\ST@plotdir} +% A little abbreviation for the plot directory. We don't use +% |\graphicspath| because it's +% \href{http://www.tex.ac.uk/cgi-bin/texfaq2html?label=graphicspath}{ +% apparently slow}---also, since we know right where our plots are +% going, no need to have \LTX looking for them. +% \begin{macrocode} +\newcommand{\ST@plotdir}{sage-plots-for-\jobname.tex} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ST@missingfilebox} +% The code that makes the ``file not found'' box. This shows up in a +% couple places below, so let's just define it once. +% \begin{macrocode} +\newcommand{\ST@missingfilebox}{\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\sageplot} +% \changes{v1.3}{2008/03/08}{Iron out warnings, cool \TikZ flowchart} +% This function is similar to |\sage|. The neat thing that we take +% advantage of is that commas aren't special for arguments to \LTX +% commands, so it's easy to capture a bunch of keyword arguments that +% get passed right into a Python function. +% +% This macro has two optional arguments, which can't be defined using +% \LTX's |\newcommand|; we use Scott Pakin's brilliant +% \href{http://tug.ctan.org/tex-archive/support/newcommand/}{|newcommand|} +% package to create this macro; the options I fed to his script were +% similar to this: +%\begin{center} +% |MACRO sageplot OPT[#1={width}] OPT[#2={notprovided}] #3| +%\end{center} +% Observe that we are using a Python script to write \LTX code which +% writes Python code which writes \LTX code. Crazy! +% +% Here's the wrapper command which does whatever magic we need to get +% two optional arguments. +% \begin{macrocode} +\newcommand{\sageplot}[1][]{% + \@ifnextchar[{\ST@sageplot[#1]}{\ST@sageplot[#1][notprovided]}} +% \end{macrocode} +% \changes{v2.3.2}{2011/06/17}{Remove ``.75 textwidth'' default option} +% The first optional argument |#1| will get shoved right into the +% optional argument for |\includegraphics|, so the user has easy control +% over the \LTX aspects of the plotting. (Perhaps a future version +% of \ST will allow the user to specify in the package options a set of +% default options to be used throughout.) The second optional argument +% |#2| is the file format and allows us to tell what files to look for. +% It defaults to ``notprovided'', which tells the Python module to +% create EPS and PDF files. Everything in |#3| gets put into the Python +% function call, so the user can put in keyword arguments there which +% get interpreted correctly by Python. +% +% \begin{macro}{\ST@sageplot} +% \changes{v2.0}{2008/12/16}{Change to use only keyword arguments: see issue +% 2 on bitbucket tracker} +% Let's see the real code here. We write a couple lines to the |.sage| +% file, including a counter, input line number, and all of the mandatory +% argument; all this is wrapped in another try/except. +% \begin{macrocode} +\def\ST@sageplot[#1][#2]#3{\ST@wsf{try:^^J + _st_.current_tex_line = \the\inputlineno^^J + _st_.plot(\theST@plot, format='#2', _p_=#3)^^Jexcept:^^J + _st_.goboom(\the\inputlineno)}% +% \end{macrocode} +% The Python |plot| function is documented on page~\pageref{plotfn}. +% +% Now we include the appropriate graphics file. Because the user might +% be producing DVI or PDF files, and have supplied a file format or not, +% and so on, the logic we follow is a bit complicated. +% \autoref{f:sageplottree} shows what we do; for completeness---and +% because I think drawing trees with \TikZ is really cool---we show what +% |\ST@inclgrfx| does in \autoref{f:stig}. This entire complicated +% business is intended to avoid doing an |\includegraphics| command on a +% file that doesn't exist, and to issue warnings appropriate to the +% situation. +% +% \begin{figure} +% \centering +% \begin{tikzpicture} +% \tikzstyle{level 1}=[sibling distance=6cm] +% \tikzstyle{level 2}=[sibling distance=3cm] +% \node [box] {DVI or PDF?} +% child {node [box] {Format provided?} +% child {node [box] {STig EPS} +% edge from parent node[left] {no}} +% child {node [box] {IM option set?} +% child {node [box, text width=3cm] {Warn that DVI + PNG = bad} +% edge from parent node[left] {no}} +% child {node [box] {STig EPS} +% edge from parent node[right] {yes}} +% edge from parent node[right] {yes}} +% edge from parent node[left] {DVI}} +% child {node [box] {Format provided?} +% child {node [box] {STig PDF} +% edge from parent node[left] {no}} +% child {node [box] {STig \texttt{\#2}} +% edge from parent node[right] {yes}} +% edge from parent node[right] {PDF}}; +% \end{tikzpicture} +% \caption{The logic tree that \texttt{\bslash sageplot} uses to +% decide whether to run \texttt{\bslash includegraphics} or to yell at +% the user. ``Format'' is the \texttt{\#2} argument to \texttt{\bslash +% sageplot}, ``STig ext'' +% means a call to \texttt{\bslash ST@inclgrfx} with ``ext'' as the +% second argument, and ``IM'' is Imagemagick.} +% \label{f:sageplottree} +% \end{figure} +% +% If we are creating a PDF, we check to see if the user asked for a +% different format, and use that if necessary: +% \begin{macrocode} +\ifthenelse{\boolean{pdf} \or \boolean{xetex}}{ + \ifthenelse{\equal{#2}{notprovided}}% + {\ST@inclgrfx{#1}{pdf}}% + {\ST@inclgrfx{#1}{#2}}} +% \end{macrocode} +% Otherwise, we are creating a DVI file, which only supports EPS. If the +% user provided a format anyway, don't include the file (since it won't +% work) and warn the user about this. (Unless the file doesn't exist, in +% which case we do the same thing that |\ST@inclgrfx| does.) +% \begin{macrocode} +{ \ifthenelse{\equal{#2}{notprovided}}% + {\ST@inclgrfx{#1}{eps}}% +% \end{macrocode} +% If a format is provided, we check to see if we're using the +% imagemagick option. If not, we're going to issue some sort of warning, +% depending on whether the file exists yet or not. +% \begin{macrocode} + {\@ifundefined{ST@useimagemagick}% + {\IfFileExists{\ST@plotdir/plot-\theST@plot.#2}% + {\ST@missingfilebox% + \PackageWarning{sagetex}{Graphics file + \ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space + cannot be used with DVI output. Use pdflatex or create an EPS + file. Plot command is}}% + {\ST@missingfilebox% + \PackageWarning{sagetex}{Graphics file + \ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space + does not exist. Plot command is}% + \gdef\ST@rerun{x}}}% +% \end{macrocode} +% Otherwise, we are using Imagemagick, so try to include an EPS file +% anyway. +% \begin{macrocode} + {\ST@inclgrfx{#1}{eps}}}} +% \end{macrocode} +% Step the counter and we're done with the usual work. +% \begin{macrocode} +\stepcounter{ST@plot}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ST@inclgrfx} +% This command includes the requested graphics file (|#2| is the +% extension) with the requested options (|#1|) if the file exists. Note +% that it just needs to know the extension, since we use a counter for +% the filename. If we are paused, it just puts in a little box saying +% so. +% \begin{macrocode} +\newcommand{\ST@inclgrfx}[2]{\ifST@paused + \fbox{\rule[-1cm]{0cm}{2cm}Sage\TeX{} is paused; no graphic} +\else + \IfFileExists{\ST@plotdir/plot-\theST@plot.#2}% + {\includegraphics[#1]{\ST@plotdir/plot-\theST@plot.#2}}% +% \end{macrocode} +% If the file doesn't exist, we try one more thing before giving up: the +% Python module will automatically fall back to saving as a PNG file if +% saving as an EPS or PDF file fails. So if making a PDF, we look for a +% PNG file. +% +% If the file isn't there, we insert a little box to indicate it wasn't +% found, issue a warning that we didn't find a graphics file, then set a +% flag that, at the end of the run, tells the user to run Sage again. +% \begin{macrocode} + {\IfFileExists{\ST@plotdir/plot-\theST@plot.png}% + {\ifpdf + \ST@inclgrfx{#1}{png} + \else + \PackageWarning{sagetex}{Graphics file + \ST@plotdir/plot-\theST@plot.png on page \thepage\space not + supported; try using pdflatex. Plot command is}% + \fi}% + {\ST@missingfilebox% + \PackageWarning{sagetex}{Graphics file + \ST@plotdir/plot-\theST@plot.#2\space on page \thepage\space does not + exist. Plot command is}% + \gdef\ST@rerun{x}}} +\fi} +% \end{macrocode} +% \autoref{f:stig} makes this a bit clearer. +% \begin{figure} +% \centering +% \begin{tikzpicture} +% \tikzstyle{level 1}=[sibling distance=4cm] +% \node [box] {Paused?} +% child {node [box] {Insert ``we're paused'' box} +% edge from parent node[left] {yes}} +% child {node [box] {Does EXT file exist?} +% child {node [box] {Does a PNG file exist?} +% child {node [box] {Making a PDF?} +% child {node [box] {\texttt{includegraphics} PNG} +% edge from parent node[left] {yes}} +% child {node [box, text width=2cm] {Warning: DVI, PNG incompatible} +% edge from parent node[left] {no}} +% edge from parent node[left] {yes}} +% child {node [box, text width = 2.125cm] {Warn user to rerun Sage} +% edge from parent node[left] {no}} +% edge from parent node[left] {no}} +% child {node [box] {Use \texttt{includegraphics}} +% edge from parent node[right] {yes}} +% edge from parent node[right] {no}}; +% \end{tikzpicture} +% \caption{The logic used by the \texttt{\bslash ST@inclgrfx} +% command.} +% \label{f:stig} +% \end{figure} +% \end{macro} +% +% \subsubsection{Verbatim-like environments} +% \label{sec:verbatim-envs} +% +% \begin{macro}{\ST@beginsfbl} +% This is ``begin |.sage| file block'', an internal-use abbreviation +% that sets things up when we start writing a chunk of Sage code to +% the |.sage| file. It begins with some \TeX{} magic that fixes +% spacing, then puts the start of a try/except block in the |.sage| +% file---this not only allows the user to indent code without +% Sage/Python complaining about indentation, but lets us tell the user +% where things went wrong. The |blockbegin| and |blockend| functions +% are documented on page~\pageref{blocksbeginend}. The last bit is some +% magic from the |verbatim| package manual that makes \LTX respect +% line breaks. +% \begin{macrocode} +\newcommand{\ST@beginsfbl}{% + \@bsphack\ST@wsf{% +_st_.current_tex_line = \the\inputlineno^^J% +_st_.blockbegin()^^Jtry:}% + \let\do\@makeother\dospecials\catcode`\^^M\active} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ST@endsfbl} +% The companion to |\ST@beginsfbl|. +% \begin{macrocode} +\newcommand{\ST@endsfbl}{% +\ST@wsf{except:^^J + _st_.goboom(\the\inputlineno)^^J_st_.blockend()}} +% \end{macrocode} +% \end{macro} +% +% Now let's define the ``verbatim-like'' environments. There are four +% possibilities, corresponding to the two independent choices of +% typesetting the code or not, and writing to the |.sage| file or not. +% +% \begin{environment}{sageblock} +% This environment does both: it typesets your code and puts it into the +% |.sage| file for execution by Sage. +% \begin{macrocode} +\newenvironment{sageblock}{\ST@beginsfbl% +% \end{macrocode} +% The space between |\ST@wsf{| and |\the| is crucial! It, along with the +% ``|try:|'', is what allows the user to indent code if they like. This +% line sends stuff to the |.sage| file. +% \begin{macrocode} +\def\verbatim@processline{\ST@wsf{ \the\verbatim@line}% +% \end{macrocode} +% Next, we typeset your code and start the verbatim environment. +% \begin{macrocode} +\hspace{\sagetexindent}\the\verbatim@line\par}% +\verbatim}% +% \end{macrocode} +% At the end of the environment, we put a chunk into the |.sage| file +% and stop the verbatim environment. +% \begin{macrocode} +{\ST@endsfbl\endverbatim} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{sagesilent} +% This is from the |verbatim| package manual. It's just like the above, +% except we don't typeset anything. +% \begin{macrocode} +\newenvironment{sagesilent}{\ST@beginsfbl% +\def\verbatim@processline{\ST@wsf{ \the\verbatim@line}}% +\verbatim@start}% +{\ST@endsfbl\@esphack} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{sageverbatim} +% The opposite of |sagesilent|. This is exactly the same as the verbatim +% environment, except that we include some indentation to be consistent +% with other typeset Sage code. +% \begin{macrocode} +\newenvironment{sageverbatim}{% +\def\verbatim@processline{\hspace{\sagetexindent}\the\verbatim@line\par}% +\verbatim}% +{\endverbatim} +% \end{macrocode} +% \end{environment} +% +% Logically, we now need an environment which neither typesets +% \emph{nor} writes code to the |.sage| file. The verbatim package's +% |comment| environment does that.\\ +% +% \begin{environment}{sageexample} +% Finally, we have an environment which is mostly-but-not-entirely +% verbatim; this is the example environment, which takes input like +% Sage doctests, and prints out the commands verbatim but nicely +% typesets the output of those commands. This and the corresponding +% Python function are originally due to Nicolas M. Thi\'ery. +% \begin{macrocode} +\newcommand{\sageexampleincludetextoutput}{False} +\newenvironment{sageexample}{% + \ST@wsf{% +try:^^J + _st_.current_tex_line = \the\inputlineno^^J + _st_.doctest(\theST@inline, r"""}% + \ST@dodfsetup% + \ST@wdf{Sage example, line \the\inputlineno::^^J}% + \begingroup% + \@bsphack% + \let\do\@makeother\dospecials% + \catcode`\^^M\active% + \def\verbatim@processline{% + \ST@wsf{\the\verbatim@line}% + \ST@wdf{\the\verbatim@line}% + }% + \verbatim@start% +} +{ + \@esphack% + \endgroup% + \ST@wsf{% + """, globals(), locals(), \sageexampleincludetextoutput)^^Jexcept:^^J + _st_.goboom(\the\inputlineno)}% + \ifST@paused% + \mbox{(Sage\TeX{} is paused)}% + \else% + \begin{NoHyper}\ref{@sageinline\theST@inline}\end{NoHyper}% + \@ifundefined{r@@sageinline\theST@inline}{\gdef\ST@rerun{x}}{}% + \fi% + \ST@wdf{}% + \stepcounter{ST@inline}} +% \end{macrocode} +% \changes{v2.2.4}{2010/03/14}{Add first support for +% \texttt{sageexample} environment} +% \end{environment} +% +% +% \begin{environment}{sagecommandline} +% This environment is similar to the |sageexample| environment, but +% typesets the Sage output as text with Python syntax highlighting. +% \begin{macrocode} +\newcommand{\sagecommandlinetextoutput}{True} +\newlength{\sagecommandlineskip} +\setlength{\sagecommandlineskip}{8pt} +\newenvironment{sagecommandline}{% + \ST@wsf{% +try:^^J + _st_.current_tex_line = \the\inputlineno^^J + _st_.commandline(\theST@cmdline, r"""}% + \ST@dodfsetup% + \ST@wdf{Sage commandline, line \the\inputlineno::^^J}% + \begingroup% + \@bsphack% + \let\do\@makeother\dospecials% + \catcode`\^^M\active% + \def\verbatim@processline{% + \ST@wsf{\the\verbatim@line}% + \ST@wdf{\the\verbatim@line}% + }% + \verbatim@start% +} +{ + \@esphack% + \endgroup% + \ST@wsf{% + """, globals(), locals(), \sagecommandlinetextoutput)^^Jexcept:^^J + _st_.goboom(\the\inputlineno)}% + \ifST@paused% + \mbox{(Sage\TeX{} is paused)}% + \else% + \begin{NoHyper}\ref{@sagecmdline\theST@cmdline}\end{NoHyper}% + \@ifundefined{r@@sagecmdline\theST@cmdline}{\gdef\ST@rerun{x}}{}% + \fi% + \ST@wdf{}% + \stepcounter{ST@cmdline}} +% \end{macrocode} +% \end{environment} +% +% \subsubsection{Pausing \ST} +% \label{sec:pausing-sagetex} +% +% How can one have Sage to stop processing \ST output for a little +% while, and then start again? At first I thought I would need some sort +% of ``goto'' statement in Python, but later realized that there's a +% dead simple solution: write triple quotes to the |.sage| file to +% comment out the code. Okay, so this isn't \emph{really} commenting out +% the code; PEP 8 says block comments should use ``|#|'' and Sage will +% read in the ``commented-out'' code as a string literal. For the +% purposes of \ST, I think this is a good decision, though, since (1) +% the pausing mechanism is orthogonal to everything else, which makes it +% easier to not screw up other code, and (2) it will always work. +% +% This illustrates what I really like about \ST: it mixes \LTX and +% Sage/Python, and often what is difficult or impossible in one system +% is trivial in the other. +% +% \begin{macro}{sagetexpause} +% This macro pauses \ST by effectively commenting out code in the +% |.sage| file. When running the corresponding |.sage| file, Sage will +% skip over any commands issued while \ST is paused. +% \begin{macrocode} +\newcommand{\sagetexpause}{\ifST@paused\relax\else +\ST@wsf{print('SageTeX paused on \jobname.tex line \the\inputlineno')^^J"""} +\ST@pausedtrue +\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{sagetexunpause} +% This is the obvious companion to |\sagetexpause|. +% \begin{macrocode} +\newcommand{\sagetexunpause}{\ifST@paused +\ST@wsf{"""^^Jprint('SageTeX unpaused on \jobname.tex line \the\inputlineno')} +\ST@pausedfalse +\fi} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{End-of-document cleanup} +% \label{sec:end-of-doc-cleanup} +% +% We tell the Sage script to write some information to the |.sout| file, +% then check to see if |ST@rerun| ever got defined. If not, all the +% inline formulas and plots worked, so do nothing. We check to see if +% we're paused first, so that we can finish the triple-quoted string in +% the |.sage| file. +% \begin{macrocode} +\AtEndDocument{\ifST@paused +\ST@wsf{"""^^Jprint('SageTeX unpaused at end of \jobname.tex')} +\fi +\ST@wsf{_st_.endofdoc()}% +\@ifundefined{ST@rerun}{}% +% \end{macrocode} +% Otherwise, we issue a warning to tell the user to run Sage on the +% |.sage| file. Part of the reason we do this is that, by using |\ref| +% to pull in the inlines, \LTX will complain about undefined references +% if you haven't run the Sage script---and for many \LTX users, myself +% included, the warning ``there were undefined references'' is a signal +% to run \LTX again. But to fix these particular undefined references, +% you need to run \emph{Sage}. We also suppress file-not-found errors +% for graphics files, and need to tell the user what to do about that. +% +% At any rate, we tell the user to run Sage if it's necessary. +% \begin{macrocode} +{\typeout{*********************************************************************} +\PackageWarningNoLine{sagetex}{there were undefined Sage formulas and/or +plots.^^JRun Sage on \jobname.sagetex.sage, and then run LaTeX on \jobname.tex +again}} +\typeout{*********************************************************************}} +% \end{macrocode} +% +% +% \subsection{The Python module} +% \label{sec:py-file} +% +% \iffalse +% Hey, docstrip! Stop putting code into the .sty file, and start +% putting it into the .py file. +%</latex> +%<*python> +% Thanks. +% \fi +% +% The style file writes things to the |.sage| file and reads them from +% the |.sout| file. The Python module provides functions that help +% produce the |.sout| file from the |.sage| file. +% +% \paragraph{A note on Python and \textsf{Docstrip}} There is one tiny +% potential source of confusion when documenting Python code with +% \textsf{Docstrip}: the percent sign. If you have a long line of Python +% code which includes a percent sign for string formatting and you break +% the line with a backslash and begin the next line with a percent sign, +% that line \emph{will not} be written to the output file. This is only +% a problem if you \emph{begin} the line with a (single) percent sign; +% there are no troubles otherwise.\\ +% +% On to the code. Munge the version string (which we get from +% \texttt{sagetex.dtx}) to extract what we want, then import what we +% need: +% \begin{macrocode} +pyversion = ' '.join(__version__.strip('[').split()[0:2]) +from sage.misc.latex import latex +from sage.repl.preparse import preparse +import sys +import os +import os.path +import hashlib +import traceback +import subprocess +import shutil +import re +from collections import defaultdict +% \end{macrocode} +% Define an exception class for version mismatches. I suppose I could +% just use |ValueError|, but this is easy enough: +% \begin{macrocode} +class VersionError(Exception): + pass +% \end{macrocode} +% Sometimes our macros that write things to the |.sout| file get +% evaluated twice, most commonly in the ``fancy'' AMS environments such +% as |align| and |multline|. So we need to keep track of the counters +% we've seen so we don't write labels to the |.sout| file more than +% once. We have more than one kind of label, so a dictionary is the +% natural way to store the counters we've seen for each kind of label. +% For convenience let's make a dictionary subclass for which (1) values +% default to $-1$, and (2) there's an |increment(key)| function that just +% increments the value corresponding to the key. +% \begin{macrocode} +class MyDict(defaultdict): + def __init__(self, *args, **kwargs): + defaultdict.__init__(self, *args, **kwargs) + self.default_factory = lambda: -1 + + def increment(self, key): + self[key] = self[key] + 1 +% \end{macrocode} +% Here's a helper function used by |doctest|; it works ike |j.join(xs)|, +% but ensures exactly one copy of |j| between the strings in |xs|. +% Intended for |j| to be a single character, particularly newline so +% that you can join things with no extra blank lines. +% \begin{macrocode} +def joinone(j, xs_): + if len(xs_) >= 2: + xs = ([xs_[0].rstrip(j)] + + [x.strip(j) for x in xs_[1:-1]] + + [xs_[-1].lstrip(j)]) + else: + xs = xs_ + return j.join(xs) +% \end{macrocode} +% Another helper, used by |commandline| (and maybe, someday, +% |doctest|?). In each line, we look for a possibly empty sequence of +% spaces followed by a non-whitespace character, so we can distinguish +% between whitespace-only lines (which we ignore) and lines that have no +% leading spaces. +% +% One tiny possible problem: you might have a line of only, say, two +% spaces, but perhaps the ``real'' lines all start with at least three +% spaces. Then you would, for that line, do |line[2:]|. That seems like +% it might raise an error, since the line only has indices 0 and 1, but +% Python's indexing handles this perfectly: in that case, |line[2:]| +% will be the empty string, which is fine for our purposes. +% \begin{macrocode} +def strip_common_leading_spaces(s): + lines = s.splitlines() + lead = min(m.end() for m in + [re.match(' *\S', line) for line in lines] + if m is not None) - 1 + return '\n'.join(line[lead:] for line in lines) +% \end{macrocode} +% +% \subsubsection{The \texttt{SageTeXProcessor} class} +% \label{sec:sagetexprocessorclass} +% +% The star of the show, as it were. We define a |SageTeXProcessor| class +% so that it's a bit easier to carry around internal state. We used to +% just have some global variables and a bunch of functions, but this +% seems a bit nicer and easier. +% \begin{macrocode} +class SageTeXProcessor(): +% \end{macrocode} +% If the original |.tex| file has spaces in its name, the |\jobname| +% we get is surrounded by double quotes, so fix that. Technically, it +% is possible to have double quotes in a legitimate filename, but +% dealing with that sort of quoting is +% \href{http://tug.org/pipermail/xetex/2006-August/004712.html}{unpleasant}. +% And yes, we're ignoring the possibility of tabs and other whitespace +% in the filename. Patches for handling pathological filenames welcome. +% +% \changes{v2.3.1}{2011/02/02}{Handle filenames with +% spaces in SageTeXProcessor and sagecommandline env.} +% \changes{v2.3.2}{2012/01/13}{Improve version mismatch check. Fixes +% trac ticket 8035.} +% \begin{macrocode} + def __init__(self, jobname, version=None, version_check=True): + if version != pyversion: + errstr = """versions of .sty and .py files do not match. +{0}.sagetex.sage was generated by sagetex.sty version "{1}", but +is being processed by sagetex.py version "{2}". +Please make sure that TeX is using the sagetex.sty +from your current version of Sage; see +http://doc.sagemath.org/html/en/tutorial/sagetex.html.""".format(jobname, + version, pyversion) + if version_check: + raise VersionError(errstr) + else: + print('**** WARNING! Skipping version check for .sty and .py files, and') + print(errstr) + if ' ' in jobname: + jobname = jobname.strip('"') + self.progress('Processing Sage code for {0}.tex...'.format(jobname)) + self.didinitplot = False + self.useimagemagick = False + self.useepstopdf = False + self.plotdir = 'sage-plots-for-' + jobname + '.tex' + self.filename = jobname + self.name = os.path.splitext(jobname)[0] + autogenstr = """% This file was *autogenerated* from {0}.sagetex.sage with + % sagetex.py version {1}\n""".format(self.name, version) +% \end{macrocode} +% Don't remove the space before the percent sign above! +% +% \LTX environments such as |align| evaluate their arguments twice after +% doing |\savecounters@|, so if you do |\sage| inside such an environment, +% it will result in two labels with the same name in the |.sout| file and +% the user sees a warning when typesetting. So we keep track of the +% largest label we've seen so that we don't write two labels with the same +% name. +% \begin{macrocode} + self.max_counter_seen = MyDict() +% \end{macrocode} +% Open a |.sout.tmp| file and write all our output to that. Then, when +% we're done, we move that to |.sout|. The ``autogenerated'' line is +% basically the same as the lines that get put at the top of preparsed +% Sage files; we are automatically generating a file with Sage, so it +% seems reasonable to add it. Add in the version to help debugging +% version mismatch problems. +% \begin{macrocode} + self.souttmp = open(self.filename + '.sagetex.sout.tmp', 'w') + self.souttmp.write(autogenstr) +% \end{macrocode} +% In addition to the |.sout| file, the |sagecommandline| also needs a +% |.scmd| file. As before, we use a |.scmd.tmp| file and rename it +% later on. We store the position so that |commandline| can tell the +% |listings| package what lines in the |.scmd| file to pull in. +% \begin{macrocode} + self.scmdtmp = open(self.filename + '.sagetex.scmd.tmp', 'w') + self.scmdtmp.write(autogenstr) + self.scmdpos = 3 +% \end{macrocode} +% +% \begin{macro}{progress} +% This function just prints stuff. It allows us to not print a +% linebreak, so you can get ``|start...|'' (little time spent +% processing) ``|end|'' on one line. +% \begin{macrocode} + def progress(self, t,linebreak=True): + if linebreak: + print(t) + else: + sys.stdout.write(t) + sys.stdout.flush() +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{initplot} +% \phantomsection\label{initplot} +% We only want to create the plots directory if the user actually plots +% something. This function creates the directory and sets the +% |didinitplot| flag after doing so. We make a directory based on the +% \LTX file being processed so that if there are multiple |.tex| files +% in a directory, we don't overwrite plots from another file. +% \begin{macrocode} + def initplot(self): + self.progress('Initializing plots directory') +% \end{macrocode} +% We hard-code the |.tex| extension, which is fine in the overwhelming +% majority of cases, although it does cause minor confusion when +% building the documentation. If it turns out lots of people use, say, a +% |ltx| extension or whatever, We could find out the correct extension, +% but it would involve a lot of irritating mucking around---on +% |comp.text.tex|, the best solution I found for finding the file +% extension is to look through the |.log| file. (Although see the +% \texttt{currfile} package.) +% \begin{macrocode} + if os.path.isdir(self.plotdir): + shutil.rmtree(self.plotdir) + os.mkdir(self.plotdir) + self.didinitplot = True +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{inline} +% \phantomsection\label{inlinefn} +% This function works with |\sage| from the style file (see +% \autoref{sec:sagemacro}) to put Sage output into your \LTX file. +% Usually, when you use |\label|, it writes a line such as +% \begin{center} +% |\newlabel{labelname}{{section number}{page number}}| +% \end{center} +% to the |.aux| file. When you use the |hyperref| package, there are +% more fields in the second argument, but the first two fields are the +% same. The |\ref| command just pulls in what's in the first field of +% the second argument, so we can hijack this mechanism for our own +% nefarious purposes. The function writes a |\newlabel| line with a +% label made from a counter and the text from running Sage on |s|. +% +% When the user does |\sage| inside certain displayed math environments +% (|align| is the most common culprit) this function will get called +% twice with exactly the same arguments. We check to see what labels +% we've seen and immediately bail if we've written this label before. +% +% The |labelname| defaults to the the name used by the usual |\sage| +% inline macro, but this function is also used by the |sagecommandline| +% environment. It's important to keep the corresponding labels separate, +% because |\sage| macros often (for example) appear inside math mode, +% and the labels from |sagecommandline| contain a |lstlistings| +% environment---pulling such an environment into math mode produces +% strange, unrecoverable errors, and if you can't typeset your file, you +% can't produce an updated |.sagetex.sage| file to run Sage on to +% produce a reasonable |.sagetext.sout| file that will fix the label +% problem. So it works much better to use distinct labels for such +% things. +% \changes{v2.3.3}{2012/01/16}{check label name when comparing against +% maximum counter seen; trac ticket 12267} +% +% We print out the line number so if something goes wrong, the user can +% more easily track down the offending |\sage| command in the source +% file. +% +% That's a lot of explanation for a short function: +% \begin{macrocode} + def inline(self, counter, s, labelname='sageinline'): + if counter <= self.max_counter_seen[labelname]: + return + else: + self.max_counter_seen.increment(labelname) + if labelname == 'sageinline': + self.progress('Inline formula {0} (line {1})'.format(counter, self.current_tex_line)) + elif labelname == 'sagecmdline': + pass # output message already printed + else: + raise ValueError('inline() got a bad labelname "{0}"'.format(labelname)) + self.souttmp.write(r'\newlabel{@' + labelname + str(counter) + + '}{{%\n' + s.rstrip() + '}{}{}{}{}}\n') +% \end{macrocode} +% We are using five fields, just like |hyperref| does, because that +% works whether or not |hyperref| is loaded. Using two fields, as in +% plain \LTX, doesn't work if |hyperref| is loaded. +% \end{macro} +% +% \begin{macro}{savecmd} +% Analogous to |inline|, this method saves the input string |s| to the +% |souttmp| file. It returns the first and last line of the +% newly-added output so that |commandline| can tell the |listings| +% package where to get stuff. +% \begin{macrocode} + def savecmd(self, s): + self.scmdtmp.write(s.rstrip() + "\n") + begin = self.scmdpos + end = begin + len(s.splitlines()) - 1 + self.scmdpos = end + 1 + return begin, end +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{blockbegin} +% \begin{macro}{blockend} +% \phantomsection\label{blocksbeginend} +% This function and its companion used to write stuff to the |.sout| +% file, but now they just update the user on our progress evaluating a +% code block. The verbatim-like environments of +% \autoref{sec:verbatim-envs} use these functions. +% \begin{macrocode} + def blockbegin(self): + self.progress('Code block (line {}) begin...'.format(self.current_tex_line), False) + def blockend(self): + self.progress('end') +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{splitsagecmds} +% Given a string |s| of doctest-like Sage code, this function returns +% a list of tuples |(i, j, cmd)|, where |cmd| is a string representing +% a Sage command, with the initial prompt and continuation lines +% stripped, |i| is the position in |s| where |cmd| starts, and |j| is +% the starting position in |s| of the purported output from the +% command that was included in |s|. +% +% This is used by |doctest| and |commandline|, below. +% +% For example, this turns the string +% \begin{quote} +% |'''|\\ +% | sage: 1+1|\\ +% | 2|\\ +% | sage: y = 1729|\\ +% | sage: 10^3 + 9^3 == 12^3 + 1^3 == y|\\ +% | sage: gcd(9999999,|\\ +% | ....: 123456)|\\ +% | 3|\\ +% | sage: factor(x^2 + 2*x + 1)|\\ +% | (x + 1)^2|\\ +% |'''| +% \end{quote} +% into +% \begin{quote} +% |[(0, 18, '1+1'),|\\ +% | (28, 51, 'y = 1729'),|\\ +% | (51, 95, '10^3 + 9^3 == 12^3 + 1^3 == y'),|\\ +% | (95, 144, 'gcd(9999999,\n123456)'),|\\ +% | (154, 190, 'factor(x^2 + 2*x + 1)')]| +% \end{quote} +% You can reconstruct the sequence of commands and their output with +% something like +% \begin{quote} +% |splitup = split_sage_cmds(s)|\\ +% |oldout = splitup[0][1]|\\ +% |print('=' * 50)|\\ +% |print('==== Command:')|\\ +% |print(s[splitup[0][0]:oldout])|\\ +% |for start, out, _ in splitup[1:]:|\\ +% | print('==== Given output:')|\\ +% | print(s[oldout:start])|\\ +% | print('=' * 50)|\\ +% | print('==== Command:')|\\ +% | print(s[start:out])|\\ +% | oldout = out|\\ +% |print('==== Given output:')|\\ +% |print(s[oldout:])| +% \end{quote} +% \begin{macrocode} + def split_sage_cmds(self, s): + prompt = '\n' + r'\s*sage: ' + oldcont = r'\s*\.\.\.' + cont = r'\s*\.\.\.\.: ' +% \end{macrocode} +% Prepending a newline to |s| ensures that the list from |re.split()| +% begins with something we can ignore---and so that the |re.split()| +% returns $n+1$ groups for $n$ matches, so therefore |split| and +% |starts| match up. +% \begin{macrocode} + split = re.split(prompt, '\n' + s)[1:] + starts = [m.start() - 1 for m in re.finditer(prompt, '\n' + s)] +% \end{macrocode} +% The prepended newline messes up the first element of |starts|, fix +% that: +% \begin{macrocode} + starts[0] = re.search(prompt, s).start() +% \end{macrocode} +% Now find where the outputs start. We need this because |doctest()| may +% or may not print the outputs. The idea is: for each |start|ing +% position, advance over the prompt that we know is there, then look for +% the rightmost continuation marker between the current prompt and the +% next one, and \emph{then} look for the newline following that. That +% position is where the output begins. +% \begin{macrocode} + outputs = [] + for i, j in zip(starts, starts[1:] + [len(s)]): + k = i + re.match(prompt, s[i:j]).end() + try: + k += [m.end() for m in re.finditer(cont, s[k:j])][-1] + except IndexError: + pass + end = s.find('\n', k) + outputs.append(end) +% \end{macrocode} +% Now we take each command group, split it up, and look for all the +% continuation lines. We append those, stripping off the continuation +% marks. We also do some error checking so that users with documents +% that use the old |...| continuation marks get a reasonable error +% message. +% \begin{macrocode} + ret = [] + for start, end, g in zip(starts, outputs, split): + lines = g.splitlines() + cmd = lines[:1] + for line in lines[1:]: + has_old_cont = re.match(oldcont, line) + has_cont = re.match(cont, line) + if has_old_cont and not has_cont: + raise SyntaxError(""" SageTeX no longer supports "..." for line continuation in sagexample and +sagecommandline environments. Use "....:", which matches what the Sage +interpreter uses. See the documentation and example file in +SAGE_ROOT/local/share/doc/sagetex.""") + if has_cont: + cmd.append(line[has_cont.end():]) + ret.append((start, end, '\n'.join(cmd))) + return ret +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{doctest} +% This function handles the |sageexample| environment, which typesets +% Sage code and its output. We call it |doctest| because the format is +% just like that for doctests in the Sage library. +% +% The idea is: +% \begin{enumerate} +% \item Get the literal text for each command, wrap that in +% |SaveVerbatim|, write that (possibly with its associated output from +% the |.tex| file) to the |sout| file. +% \item Accumulate a corresponding |UseVerbatim| and typeset output so +% that we can call |inline()| at the end and pull in all this stuff. +% \item For the output: try to |eval()| the processed command (the one +% with the prompts and continuation marks stripped). If that succeeds, +% we run |latex()| on it and display that below the verbatim text from +% above. If that fails, it's because you have a statement and not an +% expression---there's no output from such a thing (well, none that we +% can capture, anyway) so no need to typeset output. +% \end{enumerate} +% \begin{macrocode} + def doctest(self, counter, s, globals, locals, include_text_output): + self.progress('Sage example {0} (line {1})'.format(counter, self.current_tex_line)) + splitup = self.split_sage_cmds(s) + tex_strs = [] + for i in range(len(splitup)): + boxname = '@sageinline{}-code{}'.format(counter, i) + to_tmp = [r'\begin{SaveVerbatim}{' + boxname + '}', + s[splitup[i][0]:splitup[i][1]]] + if include_text_output: + try: + to_tmp.append(s[splitup[i][1]:splitup[i+1][0]]) + except IndexError: + to_tmp.append(s[splitup[i][1]:]) + to_tmp.append('\\end{SaveVerbatim}\n') + self.souttmp.write(joinone('\n', to_tmp)) +% \end{macrocode} +% Now we build up something that we can send to |inline()|, which will +% pull it into the document using its usual label mechanism. +% +% The verbatim stuff seems to end with a bit of vertical space, so don't +% start the displaymath environment with unnecessary vertical +% space---the displayskip stuff is from \S 11.5 of Herbert Vo\ss's +% ``\href{http://www.ctan.org/tex-archive/info/math/voss/mathmode/}{Math +% Mode}''. +% \begin{macrocode} + tex_strs.append(r'\UseVerbatim{' + boxname + '}') + try: + result = eval(preparse(splitup[i][2]), globals, locals) + tex_strs += [r'\abovedisplayskip=0pt plus 3pt ', + r'\abovedisplayshortskip=0pt plus 3pt ', + r'\begin{displaymath}', + latex(result), + r' \end{displaymath}'] + except SyntaxError: + exec(preparse(splitup[i][2]), globals, locals) + self.inline(counter, '\n'.join(tex_strs)) +% \end{macrocode} +% \changes{v2.2.5}{2010/03/25}{Fix up spacing in sageexample displaymath envs} +% \changes{v3.0}{2015/08/26}{sageexample and sagecommandline now require +% ``...:'' for continuation lines, not ``...''; matches the actual +% Sage interpreter} +% \end{macro} +% +% \begin{macro}{commandline} +% This function handles the |commandline| environment, which typesets +% Sage code, computes its output, and typesets that too. This is very +% similar to |doctest| and I hope to someday combine them into one. +% +% Even if I can't refactor these two functions (and their associated +% environments) into one, I would like to eliminate the |.scmd| file +% that this function uses, since exactly the same bits of Sage code +% get written to both the |.scmd| file and the |_doctest.sage| file. +% The reason this isn't trivial is because we need to keep track of +% which line number we're on so that we can give the |listings| +% package a start and end line to extract, and right now the +% |_doctest.sage| file is written to by \LaTeX{} and we can't track +% the line number. +% +% In any case, here's what we do: after splitting up the provided +% string using |split_sage_cmds|, we iterate over each of the +% commands and: +% \begin{enumerate} +% \item Put the original input command into the |.scmd| file with +% |savecmd|. +% \item Use the |begin| and |end| line numbers to append a +% |lstinputlisting| command to the \TeX{} commands we'll eventually +% hand off to |inline|. +% \item Evaluate the command using |eval()| or |exec|, as necessary. +% If we're doing plain text format, we send the output to the +% |.scmd| file and add a \TeX{} command to pull that back in---if we +% need typeset output, then we just hit the output with |latex()| +% and add that to the list of \TeX{} commands. +% \end{enumerate} +% Observe that we detect spaces in the filename and quote that for +% \TeX{} if we need to. +% \begin{macrocode} + def commandline(self, counter, s, globals, locals, text_output): + self.progress('Sage commandline {0} (line {1})'.format(counter, self.current_tex_line)) + scmd_fn = self.name + '.sagetex.scmd' + if ' ' in scmd_fn: + scmd_fn = '"{}"'.format(scmd_fn) + + splitup = self.split_sage_cmds(s) + skip = r'\vspace{\sagecommandlineskip}' + tex_strs = [skip] + lstinput = r'\lstinputlisting[firstline={0},lastline={1},firstnumber={2},style=SageInput{escape}]{{{3}}}' + for i in range(len(splitup)): + orig_input = s[splitup[i][0]:splitup[i][1]] + begin, end = self.savecmd(strip_common_leading_spaces(orig_input.strip('\n'))) + if '#@' in orig_input: + escapeoption = ',escapeinside={\\#@}{\\^^M}' + else: + escapeoption = '' + tex_strs.append(lstinput.format(begin, end, begin - 2, scmd_fn, escape=escapeoption)) + try: + result = eval(preparse(splitup[i][2]), globals, locals) + if text_output: + begin, end = self.savecmd(str(result)) + tex_strs.append(lstinput.format(begin, end, begin - 2, scmd_fn, escape='')) + else: + tex_strs.append(r'\begin{displaymath}' + + latex(result) + + r'\end{displaymath}') + except SyntaxError: + exec(preparse(splitup[i][2]), globals, locals) + if 'displaymath' not in tex_strs[-1]: + tex_strs.append(skip) + self.inline(counter, '\n'.join(tex_strs), labelname='sagecmdline') +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{plot} +% \phantomsection\label{plotfn} +% I hope it's obvious that this function does plotting. It's the Python +% counterpart of |\ST@sageplot| described in \autoref{sec:sageplotmacro}. As +% mentioned in the |\sageplot| code, we're taking advantage of two +% things: first, that \LTX doesn't treat commas and spaces in macro +% arguments specially, and second, that Python (and Sage plotting +% functions) has nice support for keyword arguments. The |#3| argument +% to |\sageplot| becomes |_p_| and |**kwargs| below. +% \begin{macrocode} + def plot(self, counter, _p_, format='notprovided', **kwargs): + if not self.didinitplot: + self.initplot() + self.progress('Plot {0} (line {1})'.format(counter, self.current_tex_line)) +% \end{macrocode} +% If the user says nothing about file formats, we default to producing +% PDF and EPS. This allows the user to transparently switch between +% using a DVI previewer (which usually automatically updates when the +% DVI changes, and has support for source specials, which makes the +% writing process easier) and making PDFs.\footnote{Yes, there's +% \texttt{pdfsync}, but full support for that is still rare in Linux, so +% producing EPS and PDF is the best solution for now.} +% \begin{macrocode} + if format == 'notprovided': + formats = ['eps', 'pdf'] + else: + formats = [format] + for fmt in formats: +% \end{macrocode} +% If we're making a PDF and have been told to use |epstopdf|, do so, +% then skip the rest of the loop. +% \begin{macrocode} + if fmt == 'pdf' and self.useepstopdf: + epsfile = os.path.join(self.plotdir, 'plot-{0}.eps'.format(counter)) + self.progress('Calling epstopdf to convert plot-{0}.eps to PDF'.format( + counter)) + subprocess.check_call(['epstopdf', epsfile]) + continue +% \end{macrocode} +% Some plot objects (mostly 3-D plots) do not support saving to EPS or +% PDF files (yet), but everything can be saved to a PNG file. For the +% user's convenience, we catch the error when we run into such an +% object, save it to a PNG file, then exit the loop. +% \begin{macrocode} + plotfilename = os.path.join(self.plotdir, 'plot-{0}.{1}'.format(counter, fmt)) + try: + _p_.save(filename=plotfilename, **kwargs) + except ValueError as inst: + if re.match('filetype .*not supported by save', str(inst)): + newfilename = plotfilename[:-3] + 'png' + print(' saving {0} failed; saving to {1} instead.'.format( + plotfilename, newfilename)) + _p_.save(filename=newfilename, **kwargs) + break + else: + raise +% \end{macrocode} +% If the user provides a format \emph{and} specifies the |imagemagick| +% option, we try to convert the newly-created file into EPS format. +% \begin{macrocode} + if format != 'notprovided' and self.useimagemagick: + self.progress('Calling Imagemagick to convert plot-{0}.{1} to EPS'.format( + counter, format)) + self.toeps(counter, format) +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{toeps} +% This function calls the Imagmagick utility |convert| to, well, convert +% something into EPS format. This gets called when the user has +% requested the ``|imagemagick|'' option to the \ST\ style file and is +% making a graphic file with a nondefault extension. +% \begin{macrocode} + def toeps(self, counter, ext): + subprocess.check_call(['convert',\ + '{0}/plot-{1}.{2}'.format(self.plotdir, counter, ext), \ + '{0}/plot-{1}.eps'.format(self.plotdir, counter)]) +% \end{macrocode} +% We are blindly assuming that the |convert| command exists and will do +% the conversion for us; the |check_call| function raises an exception +% which, since all these calls get wrapped in try/excepts in the |.sage| +% file, should result in a reasonable error message if something strange +% happens. +% \end{macro} +% +% \begin{macro}{goboom} +% \phantomsection\label{macro:goboom} +% When a chunk of Sage code blows up, this function bears the bad news +% to the user. Normally in Python the traceback is good enough for +% this, but in this case, we start with a |.sage| file (which is +% autogenerated) which itself autogenerates a |.py| file---and the +% tracebacks the user sees refer to that file, whose line numbers are +% basically useless. We want to tell them where in the \LTX file +% things went bad, so we do that, give them the traceback, and exit +% after removing the |.sout.tmp| and |.scmd.tmp| file. +% \begin{macrocode} + def goboom(self, line): + print('\n**** Error in Sage code on line {0} of {1}.tex! Traceback\ + follows.'.format(line, self.filename)) + traceback.print_exc() + print('\n**** Running Sage on {0}.sage failed! Fix {0}.tex and try\ + again.'.format(self.filename)) + self.souttmp.close() + os.remove(self.filename + '.sagetex.sout.tmp') + self.scmdtmp.close() + os.remove(self.filename + '.sagetex.scmd.tmp') + sys.exit(int(1)) +% \end{macrocode} +% We use |int(1)| above to make sure |sys.exit| sees a Python integer; +% see +% \href{http://trac.sagemath.org/sage_trac/ticket/2861#comment:5}{ticket +% \#2861}. +% \changes{v2.0.2}{2008/04/21}{Make sure sys.exit sees a Python integer} +% \end{macro} +% +% \begin{macro}{endofdoc} +% \phantomsection\label{macro:endofdoc} +% When we're done processing, we have some cleanup tasks. We +% want to put the MD5 sum of the |.sage| file that produced the |.sout| +% file we're about to write into the |.sout| file, so that external +% programs that build \LTX documents can determine if they need to call Sage +% to update the |.sout| file. But there is a problem: we write line +% numbers to the |.sage| file so that we can provide useful error +% messages---but that means that adding non-\ST text to your +% source file will change the MD5 sum, and your program will think it +% needs to rerun Sage even though none of the actual \ST macros +% changed. +% +% How do we include line numbers for our error messages but still allow +% a program to discover a ``genuine'' change to the |.sage| file? +% +% The answer is to only find the MD5 sum of \emph{part} of the |.sage| +% file. By design, the source file line numbers only appear in (1) calls +% to |goboom|, (2) lines with |_st_.current_tex_line|, and (3) +% pause/unpause lines, so we will strip those lines out. What we do +% below is exactly equivalent to running +% \begin{center} +% \verb+egrep -v '^( _st_.goboom| ?_st_.current_tex_line|print(.SageT)' filename.sage | md5sum+ +% \end{center} +% in a shell. The included |run-sagetex-if-necessary| uses this +% mechanism to, well, only run Sage when necessary; see +% \autoref{sec:run-sagetex-if-necessary}. +% \begin{macrocode} + def endofdoc(self): + sagef = open(self.filename + '.sagetex.sage', 'r') + m = hashlib.md5() + for line in sagef: + if not line.startswith((" _st_.goboom", + "print('SageT", + "_st_.current_tex_line", + " _st_.current_tex_line")): + m.update(bytearray(line,'utf8')) +% \end{macrocode} +% (The |current_tex_line| thing appears twice because it may appear +% indented one space or not, depending on whether it's used before +% |blockbegin| or not.) +% \begin{macrocode} + s = '%' + m.hexdigest() + '% md5sum of corresponding .sage file\ + (minus "goboom", "current_tex_line", and pause/unpause lines)\n' + self.souttmp.write(s) + self.scmdtmp.write(s) +% \end{macrocode} +% Now, we do issue warnings to run Sage on the |.sage| file and an +% external program might look for those to detect the need to rerun +% Sage, but those warnings do not quite capture all situations. (If +% you've already produced the |.sout| file and change a |\sage| call, no +% warning will be issued since all the |\ref|s find a |\newlabel|.) +% Anyway, I think it's easier to grab an MD5 sum out of the end of the +% file than parse the output from running |latex| on your file. (The +% regular expression |^%[0-9a-f]{32}%| will find the MD5 sum. Note that +% there are percent signs on each side of the hex string.) +% +% Now we are done with the |.sout.tmp| file. Close it, rename it, and +% tell the user we're done. +% \begin{macrocode} + self.souttmp.close() + os.rename(self.filename + '.sagetex.sout.tmp', self.filename + '.sagetex.sout') + self.scmdtmp.close() + os.rename(self.filename + '.sagetex.scmd.tmp', self.filename + '.sagetex.scmd') + self.progress('Sage processing complete. Run LaTeX on {0}.tex again.'.format( + self.filename)) +% \end{macrocode} +% % \changes{v2.1.1}{2009/05/14}{Fix bug in finding md5 sum introduced by +% pause facility} +% \end{macro} + +% \endinput +%</python> +% Local Variables: +% mode: doctex +% TeX-master: "sagetex.dtx" +% End: diff --git a/macros/latex/contrib/sagetex/remote-sagetex.dtx b/macros/latex/contrib/sagetex/remote-sagetex.dtx new file mode 100644 index 0000000000..1460c1a69c --- /dev/null +++ b/macros/latex/contrib/sagetex/remote-sagetex.dtx @@ -0,0 +1,438 @@ +% \section{The \texttt{remote-sagetex} script} +% \label{sec:remote-sagetex-code} +% +% +% Here we describe the Python code for |remote-sagetex.py|. Since its +% job is to replicate the functionality of using Sage and |sagetex.py|, +% there is some overlap with the Python module. +% +% \iffalse +%<*remotesagetex> +% \fi +% +% The |#!/usr/bin/env python| line is provided for us by the |.ins| +% file's preamble, so we don't put it here. +% \begin{macrocode} +from __future__ import print_function +import json +import sys +import time +import re +import urllib +import hashlib +import os +import os.path +import shutil +import getopt +from contextlib import closing + +######################################################################### +# You can provide a filename here and the script will read your login # +# information from that file. The format must be: # +# # +# server = 'http://foo.com:8000' # +# username = 'my_name' # +# password = 's33krit' # +# # +# You can omit one or more of those lines, use " quotes, and put hash # +# marks at the beginning of a line for comments. Command-line args # +# take precedence over information from the file. # +######################################################################### +login_info_file = None # e.g. '/home/foo/Private/sagetex-login.txt' + + +usage = """Process a SageTeX-generated .sage file using a remote Sage server. + +Usage: {0} [options] inputfile.sage + +Options: + + -h, --help: print this message + -s, --server: the Sage server to contact + -u, --username: username on the server + -p, --password: your password + -f, --file: get login information from a file + +If the server does not begin with the four characters `http', then +`https://' will be prepended to the server name. + +You can hard-code the filename from which to read login information into +the remote-sagetex script. Command-line arguments take precedence over +the contents of that file. See the SageTeX documentation for formatting +details. + +If any of the server, username, and password are omitted, you will be +asked to provide them. + +See the SageTeX documentation for more details on usage and limitations +of remote-sagetex.""".format(sys.argv[0]) + +server, username, password = (None,) * 3 + +try: + opts, args = getopt.getopt(sys.argv[1:], 'hs:u:p:f:', + ['help', 'server=', 'user=', 'password=', 'file=']) +except getopt.GetoptError as err: + print(str(err), usage, sep='\n\n') + sys.exit(2) + +for o, a in opts: + if o in ('-h', '--help'): + print(usage) + sys.exit() + elif o in ('-s', '--server'): + server = a + elif o in ('-u', '--user'): + username = a + elif o in ('-p', '--password'): + password = a + elif o in ('-f', '--file'): + login_info_file = a + +if len(args) != 1: + print('Error: must specify exactly one file. Please specify options first.', + usage, sep='\n\n') + sys.exit(2) + +jobname = os.path.splitext(args[0])[0] +% \end{macrocode} +% When we send things to the server, we get everything back as a string, +% including tracebacks. We can search through output using regexps to +% look for typical traceback strings, but there's a more robust way: put +% in a special string that changes every time and is printed when +% there's an error, and look for that. Then it is massively unlikely +% that a user's code could produce output that we'll mistake for an +% actual traceback. System time will work well enough for these +% purposes. We produce this string now, and we it when parsing the +% |.sage| file (we insert it into code blocks) and when parsing the +% output that the remote server gives us. +% \begin{macrocode} +traceback_str = 'Exception in SageTeX session {0}:'.format(time.time()) +% \end{macrocode} +% \begin{macro}{parsedotsage} +% To figure out what commands to send the remote server, we actually +% read in the |.sage| file as strings and parse it. This seems a bit +% strange, but since we know exactly what the format of that file is, we +% can parse it with a couple flags and a handful of regexps. +% \begin{macrocode} +def parsedotsage(fn): + with open(fn, 'r') as f: +% \end{macrocode} +% Here are the regexps we use to snarf the interesting bits out of the +% |.sage| file. Below we'll use the |re| module's |match| function so we +% needn't anchor any of these at the beginning of the line. +% \begin{macrocode} + inline = re.compile(r" _st_.inline\((?P<num>\d+), (?P<code>.*)\)") + plot = re.compile(r" _st_.plot\((?P<num>\d+), (?P<code>.*)\)") + goboom = re.compile(r" _st_.goboom\((?P<num>\d+)\)") + pausemsg = re.compile(r"print.'(?P<msg>SageTeX (un)?paused.*)'") + blockbegin = re.compile(r"_st_.blockbegin\(\)") + ignore = re.compile(r"(try:)|(except):") + in_comment = False + in_block = False + cmds = [] +% \end{macrocode} +% Okay, let's go through the file. We're going to make a list of +% dictionaries. Each dictionary corresponds to something we have to do +% with the remote server, except for the pause/unpause ones, which we +% only use to print out information for the user. All the dictionaries +% have a |type| key, which obviously tells you type they are. The +% pause/unpause dictionaries then just have a |msg| which we toss out to +% the user. The ``real'' dictionaries all have the following keys: +% \begin{itemize} +% \item |type|: one of |inline|, |plot|, and |block|. +% \item |goboom|: used to help the user pinpoint errors, just like the +% |goboom| function (page \pageref{macro:goboom}) does. +% \item |code|: the code to be executed. +% \end{itemize} +% Additionally, the |inline| and |plot| dicts have a |num| key for the +% label we write to the |.sout| file. +% +% Here's the whole parser loop. The interesting bits are for parsing +% blocks because there we need to accumulate several lines of code. +% \begin{macrocode} + for line in f.readlines(): + if line.startswith('"""'): + in_comment = not in_comment + elif not in_comment: + m = pausemsg.match(line) + if m: + cmds.append({'type': 'pause', + 'msg': m.group('msg')}) + m = inline.match(line) + if m: + cmds.append({'type': 'inline', + 'num': m.group('num'), + 'code': m.group('code')}) + m = plot.match(line) + if m: + cmds.append({'type': 'plot', + 'num': m.group('num'), + 'code': m.group('code')}) +% \end{macrocode} +% The order of the next three ``if''s is important, since we need the +% ``goboom'' line and the ``blockbegin'' line to \emph{not} get included +% into the block's code. Note that the lines in the |.sage| file already +% have some indentation, which we'll use when sending the block to the +% server---we wrap the text in a try/except. +% \begin{macrocode} + m = goboom.match(line) + if m: + cmds[-1]['goboom'] = m.group('num') + if in_block: + in_block = False + if in_block and not ignore.match(line): + cmds[-1]['code'] += line + if blockbegin.match(line): + cmds.append({'type': 'block', + 'code': ''}) + in_block = True + return cmds +% \end{macrocode} +% \end{macro} +% Parsing the |.sage| file is simple enough so that we can write one +% function and just do it. Interacting with the remote server is a bit +% more complicated, and requires us to carry some state, so let's make a +% class. +% +% \begin{macro}{RemoteSage} +% \changes{v2.2.1}{2009/06/20}{Fix stupid bug in \texttt{do\_inline()} +% so that we actually write output to .sout file} +% +% This is pretty simple; it's more or less a translation of the examples +% in \texttt{sage/server/simple/twist.py}. +% \begin{macrocode} +debug = False +class RemoteSage: + def __init__(self, server, user, password): + self._srv = server.rstrip('/') + sep = '___S_A_G_E___' + self._response = re.compile('(?P<header>.*)' + sep + + '\n*(?P<output>.*)', re.DOTALL) + self._404 = re.compile('404 Not Found') + self._session = self._get_url('login', + urllib.urlencode({'username': user, + 'password': + password}))['session'] +% \end{macrocode} +% In the string below, we want to do ``partial formatting'': we format +% in the traceback string now, and want to be able to format in the code +% later. The double braces get ignored by |format()| now, and are picked +% up by |format()| when we use this later. +% \begin{macrocode} + self._codewrap = """try: +{{0}} +except: + print('{0}') + traceback.print_exc()""".format(traceback_str) + self.do_block(""" + import traceback + def __st_plot__(counter, _p_, format='notprovided', **kwargs): + if format == 'notprovided': + formats = ['eps', 'pdf'] + else: + formats = [format] + for fmt in formats: + plotfilename = 'plot-%s.%s' % (counter, fmt) + _p_.save(filename=plotfilename, **kwargs)""") + + def _encode(self, d): + return 'session={0}&'.format(self._session) + urllib.urlencode(d) + + def _get_url(self, action, u): + with closing(urllib.urlopen(self._srv + '/simple/' + action + + '?' + u)) as h: + data = self._response.match(h.read()) + result = json.loads(data.group('header')) + result['output'] = data.group('output').rstrip() + return result + + def _get_file(self, fn, cell, ofn=None): + with closing(urllib.urlopen(self._srv + '/simple/' + 'file' + '?' + + self._encode({'cell': cell, 'file': fn}))) as h: + myfn = ofn if ofn else fn + data = h.read() + if not self._404.search(data): + with open(myfn, 'w') as f: + f.write(data) + else: + print('Remote server reported {0} could not be found:'.format( + fn)) + print(data) +% \end{macrocode} +% The |code| below gets stuffed between a try/except, so make sure it's +% indented! +% \begin{macrocode} + def _do_cell(self, code): + realcode = self._codewrap.format(code) + result = self._get_url('compute', self._encode({'code': realcode})) + if result['status'] == 'computing': + cell = result['cell_id'] + while result['status'] == 'computing': + sys.stdout.write('working...') + sys.stdout.flush() + time.sleep(10) + result = self._get_url('status', self._encode({'cell': cell})) + if debug: + print('cell: <<<', realcode, '>>>', 'result: <<<', + result['output'], '>>>', sep='\n') + return result + + def do_inline(self, code): + return self._do_cell(' print(latex({0}))'.format(code)) + + def do_block(self, code): + result = self._do_cell(code) + for fn in result['files']: + self._get_file(fn, result['cell_id']) + return result + + def do_plot(self, num, code, plotdir): + result = self._do_cell(' __st_plot__({0}, {1})'.format(num, code)) + for fn in result['files']: + self._get_file(fn, result['cell_id'], os.path.join(plotdir, fn)) + return result +% \end{macrocode} +% When using the simple server API, it's important to log out so the +% server doesn't accumulate idle sessions that take up lots of memory. +% We define a |close()| method and use this class with the |closing| +% context manager that always calls |close()| on the way out. +% \begin{macrocode} + def close(self): + sys.stdout.write('Logging out of {0}...'.format(server)) + sys.stdout.flush() + self._get_url('logout', self._encode({})) + print('done') +% \end{macrocode} +% \end{macro} +% Next we have a little pile of miscellaneous functions and variables +% that we want to have at hand while doing our work. Note that we again +% use the traceback string in the error-finding regular expression. +% \begin{macrocode} +def do_plot_setup(plotdir): + printc('initializing plots directory...') + if os.path.isdir(plotdir): + shutil.rmtree(plotdir) + os.mkdir(plotdir) + return True + +did_plot_setup = False +plotdir = 'sage-plots-for-' + jobname + '.tex' + +def labelline(n, s): + return r'\newlabel{@sageinline' + str(n) + '}{{' + s + '}{}{}{}{}}\n' + +def printc(s): + print(s, end='') + sys.stdout.flush() + +error = re.compile("(^" + traceback_str + ")|(^Syntax Error:)", re.MULTILINE) + +def check_for_error(string, line): + if error.search(string): + print(""" +**** Error in Sage code on line {0} of {1}.tex! +{2} +**** Running Sage on {1}.sage failed! Fix {1}.tex and try again.""".format( + line, jobname, string)) + sys.exit(1) +% \end{macrocode} +% Now let's actually start doing stuff. +% \begin{macrocode} +print('Processing Sage code for {0}.tex using remote Sage server.'.format( + jobname)) + +if login_info_file: + with open(login_info_file, 'r') as f: + print('Reading login information from {0}.'.format(login_info_file)) + get_val = lambda x: x.split('=')[1].strip().strip('\'"') + for line in f: + print(line) + if not line.startswith('#'): + if line.startswith('server') and not server: + server = get_val(line) + if line.startswith('username') and not username: + username = get_val(line) + if line.startswith('password') and not password: + password = get_val(line) + +if not server: + server = raw_input('Enter server: ') + +if not server.startswith('http'): + server = 'https://' + server + +if not username: + username = raw_input('Enter username: ') + +if not password: + from getpass import getpass + password = getpass('Please enter password for user {0} on {1}: '.format( + username, server)) + +printc('Parsing {0}.sage...'.format(jobname)) +cmds = parsedotsage(jobname + '.sage') +print('done.') + +sout = '% This file was *autogenerated* from the file {0}.sage.\n'.format( + os.path.splitext(jobname)[0]) + +printc('Logging into {0} and starting session...'.format(server)) +with closing(RemoteSage(server, username, password)) as sage: + print('done.') + for cmd in cmds: + if cmd['type'] == 'inline': + printc('Inline formula {0}...'.format(cmd['num'])) + result = sage.do_inline(cmd['code']) + check_for_error(result['output'], cmd['goboom']) + sout += labelline(cmd['num'], result['output']) + print('done.') + if cmd['type'] == 'block': + printc('Code block begin...') + result = sage.do_block(cmd['code']) + check_for_error(result['output'], cmd['goboom']) + print('end.') + if cmd['type'] == 'plot': + printc('Plot {0}...'.format(cmd['num'])) + if not did_plot_setup: + did_plot_setup = do_plot_setup(plotdir) + result = sage.do_plot(cmd['num'], cmd['code'], plotdir) + check_for_error(result['output'], cmd['goboom']) + print('done.') + if cmd['type'] == 'pause': + print(cmd['msg']) + if int(time.time()) % 2280 == 0: + printc('Unscheduled offworld activation; closing iris...') + time.sleep(1) + print('end.') + +with open(jobname + '.sage', 'r') as sagef: + h = hashlib.md5() + for line in sagef: + if (not line.startswith(' _st_.goboom') and + not line.startswith("print('SageT")): + h.update(bytearray(line,'utf8')) +% \end{macrocode} +% Putting the |{1}| in the string, just to replace it with |%|, seems a +% bit weird, but if I put a single percent sign there, Docstrip won't +% put that line into the resulting |.py| file---and if I put two percent +% signs, it replaces them with |\MetaPrefix| which is |##| when this +% file is generated. This is a quick and easy workaround. +% \begin{macrocode} + sout += """%{0}% md5sum of corresponding .sage file +{1} (minus "goboom" and pause/unpause lines) +""".format(h.hexdigest(), '%') + +printc('Writing .sout file...') +with open(jobname + '.sout', 'w') as soutf: + soutf.write(sout) + print('done.') +print('Sage processing complete. Run LaTeX on {0}.tex again.'.format(jobname)) +% \end{macrocode} + +% \endinput +%</remotesagetex> +% Local Variables: +% mode: doctex +% TeX-master: "sagetex" +% End: diff --git a/macros/latex/contrib/sagetex/sagetex.dtx b/macros/latex/contrib/sagetex/sagetex.dtx new file mode 100644 index 0000000000..da0b7ff86a --- /dev/null +++ b/macros/latex/contrib/sagetex/sagetex.dtx @@ -0,0 +1,1225 @@ +% \iffalse meta-comment +% +% Copyright (C) 2008--2015 by Dan Drake <dr.dan.drake (at) gmail (dot) com> +% ------------------------------------------------------- +% +% See the "Copying and licenses" section in this file for the terms +% under which this source code and documentation may be modified and +% distributed. +% +% This package is not licensed under the LPPL, but it seems reasonable +% to say: +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainers of this work are Sagemath Developers. +% +% This work consists of the files sagetex.dtx, py-and-sty.dtx, +% scripts.dtx, remote-sagetex.dtx, sagetex.ins, example.tex, +% and the derived files sagetex.sty, sagetex.py, sagetexparse.py, +% makestatic.py, extractsagecode.py, and remote-sagetex.py. +% +% \fi +% +% \iffalse +%<*driver> +\ProvidesFile{sagetex.dtx} +%</driver> +%<latex>\NeedsTeXFormat{LaTeX2e} +%<latex>\ProvidesPackage{sagetex} +%<python>__version__ = """ +%<*latex|python> + [2019/01/09 v3.2 embedding Sage into LaTeX documents] +%</latex|python> +%<python>""".strip() +%<latex>\newcommand{\ST@ver}{2019/01/09 v3.2} +%<*driver> +\documentclass{ltxdoc} +\usepackage{sagetex} +\usepackage{xspace} +\usepackage{tikz} +\usepackage{hyperref} +% \iffalse +% Work around a problem with using Docstrip and hyperref; for macros and +% such described with DescribeMacro and friends, plain Docstrip puts +% something like this into the .idx file: +% +% \indexentry{sage=\verb!*+\sage+|usage}{5} +% +% and defines \usage{}. hyperref comes along and sneakily alters those +% lines and adds: +% +% \indexentry{sage=\verb!*+\sage+|usage|hyperpage}{5} +% +% and makeindex gets confused because you can't have two | things in one +% indexentry. I could probably figure out how to fix this in LaTeX, but +% it's easier to run sed on the .idx file to remove the extra | and +% define a new macro that makes the text italic and puts in the +% hyperlink. +% +% Another option is to forget about all this and just pass the +% hyperindex=false option to hyperref, but then you don't get +% hyperlinked page numbers. +% \fi +\newcommand{\usagehyperpage}[1]{\textit{\hyperpage{#1}}} + +\renewcommand{\subsubsectionautorefname}{section} +\renewcommand{\subsectionautorefname}{section} +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\begin{document} +\DocInput{sagetex.dtx} +\StopEventually{ +\section{Credits and acknowledgments} + +According to the original README file, this system was originally done +by Gonzalo Tornaria and Joe Wetherell. Later Harald Schilly made some +improvements and modifications. Many of the examples in the +|example.tex| file are from Harald. + +Dan Drake rewrote and extended the style file (there is effectively zero +original code there), made significant changes to the Python module, put +both files into \textsf{Docstrip} format, and wrote all the +documentation and extra Python scripts. + +Many thanks to Jason Grout for his numerous comments, suggestions, and +feedback. Thanks to Nicolas Thi\'ery for the initial code and +contributions to the \texttt{sageexample} environment and Volker Braun +for the \texttt{sagecommandline} environment. + +\section{Copying and licenses} +\label{sec:copying-licenses} + +If you are unnaturally curious about the current state of the \ST +package, you can visit \url{https://github.com/sagemath/sagetex}. (The +old Bitbucket and Github dandrake repositories are deprecated.) + +As for the terms and conditions under which you can copy and modify \ST: + +The \emph{source code} of the \ST package may be redistributed and/or +modified under the terms of the GNU General Public License as published +by the Free Software Foundation, either version 2 of the License, or (at +your option) any later version. To view a copy of this license, see +\url{http://www.gnu.org/licenses/} or send a letter to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +The \emph{documentation} of the \ST package is licensed under the +Creative Commons Attribution-Share Alike 3.0 License. To view a copy of +this license, visit \url{http://creativecommons.org/licenses/by-sa/3.0/} +or send a letter to Creative Commons, 171 Second Street, Suite 300, San +Francisco, California, 94105, USA. + +I am not terribly dogmatic about these licenses, so if you would like to +do something with \ST that's not possible under these license +conditions, please contact me. I will likely be receptive to +suggestions. + +\iffalse meta-comment + I've run into a situation where the index wants to start on the very + last line of the page, and I actually get errors: ``Package multicol + Error: Error saving partial page.'' The problem goes away if I fiddle + with some lines so that the index starts elsewhere. Putting in a + clearpage below makes the index start nicely in the middle of a page + (until my change history gets too long!) and solves all those + problems. It can be removed/pulled into this comment if you're + confident the page break problems won't occur. +\fi +\clearpage + +} + +\DocInput{py-and-sty.dtx} +\DocInput{scripts.dtx} +\DocInput{remote-sagetex.dtx} +\Finale +\PrintChanges +\PrintIndex +\end{document} +%</driver> +% \fi +% +% \changes{v1.0}{2008/03/03}{Initial version} +% \changes{v1.1}{2008/03/05}{Wrapped user-provided Sage code in +% try/except clauses; plotting now has optional format argument} +% \changes{v1.2}{2008/03/07}{Imagemagick option; better documentation} +% \changes{v1.3.1}{2008/03/10}{Internal variables renamed; fixed typos} +% \changes{v1.4}{2008/03/11}{MD5 fix, percent sign macro, CTAN upload} +% \changes{v2.0}{2008/12/16}{External Python scripts for parsing +% SageTeX-ified documents, tons of documentation improvements, +% sagetex.py refactored, include in Sage as spkg} +% \changes{v2.0}{2009/01/09}{Miscellaneous fixes, final 2.0 version} +% \changes{v2.1}{2009/05/12}{Add pausing support} +% \changes{v2.1}{2009/05/12}{Get version written to .py file} +% \changes{v2.2}{2009/06/17}{Add remote-sagetex.py script} +% \changes{v2.3}{2010/10/20}{Add sagecommandline environment} +% +% \GetFileInfo{sagetex.sty} +% +% \DoNotIndex{\newcommand,\newenvironment,\the} +% +% \newcommand{\ST}{\textsf{Sage\TeX}\xspace} +% \iffalse +% so I don't have to put \ or {} after \LaTeX: +% \fi +% \newcommand{\LTX}{\LaTeX\xspace} +% +% \newcommand{\TikZ}{Ti\emph{k}Z\xspace} +% +% \newcommand{\warningbox}[1]{\colorbox[rgb]{1, 0.6, 0.6}% +% {\parbox{.97\textwidth}{#1}}} +% +% \tikzstyle{box}=[draw, shape=rectangle, thick] +% +% \title{The \ST{} package\thanks{This document corresponds to +% \ST \fileversion, dated \filedate.}} +% +% \author{Dan Drake and others\thanks{Author's website: +% \href{http://mathsci.kaist.ac.kr/\textasciitilde drake/} +% {\texttt{mathsci.kaist.ac.kr/$\sim$drake/}}.}} +% +% \iffalse +% Don't put any other code from this file into the .sty or .py +% file: +%<*!latex&!python> +% This lets us use verbatim environments in the documentation. +% \fi +% +% \maketitle +% +% \section{Introduction} +% +% Why should the Haskell and R folks have all the fun? +% \href{http://www.haskell.org/haskellwiki/Literate_programming}{Literate +% Haskell} is a popular way to mix Haskell source code and \LTX +% documents. (Actually any kind of text or document, but here we're +% concerned only with \LTX.) You can even embed Haskell code in your +% document that writes part of your document for you. Similarly, the R +% statistical computing environment includes +% \href{http://tug.org/pracjourn/2008-1/zahn/}{Sweave}, which lets you +% do the same thing with R code and \LTX. +% +% The \ST package allows you to do (roughly) the same thing with the +% Sage mathematics software suite (see \url{http://sagemath.org}) and +% \LTX. (If you know how to write literate Haskell: the |\eval| command +% corresponds to |\sage|, and the |code| environment to the |sageblock| +% environment.) As a simple example, imagine in your document you are +% writing about how to count license plates with three letters and three +% digits. With this package, you can write something like this: +% \begin{quote} +% |There are $26$ choices for each letter, and $10$ choices for|\\ +% |each digit, for a total of $26^3 \cdot 10^3 =|\\ +% |\sage{26^3*10^3}$ license plates.| +% \end{quote} +% and it will produce +% \begin{quote} +% There are $26$ choices for each letter, and $10$ choices for each +% digit, for a total of $26^3 \cdot 10^3 = \sage{26^3 * 10^3}$ license +% plates. +% \end{quote} +% The great thing is, you don't have to do the multiplication. Sage does +% it for you. This process mirrors one of the great aspects of \LTX: +% when writing a \LTX document, you can concentrate on the logical +% structure of the document and trust \LTX and its army of packages to +% deal with the presentation and typesetting. Similarly, with \ST, you +% can concentrate on the mathematical structure (``I need the product of +% $26^3$ and $10^3$'') and let Sage deal with the base-$10$ presentation +% of the number. +% +% A less trivial, and perhaps more useful example is plotting. You can +% include a plot of the sine curve without manually producing a plot, +% saving an EPS or PDF file, and doing the |\includegraphics| business +% with the correct filename yourself. If you write this: +% \begin{quote} +% |Here is a lovely graph of the sine curve:| +% +% |\sageplot[width=.75\textwidth]{plot(sin(x), x, 0, 2*pi)}| +% \end{quote} +% in your \LTX file, it produces +% \begin{quote} +% Here is a lovely graph of the sine curve: +% +% \sageplot[width=.75\textwidth]{plot(sin(x), x, 0, 2*pi)} +% \end{quote} +% Again, you need only worry about the logical/mathematical structure of +% your document (``I need a plot of the sine curve over the interval +% $[0, 2\pi]$ here''), while \ST{} takes care of the gritty details of +% producing the file and sourcing it into your document. +% +% \paragraph{But \texttt{\bslash sageplot} isn't magic} I just tried to +% convince you that \ST makes putting nice graphics into your document +% very easy; let me turn around and warn you that using graphics +% \emph{well} is not easy, and no \LTX package or Python script will +% ever make it easy. What \ST does is make it easy to \emph{use Sage} to +% create graphics; it doesn't magically make your graphics good, +% appropriate, or useful. (For instance, look at the sine plot above---I +% would say that a truly lovely plot of the sine curve would not mark +% integer points on the $x$-axis, but rather $\pi/2$, $\pi$, $3\pi/2$, +% and $2\pi$. Incidentally, you can do this in Sage: do +% |sage.plot.plot?| and look for |ticks| and |tick_formatter|.) +% +% Till Tantau has some good commentary on the use of graphics in the +% \href{http://www.ctan.org/tex-archive/help/Catalogue/entries/pgf.html}{``Guidelines +% on Graphics'' section of the \textsc{pgf} manual} (chapter 7 of the +% manual for version 2.10). You should always give careful thought and +% attention to creating graphics for your document; I have in mind that +% a good workflow for using \ST for plotting is something like this: +% +% \begin{enumerate} +% \item Figure out what sort of graphic you need to communicate your +% ideas or information. +% \item Fiddle around in Sage until you get a graphics object and set +% of options that produce the graphic you need. +% \item Copy those commands and options into \ST commands in your +% \LTX document. +% \end{enumerate} +% +% The \ST{} package's plotting capabilities don't help you find those +% Sage commands to make your lovely plot, but they do eliminate the need +% to muck around with saving the result to a file, remembering the +% filename, including it into your document, and so on. In +% \autoref{sec:usage}, we will see what what we can do with \ST. +% +% +% \section{Installation} +% \label{sec:installation} +% \changes{v2.0}{2009/01/14}{Fixed up installation section, final +% \emph{final} 2.0} +% \changes{v2.2.3}{2009/12/29}{Rewrote installation section to reflect +% inclusion as standard spkg} +% +% \newcommand{\sageroot}{\$SAGE\_ROOT} +% +% \ST needs two parts to work: a Python module known to Sage, and a \LTX +% package known to \TeX. These two parts need to come from the same +% version of \ST to guarantee that everything works properly. As of Sage +% version 4.3.1, \ST comes included with Sage, so you only need to make +% \texttt{sagetex.sty}, the \LTX package, known to \TeX. Full details of +% this are in the Sage tutorial at +% \href{http://doc.sagemath.org/html/en/tutorial/sagetex.html}{\texttt{doc.sagemath.org/html/en/tutorial/sagetex.html}} +% in the obviously-named section ``Make \ST known to \TeX''. Here's a +% brief summary of how to do that: +% +% \begin{itemize} +% \item Copy \texttt{sagetex.sty} to the same directory as your +% document. This always works, but requires lots of copies of +% \texttt{sagetex.sty} and is prone to version skew. +% +% \item Copy the directory containing \texttt{sagetex.sty} to your home +% directory with a command like +% \begin{quotation} +% \texttt{cp -R \sageroot/local/share/texmf \textasciitilde/} +% \end{quotation} +% where \texttt{\sageroot} is replaced with the location of your +% Sage installation. +% +% \item Use the environment variable \texttt{TEXINPUTS} to tell \TeX{} +% to search the directory containing \texttt{sagetex.sty}; in the bash +% shell, you can do +% \begin{quotation} +% \texttt{export TEXINPUTS=\sageroot/local/share/texmf//:} +% \end{quotation} +% You should again replace \texttt{\sageroot} with the location of +% your Sage installation. +% \end{itemize} +% +% The best method is likely the second; while that does require you to +% recopy the files every time you update your copy of Sage, it does not +% depend on your shell, so if you use, say, Emacs with Auc\TeX{} or some +% other editor environment, everything will still work since \TeX's +% internal path-searching mechanisms can find \texttt{sagetex.sty}. +% +% Note that along with \texttt{sagetex.sty}, this documentation, an +% example file, and other useful scripts are all located in the +% directory \texttt{\sageroot/local/share/texmf}. +% +% \subsection{\ST and \TeX Live} +% +% \ST was included in \TeX Live, which seemed nice, except that the Python +% module and \LTX package for \ST need to be synchronized and the Python +% module in Sage was much easier to update than the \LTX style file in +% \TeX Live. If you are so unlucky as to be using a version of \TeX Live +% that includes \ST, I strongly recommend using \ST only from what is +% included with Sage and ignoring what's included with \TeX Live. +% +% \subsection{The noversioncheck option} +% \label{sec:noversioncheck} +% +% As of version 2.2.4, \ST automatically checks to see if the versions +% of the style file and Python module match. This is intended to prevent +% strange version mismatch problems, but if you would like to use +% mismatched sources, you can---at your peril---give the +% |noversioncheck| option when you load the \ST package. Don't be +% surprised if things don't work when you do this. +% +% If you are considering using this option because the Sage script +% complained and exited, you really should just get the \LTX and Python +% modules synchronized. Every copy of Sage since version 4.3.2 comes +% with a copy of |sagetex.sty| that is matched up to Sage's baked-in \ST +% support, so you can always use that. See the +% \href{http://doc.sagemath.org/html/en/tutorial/sagetex.html}{\ST section of the Sage +% tutorial}. +% +% \subsection{Using \TeX Shop} +% \label{sec:using-texshop} +% \changes{v2.0.1}{2009/03/10}{Add \TeX Shop info} +% +% Starting with version 2.25, +% \href{http://www.uoregon.edu/~koch/texshop/}{\TeX Shop} includes +% support for \ST. If you move the file |sage.engine| from +% |~/Library/TeXShop/Engines/Inactive/Sage| to +% |~/Library/TeXShop/Engines| and put the line +% \begin{quotation} +% |%!TEX TS-program = sage| +% \end{quotation} +% at the top of your document, then \TeX Shop will automatically run Sage +% for you when compiling your document. +% +% Note that you will need to make sure that \LTX can find |sagetex.sty| +% using any of the methods above. You also might need to edit the +% |sage.engine| script to reflect the location of your Sage +% installation. \TeX Shop includes further documentation in the +% |~/Library/TeXShop/Engines/Inactive/Sage| folder; be sure to check out +% the ``About Sage'' PDF there, which has good advice on setting up +% things so that typesetting \ST-ified documents works automatically, +% and so that it continues to work when you upgrade your Sage +% installation. +% +% \subsection{Other scripts included with \ST} +% \label{sec:inst-other-scripts} +% +% \ST includes several Python files which may be useful for working with +% ``\ST-ified'' documents. At this point they have likely bitrotted but +% are, for now, included for archaeological purposes. +% +% The |remote-sagetex.py| script allows you to use \ST on a computer +% that doesn't have Sage installed; see \autoref{sec:remote-sagetex} for +% more information. +% +% Also included are |makestatic.py| and |extractsagecode.py|, which are +% convenience scripts that you can use after you've written your +% document. See \autoref{sec:makestatic-usage} and +% \autoref{sec:extractsagecode} for information on using those scripts. +% The file |sagetexparse.py| is a module used by both those scripts. +% These three files are independent of \ST. If you install from a spkg, +% these scripts can be found in \texttt{\sageroot/local/share/texmf/}. +% +% \section{Usage} +% \label{sec:usage} +% +% Let's begin with a rough description of how \ST works. Naturally the +% very first step is to put |\usepackage{sagetex}| in the preamble of +% your document. When you use macros from this package and run \LTX on +% your file, along with the usual zoo of auxiliary files, a |.sage| file +% is written with the same basename as your document. This is a Sage +% source file that uses the Python module from this package and when you +% run Sage on that file, it will produce a |.sout| and a |.scmd| file. +% The |.sout| file contains \LTX code that, when you run \LTX on your +% source file again, will pull in all the results of Sage's computation. +% +% The |sagecommandline| environment additionally logs the plain sage +% commands and output furthermore in a |.scmd| file. +% +% All you really need to know is that to typeset your document, you need +% to run \LTX, then run Sage, then run \LTX again. +% +% Also keep in mind that everything you send to Sage is done within one +% Sage session. This means you can define variables and reuse them +% throughout your \LTX document; if you tell Sage that |foo| is +% $12$, then anytime afterwards you can use |foo| in your Sage code and +% Sage will remember that it's $12$---just like in a regular Sage +% session. +% +% Now that you know that, let's describe what macros \ST provides and +% how to use them. If you are the sort of person who can't be bothered +% to read documentation until something goes wrong, you can also just +% look through the |example.tex| file included with this +% package.\footnote{Then again, if you're such a person, you're probably +% not reading this, and are already fiddling with +% \texttt{example.tex}\dots}\\ +% +% \noindent\warningbox{\textbf{WARNING!} When you run \LTX on a file +% named \texttt{\meta{filename}.tex}, the file +% \texttt{\meta{filename}.sagetex.sage} is created---and will be +% \emph{automatically overwritten} if it already exists. If you keep +% Sage scripts in the same directory as your \ST-ified \LTX documents, +% use a different file name!} +% +% \noindent\warningbox{\textbf{WARNING!} Speaking of filenames, \ST +% really works best on files whose names don't have spaces or other +% ``funny'' characters in them. \ST \emph{should} work on such +% files---and you should let us know if it doesn't---but it's safest +% to stick to files with alphanumeric characters and ``safe'' +% punctuation (i.e., nothing like |<|, |"|, |!|, +% \texttt{\bslash}, or other characters that would confuse a +% shell).} +% +% \paragraph{The final option} On a similar note, \ST, like many \LTX +% packages, accepts the |final| option. When passed this option, either +% directly in the |\usepackage| line, or from the |\documentclass| line, +% \ST will not write a |.sage| file. It will try to read in the |.sout| +% file so that the \ST macros can pull in their results. However, this +% will not allow you to have an independent Sage script with the same +% basename as your document, since to get the |.sout| file, you need the +% |.sage| file. +% +% \subsection{Inline Sage} +% \label{sec:sagemacro-usage} +% +% \DescribeMacro{sage} +% \fbox{\texttt{\bslash sage}\marg{Sage code}} +% takes whatever Sage code you give it, runs Sage's |latex| function on +% it, and puts the result into your document. +% +% For example, if you do |\sage{matrix([[1, 2], [3,4]])^2}|, then that +% macro will get replaced by +% \begin{quote} +% |\left(\begin{array}{rr}|\\ +% |7 & 10 \\|\\ +% |15 & 22|\\ +% |\end{array}\right)| +% \end{quote} +% in your document---that \LTX code is exactly exactly what you get +% from doing +% \begin{center} +% |latex(matrix([[1, 2], [3,4]])^2)| +% \end{center} +% in Sage. +% +% Note that since \LTX will do macro expansion on whatever you give +% to |\sage|, you can mix \LTX variables and Sage variables! If +% you have defined the Sage variable |foo| to be $12$ (using, say, the +% |sageblock| environment), then you can do something like this: +% \begin{quote} +% |The prime factorization of the current page number plus foo|\\ +% |is $\sage{factor(foo + \thepage)}$|. +% \end{quote} +% +% Here, I'll do just that right now: the prime factorization of the +% current page number plus $12$ is $\sage{factor(\thepage + 12)}$. +% (Wrong answer? See footnote.\footnote{Is the above factorization +% wrong? If the current page number plus $12$ is one larger than the +% claimed factorization, another Sage/\LTX cycle on this source file +% should fix it. Why? The first time you run \LTX on this file, the +% sine graph isn't available, so the text where I've talked about the +% prime factorization is back one page. Then you run Sage, and it +% creates the sine graph and does the factorization. When you run \LTX +% again, the sine graph pushes the text onto the next page, but it +% uses the Sage-computed value from the previous page. Meanwhile, the +% |.sage| file has been rewritten with the correct page number, so if +% you do another Sage/\LTX cycle, you should get the correct value +% above. However, in some cases, even \emph{that} doesn't work because +% of some kind of \TeX{} weirdness in ending the one page a bit short +% and starting another.}) The |\sage| command doesn't automatically +% use math mode for its output, so be sure to use dollar signs or a +% displayed math environment +% as appropriate.\\ +% +% \DescribeMacro{\sagestr} +% \fbox{\texttt{\bslash sagestr}\marg{Sage code}} +% is identical to |\sage|, but is does \emph{not} run Sage's |latex| +% function on the code you give it; it simply runs the Sage code and +% pulls the result into your \LTX file. This is useful for calling +% functions that return \LTX code; see the example file distributed +% along with \ST for a demonstration of using this command to easily +% produce a table. +% +% \DescribeMacro{\percent} If you are doing modular arithmetic or string +% formatting and need a percent sign in a call to |\sage| (or +% |\sageplot|), you can use |\percent|. Using a bare percent sign won't +% work because \LTX will think you're starting a comment and get +% confused; prefixing the percent sign with a backslash won't work +% because then ``|\%|'' will be written to the |.sage| file and Sage +% will get confused. The |\percent| macro makes everyone happy. +% +% Note that using |\percent| inside the verbatim-like environments +% described in \autoref{sec:codeblockenv} isn't necessary; a literal +% ``\percent'' inside such an environment will get written, uh, verbatim +% to the |.sage| file. +% +% \paragraph{Arguments with side effects} +% +% Be careful when feeding |\sage| and |\sagestr| arguments that have +% side effects, since in some situations they can get evaluated more +% than once; see section \ref{sec:sage-inside-align}. +% +% +% \subsection{Graphics and plotting} +% \label{sec:graphics-plotting} +% +% \noindent \DescribeMacro{\sageplot} +% \fbox{\texttt{\bslash sageplot}\oarg{ltx opts}\oarg{fmt}\{\meta{graphics +% obj}, \meta{keyword args}\}} +% plots the given Sage graphics object and runs an +% |\includegraphics| command to put it into your document. It does not +% have to actually be a plot of a function; it can be any Sage graphics +% object. The options are described in \autoref{t:sageplotopts}. +% +% \begin{table}[h] +% \centering +% \begin{tabular}{l p{8cm}} +% Option & Description \\ +% \hline +% \meta{ltx options} & Any text here is passed directly into the +% optional arguments (between the square brackets) of an +% |\includegraphics| command.\\ +% \meta{fmt} & You can optionally specify a file extension here; Sage +% will then try to save the graphics object to a file with extension +% \emph{fmt}. If not specified, \ST\ will save to EPS and PDF files; +% if saving to those formats does not work, \ST will save to a PNG file.\\ +% \meta{graphics obj} & A Sage object on which you can call |.save()| +% with a graphics filename.\\ +% \meta{keyword args} & Any keyword arguments you put here will +% all be put into the call to |.save()|. +% \end{tabular} +% \caption{Explanation of options for the \texttt{\bslash sageplot} +% command.} +% \label{t:sageplotopts} +% \end{table} +% +% This setup allows you to control both the Sage side of things, and the +% \LTX side. For instance, the command +% \begin{quote} +% |\sageplot[angle=30, width=5cm]{plot(sin(x), 0, pi), axes=False,|\\ +% |chocolate=True}| +% \end{quote} +% will run the following command in Sage: +% \begin{quote} +% |sage: plot(sin(x), 0, pi).save(filename=autogen, axes=False,|\\ +% |chocolate=True)| +% \end{quote} +% Then, in your \LTX file, the following command will be issued +% automatically: +% \begin{center} +% |\includegraphics[angle=30, width=5cm]{autogen}| +% \end{center} +% You can specify a file format if you like. This must be the +% \emph{second} optional argument, so you must use empty brackets if +% you're not passing anything to |\includegraphics|: +% \begin{center} +% |\sageplot[][png]{plot(sin(x), x, 0, pi)}| +% \end{center} +% The filename is automatically generated, and unless you specify a +% format, both EPS and PDF files will be generated. This allows you to +% freely switch between using, say, a DVI viewer (many of which have +% support for automatic reloading, source specials and make the writing +% process easier) and creating PDFs for posting on the web or emailing +% to colleagues. \ST will fall back to creating a PNG file for any +% graphics object that cannot be saved as an EPS or PDF file; this is +% useful for three dimensional plot objects, which currently cannot be +% saved as EPS or PDF files. +% +% If you ask for, say, a PNG file (or if one is automatically generated +% for you as described above), keep in mind that ordinary |latex| and +% DVI files have no support for PNG files; \ST detects this and will +% warn you that it cannot find a suitable file if using +% |latex|.\footnote{We use a typewriter font here to indicate the +% executables which produce DVI and PDF files, respectively, as +% opposed to ``\LTX'' which refers to the entire typesetting system.} +% If you use |pdflatex|, there will be no problems because PDF files can +% include PNG graphics. +% +% When \ST cannot find a graphics file, it inserts this into your +% document: +% +% \begin{center} +% \framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}} +% \end{center} +% +% \noindent That's supposed to resemble the image-not-found graphics +% used by web browsers and use the traditional ``\textbf{??}'' that \LTX +% uses to indicate missing references. +% +% You needn't worry about the filenames; they are automatically +% generated and will be put into the directory +% |sage-plots-for-filename.tex|. You can safely delete that directory +% anytime; if \ST can't find the files, it will warn you to run Sage to +% regenerate them.\\ +% +% \noindent\warningbox{\textbf{WARNING!} When you run Sage on your +% |.sage| file, all files in the +% \texttt{sage-plots-for-\meta{filename}.tex} directory \emph{will be +% deleted!} Do not put any files into that directory that you do not +% want to get automatically deleted.} +% +% \paragraph{The epstopdf option} One of the graphics-related options +% supported by \ST is |epstopdf|. This option causes \ST to use the +% |epstopdf| command to convert EPS files into PDF files. Like with the +% |imagemagick| option, it doesn't check to see if the |epstopdf| +% command exists or add options: it just runs the command. This option +% was motivated by a bug in the matplotlib PDF backend which caused it +% to create invalid PDFs. Ideally, this option should never be +% necessary; if you do need to use it, file a bug! +% +% This option will eventually be removed, so do not use it. +% +% \subsubsection{3D plotting} +% +% Right now there is, to put it nicely, a bit of tension between the +% sort of graphics formats supported by |latex| and |pdflatex|, and the +% graphics formats supported by Sage's 3D plotting systems. \LTX is +% happiest, and produces the best output, with EPS and PDF files, which +% are vector formats. Tachyon, Sage's 3D plotting system, produces +% bitmap formats like BMP and PNG. +% +% \ST will automatically fall back to saving plot objects in PNG format +% if saving to EPS and PDF fails, so it should automatically work with +% 3D plot objects. However, since |latex| does not support PNGs, when +% using 3D plotting (and therefore a bitmap format like PNG), \ST will +% always issue a warning about incompatible graphics if you use |latex|, +% provided you've processed the |.sage| file and the PNG file exists. +% The only exception is if you're using the |imagemagick| option below. +% +% \paragraph{The imagemagick option} As a response to the above issue, +% the \ST package has an |imagemagick| option. If you specify this +% option in the preamble of your document with the usual +% ``|\usepackage[imagemagick]{sagetex}|'', then when you are compiling +% your document using |latex|, any |\sageplot| command which requests a +% non-default format will cause the \ST Python script to convert the +% resulting file to EPS using the Imagemagick |convert| utility. It does +% this by executing ``|convert filename.EXT filename.eps|'' in a +% subshell. It doesn't add any options, check to see if the |convert| +% command exists or belongs to Imagemagick---it just runs the command. +% +% The resulting EPS files are not very high quality, but they will work. +% This option is not intended to produce good graphics, but to allow you +% to see your graphics when you use |latex| and DVI files while writing +% your document. +% +% \subsubsection{But that's not good enough!} +% \label{sec:notgoodenough} +% +% The |\sageplot| command tries to be both flexible and easy to use, but +% if you are just not happy with it, you can always do things manually: +% inside a |sagesilent| environment (see the next section) you could do +% \begin{quote} +% |your special commands|\\ +% |x = your graphics object|\\ +% |x.save(filename=myspecialfile.ext, options, etc)| +% \end{quote} +% and then, in your source file, do your own |\includegraphics| command. +% The \ST package gives you full access to Sage and Python and doesn't +% turn off anything in \LTX, so you can always do things manually. +% +% \subsection{Verbatim-like environments} +% \label{sec:codeblockenv} +% +% The \ST package provides several environments for typesetting and +% executing blocks of Sage code.\\ +% +% \DescribeEnv{sageblock} Any text between |\begin{sageblock}| and +% |\end{sageblock}| will be typeset into your file, and also written into +% the |.sage| file for execution. This means you can do something like +% this: +% \begin{quote} +% |\begin{sageblock}|\\ +% | var('x')|\\ +% | f(x) = sin(x) - 1|\\ +% | g(x) = log(x)|\\ +% | h(x) = diff(f(x) * g(x), x)|\\ +% |\end{sageblock}| +% \end{quote} +% and then anytime later write in your source file +% \begin{quote} +% |We have $h(2) = \sage{h(2)}$, where $h$ is the derivative of|\\ +% |the product of $f$ and $g$.| +% \end{quote} +% and the |\sage| call will get correctly replaced by $\sage{ +% diff((sin(x) - 1)*log(x), x)(x=1)}$. You can use any Sage or Python +% commands inside a |sageblock|; all the commands get sent directly to +% Sage.\\ +% +% \iffalse meta-comment +% Sadly, we can't use sageblock or similar environments in this file! +% If you prefix the lines inside the environment with percent signs, +% then those percent signs get written to your .sage file. If you +% *don't* prefix the lines with percent signs, those lines get written +% into the .sty or .py file. It's just too tricky to get docstrip and +% the verbatim stuff to play nicely together. I'd have to redefine how +% those environments work, and get them to strip off initial percents. +% \fi +% +% \DescribeEnv{sagesilent} This environment is like |sageblock|, but it +% does not typeset any of the code; it just writes it to the |.sage| +% file. This is useful if you have to do some setup in Sage that is not +% interesting or relevant to the document you are writing.\\ +% +% \DescribeEnv{sageverbatim} This environment is the opposite of the one +% above: whatever you type will be typeset, but not written into the +% |.sage| file. This allows you to typeset psuedocode, code that will +% fail, or take too much time to execute, or whatever.\\ +% +% \DescribeEnv{comment} Logically, we now need an environment that +% neither typesets nor executes your Sage code\ldots but the |verbatim| +% package, which is always loaded when using \ST, provides such an +% environment: |comment|. Another way to do this is to put stuff between +% |\iffalse| and |\fi|.\\ +% +% \DescribeMacro{\sagetexindent} There is one final bit to our +% verbatim-like environments: the indentation. The \ST package defines a +% length |\sagetexindent|, which controls how much the Sage code is +% indented when typeset. You can change this length however you like +% with |\setlength|: do |\setlength{\sagetexindent}{6ex}| or whatever. +% +% \DescribeEnv{sageexample} This environment allow you to include +% doctest-like snippets in your document that will be nicely typeset. +% For example, +% \begin{quote} +% |\begin{sageexample}|\\ +% | sage: 1+1|\\ +% | 2|\\ +% | sage: factor(x^2 + 2*x + 1)|\\ +% | (x + 1)^2|\\ +% |\end{sageexample}| +% \end{quote} +% in your document will be typeset with the Sage inputs in the usual +% fixed-width font, and the outputs will be typeset as if given to a +% |\sage| macro, as you see below: +\begin{sageexample} + sage: 1+1 + 2 + sage: factor(x^2 + 2*x + 1) + (x + 1)^2 +\end{sageexample} +% When typesetting the document, there is no test of the +% validity of the outputs (that is, typesetting with a typical +% \LTX-Sage-\LTX cycle does not do doctesting), but when using the +% |sageexample| environment, an extra file named +% ``|myfile_doctest.sage|'' is created with the contents of all those +% environments; it is formatted so that Sage can doctest that file. You +% should be able to doctest your document with ``|sage -t myfile_doctest.sage|''. +% (This does not always work; if this fails for you, please contact +% the sage-support group.) +% +% If you would like to see both the original text input and the +% typeset output, you can issue +% |\renewcommand{\sageexampleincludetextoutput}{True}| in your +% document. You can do the same thing with ``False'' to later turn it +% off. In the above example, this would cause \ST to output both +% |(x + 1)^2| and $(x + 1)^{2}$ in your typeset document. +% +% Just as in doctests, multiline statements are acceptable. The only +% limitation is that triple-quoted strings delimited by |"""| cannot be +% used in a |sageexample| environment; instead, you can use +% triple-quoted strings delimited by |'''|. +% +% See the |example.tex| file for many examples and more explanation. +% +% The initial implementation of this environment is due to Nicolas M. +% Thi\'ery.\\ +% +% \DescribeEnv{sagecommandline} This environment is similar to the +% sageexample environment in that it allow you to use \ST as a +% pretty-printing command line, or to include doctest-like snippets in +% your document. The difference is that the output is typeset as text, +% much like running Sage on the command line, using the +% |lstlisting| environment. In particular, this environment +% provides Python syntax highlighting and line numbers. For example, +% \begin{quote} +% |\begin{sagecommandline}|\\ +% | sage: 1+1|\\ +% | 2|\\ +% | sage: factor(x^2 + 2*x + 1)|\\ +% |\end{sagecommandline}| +% \end{quote} +% becomes +\begin{sagecommandline} + sage: 1+1 + 2 + sage: factor(x^2 + 2*x + 1) +\end{sagecommandline} +% You have a choice of either explicitly providing the Sage output or +% leaving it up to the computer to fill in the blanks. Above, the output +% for $1+1$ was provided, but the output for the |factor()| command +% wasn't. Moreover, any Sage comment that starts with a ``at'' sign is +% escaped to \LTX. In particular, you can use |\label| to mark line +% numbers in order to |\ref|erence and |\pageref|erence them as usual. +% See the example file to see this mechanism in action. +% +% If you prefer to typeset the output in \LTX, you can set +% \begin{quote} +% |\renewcommand{\sagecommandlinetextoutput}{False}| +% \end{quote} +% which produces +\renewcommand{\sagecommandlinetextoutput}{False} +\begin{sagecommandline} + sage: var('a, b, c'); + sage: ( a*x^2+b*x+c ).solve(x) +\end{sagecommandline} +\renewcommand{\sagecommandlinetextoutput}{True} +% The Sage input and output is typeset using the |listings| package +% with the styles |SageInput| and |SageOutput|, respectively. If you +% don't like the defaults you can change them. It is recommended to +% derive from |DefaultSageInput| and |DefaultSageOutput|, for example +% \begin{quote} +% |\lstdefinestyle{SageInput}{style=DefaultSageInput,|\\ +% | basicstyle={\color{red}}}|\\ +% |\lstdefinestyle{SageOutput}{style=DefaultSageOutput,|\\ +% | basicstyle={\color{green}}}| +% \end{quote} +% makes things overly colorful: +\lstdefinestyle{SageInput}{style=DefaultSageInput,basicstyle={\color{red}}} +\lstdefinestyle{SageOutput}{style=DefaultSageOutput,basicstyle={\color{green}}} +\begin{sagecommandline} + sage: pi.n(100) +\end{sagecommandline} +\lstdefinestyle{SageInput}{style=DefaultSageInput} +\lstdefinestyle{SageOutput}{style=DefaultSageOutput} +% +% \subsection{Pausing \ST} +% \label{sec:pausing-st-usage} +% +% Sometimes when you are writing a document, you may wish to temporarily +% turn off or pause \ST to concentrate more on your document than on the +% Sage computations, or to simply have your document typeset faster. You +% can do this with the following commands. +% +% \DescribeMacro{\sagetexpause} \DescribeMacro{\sagetexunpause} Use +% these macros to ``pause'' and ``unpause'' \ST. After issuing this +% macro, \ST will simply skip over the corresponding calculations. +% Anywhere a |\sage| macro is used while paused, you will simply see +% \sagetexpause ``\sage{dummy call to sage to illustrate +% pausing}'', and anywhere a |\sageplot| macro is used, you will see:\\ +% +% \noindent +% \sageplot{dummy call to sageplot to illustrate pausing} +% \sagetexunpause\\ +% +% \noindent Anything in the verbatim-like environments of +% \autoref{sec:codeblockenv} will be typeset or not as usual, but none +% of the Sage code will be executed. +% +% Obviously, you use |\sagetexunpause| to unpause \ST and return to the +% usual state of affairs. Both commands are idempotent; issuing them +% twice or more in a row is the same as issuing them once. This means +% you don't need to precisely match pause and unpause commands: once +% paused, \ST stays paused until it sees |\sagetexunpause| and +% vice versa. +% +% \section{Other notes} +% +% Here are some other notes on using \ST. +% +% \subsection{Using the \texttt{sage} macro inside align (and similar) environments} +% \label{sec:sage-inside-align} +% +% The |align|, |align*|, and some other ``fancy'' math environments in +% the |amsmath| package do some special processing---in particular, they +% evaluate everything inside twice. This means that if you use |\sage| +% or |\sagestr| inside such an environment, it will be evaluated twice, +% and its argument will be put into the generated |.sage| file +% twice---and if that argument has side effects, those side effects will +% be executed twice! Doing something such as popping an element from a +% list will actually pop \emph{two} elements and typeset the second. The +% solution is to do any processing that has side effects before the +% |align| environment (in a |sagesilent| environment, say) and to give +% |\sage| or |\sagestr| an argument with no side effects. +% +% Thanks to Bruno Le Floch for reporting this. +% +% +% \subsection{Using \texttt{sage} inside \texttt{caption}} +% \label{sec:sage-inside-caption} +% +% If you want to use |\sage| inside the |\caption| for a figure, you'll +% need to prepend it with |\protect|, because (in \TeX{} parlance) the +% |\sage| macro is not ``robust''. For example: +% \begin{quote} +% |\caption{this figure illustrates why $2 + 2 = \protect\sage{2 + 2}$.}| +% \end{quote} +% +% \subsection{Using \ST with TeXworks} +% +% On Linux and OS X, it's easy to get the +% \href{https://www.tug.org/texworks/}{\TeX works} editor to work with +% \ST. You will define a new ``typesetting engine'' following +% \href{https://github.com/TeXworks/texworks/wiki/AdvancedTypesettingTools#defining-new-typesetting-tools}{these +% directions}. First, in some convenient location, create a shell +% script with these contents: +% \begin{quote} +% |#!/bin/sh|\\ +% |pdflatex $1.tex|\\ +% |sage $1.sagetex.sage|\\ +% |pdflatex $1.tex| +% \end{quote} +% Name it \texttt{sagetex-engine} or something similar. Then, in the +% Edit $\to$ Preferences menu, click the $+$ button in the Processing +% tools section. Give the new tool a good name, like ``SageTeX''. In the +% Program space, browse to your script. Click the $+$ for the Arguments +% and type \texttt{\$basename} in the resulting box. +% +% Then, back in your document, you should be able to select SageTex in +% the typesetting engine dropdown menu and then typeset. +% +% (You can also replace "|sage|" above with the +% |run-sagetex-if-necessary| script---see +% \autoref{sec:run-sagetex-if-necessary}.) +% +% \subsection{Using Beamer} +% +% The \textsc{beamer} package does not play nicely with verbatim-like +% environments unless you ask it to. To use code block environments in a +% \textsc{beamer} presentation, do: +% \begin{quote} +% |\begin{frame}[fragile]|\\ +% |\begin{sageblock}|\\ +% |# sage stuff|\\ +% |# more stuff \end{sageblock}|\\ +% |\end{frame}|\\ +% \end{quote} +% For some reason, \textsc{beamer} inserts an extra line break at the +% end of the environment; if you put the |\end{sageblock}| on the same +% line as the last line of your code, it works properly. See section +% 12.9, ``Verbatim and Fragile Text'', in the \textsc{beamer} manual. +% (Thanks to Franco Saliola for reporting this.) +% +% \textsc{beamer}'s overlays and |\sageplot| also need some help in +% order to work together, as discussed in +% \href{http://groups.google.com/group/sage-support/browse_thread/thread/9a0a2d60ef1126fd}{this +% sage-support thread}. If you want a plot to only appear in a certain +% overlay, you might try something like this in your frame: +% \begin{quote} +% |\begin{itemize}|\\ +% |\item item 1|\\ +% |\item item 2|\\ +% |\item \sageplot[height=4cm][png]{(plot_slope_field(2*x,(x,-4,4),|\\ +% | (y,-4,4))+(x^2-2).plot(-2,2))}|\\ +% |\end{itemize}|\\ +% \end{quote} +% but the plot will appear on all the overlays, instead of the third. +% The solution is to use the |\visible| macro: +% \begin{quote} +% |\begin{itemize}|\\ +% |\item item 1|\\ +% |\item item 2|\\ +% |\item \visible<3->{\sageplot[height=4cm][png]{(plot_slope_field(2*x,(x,-4,4),|\\ +% | (y,-4,4))+(x^2-2).plot(-2,2))}}|\\ +% |\end{itemize}|\\ +% \end{quote} +% Then the plot will only appear on the third (and later) overlays. +% (Thanks to Robert Ma{\v r}{\'\i}k for this solution.) +% +% \subsection{Using the \texttt{rccol} package} +% +% If you are trying to use the |\sage| macro inside a table when using +% the +% \href{http://www.ctan.org/tex-archive/macros/latex/contrib/rccol/}{\texttt{rccol}} +% package, you need to use an extra pair of braces or typesetting will +% fail. That is, you need to do something like this: +% \begin{quote} +% | abc & {\sage{foo.n()}} & {\sage{bar}} \\| +% \end{quote} +% with each ``|\sage{}|'' enclosed in an extra |{}|. Thanks to Sette +% Diop for reporting this. +% +% \subsection{Plotting from Mathematica, Maple, etc.} +% +% Sage can use Mathematica, Maple, and friends and can tell them to do +% plotting, but since it cannot get those plots into a Sage graphics +% object, you cannot use |\sageplot| to use such graphics. You'll need +% to use the method described in ``But that's not good enough!'' +% (\autoref{sec:notgoodenough}) with some additional bits to get the +% directory right---otherwise your file will get saved to someplace in a +% hidden directory. +% +% For Mathematica, you can do something like this inside a |sagesilent| +% or |sageblock| environment: +% \begin{quote} +% |mathematica('myplot = commands to make your plot')|\\ +% |mathematica('Export["%s/graphicsfile.eps", myplot]' % os.getcwd())| +% \end{quote} +% then put |\includegraphics[opts]{graphicsfile}| in your file. +% +% For Maple, you'll need something like +% \begin{quote} +% |maple('plotsetup(ps, plotoutput=`%s/graphicsfile.eps`, \|\\ +% | plotoptions=`whatever`);' % os.getcwd())|\\ +% |maple('plot(function, x=1..whatever);')| +% \end{quote} +% and then |\includegraphics| as necessary. +% +% These interfaces, especially when plotting, can be finicky. The above +% commands are just meant to be a starting point. +% +% \subsection{Sending \ST files to others who don't use Sage} +% \label{sec:makestatic-usage} +% +% \subsubsection{The 21st century way} +% +% The SageMathCloud +% (\href{http://cloud.sagemath.com}{\texttt{cloud.sagemath.com}}) service has +% full support for \ST, is free to use, and has many fantastic +% collaboration features. If you somehow want to collaborate on a +% \ST-enabled \TeX document with a colleague, using SageMathCloud is one +% of the best and easiest ways to do it. You and your collaborators +% simply create an account, then make a project for your collaboration, +% and add all the collaborators to the project. Then you can all enjoy +% realtime collaborative editing, PDF previews, chat, and more. +% +% \subsubsection{The $N$th century way, for $N < 21$} +% +% Using anything other than SageMathCloud, |git|, or similar tools these +% days seems pretty primitive. If emailing |.tex| files back and forth +% seems perfectly reasonable to you, or if you have to send a file to a +% journal, the easiest way is to simply include with your document the +% following files: +% \begin{enumerate} +% \item |sagetex.sty| +% \item the generated |.sout| and |.scmd| files +% \item the \texttt{sage-plots-for-\meta{filename}.tex} directory and +% its contents +% \end{enumerate} +% As long as |sagetex.sty| is available, your document can be typeset +% using any reasonable \LTX system. Since it is very common to include +% graphics files with a paper submission, this is a solution that should +% always work. (In particular, it will work with arXiv submissions.) +% +% There is another option, and that is to use the |makestatic.py| script +% included with \ST. This script has been unmaintained for some time and +% likely won't work. If you want or need to use it and run into trouble, +% email the +% \href{https://groups.google.com/forum/#!forum/sage-support}{\texttt{sage-support} +% group} and let us know. +% +% Use of the script is quite simple. Copy it and |sagetexparse.py| to +% the directory with your document, and run +% \begin{quote} +% |python makestatic.py inputfile [outputfile]| +% \end{quote} +% where |inputfile| is your document. (You can also set the executable +% bit of |makestatic.py| and use |./makestatic.py|.) This script needs +% the \href{http://pyparsing.wikispaces.com}{pyparsing} module to be +% installed.\footnote{If you don't have pyparsing installed, you can +% simply copy the file +% \texttt{\sageroot/local/lib/python/matplotlib/pyparsing.py} into +% your directory.} You may optionally specify |outputfile|; if you do +% so, the results will be written to that file. If the file exists, it +% won't be overwritten unless you also specify the |-o| switch. +% +% You will need to run this after you've compiled your document and +% run Sage on the |.sage| file. The script reads in the |.sout| file +% and replaces all the calls to |\sage| and |\sageplot| with their +% plain \LTX equivalent, and turns the |sageblock| and |sageverbatim| +% environments into |verbatim| environments. Any |sagesilent| +% environment is turned into a |comment| environment. Any +% |sagecommandline| environment is turned into a |lstlisting| +% environment, typesetting the relevant part of the |.scmd| file. The +% resulting document should compile to something identical, or very +% nearly so, to the original file. +% +% One large limitation of this script is that it can't change anything +% while \ST is paused, since Sage doesn't compute anything for such +% parts of your document. It also doesn't check to see if pause and +% unpause commands are inside comments or verbatim environments. If +% you're going to use |makestatic.py|, just remove all pause/unpause +% statements. +% +% The parsing that |makestatic.py| does is pretty good, but not perfect. +% Right now it doesn't support having a comma-separated list of +% packages, so you can't have |\usepackage{sagetex, foo}|. You need to +% have just |\usepackage{sagetex}|. (Along with package options; those +% are handled correctly.) If you find other parsing errors, please let +% me know. +% +% \subsection{Extracting the Sage code from a document} +% \label{sec:extractsagecode} +% +% (This script has the same unmaintained-and-probably-doesn't-work +% status as |makestatic.py|; see above.) +% +% This next script is probably not so useful, but having done the above, +% this was pretty easy. The |extractsagecode.py| script does the +% opposite of |makestatic.py|, in some sense: given a document, it +% extracts all the Sage code and removes all the \LTX. +% +% Its usage is the same as |makestatic.py|. +% +% Note that the resulting file will almost certainly \emph{not} be a +% runnable Sage script, since there might be \LTX commands in it, the +% indentation may not be correct, and the plot options just get written +% verbatim to the file. Nevertheless, it might be useful if you just +% want to look at the Sage code in a file. +% +% \section{Using \ST without Sage installed} +% \label{sec:remote-sagetex} +% +% (This script has the same unmaintained-and-probably-doesn't-work +% status as |makestatic.py|; see above.) +% +% You may want to edit and typeset a \ST-ified file on a computer that +% doesn't have Sage installed. How can you do that? We need to somehow +% run Sage on the |.sage| file. The included script +% \texttt{remote-sagetex.py} takes advantage of Sage's network +% transparency and will use a remote server to do all the computations. +% Anywhere in this manual where you are told to ``run Sage'', instead of +% actually running Sage, you can run +% \begin{center} +% \texttt{python remote-sagetex.py filename.sage} +% \end{center} +% The script will ask you for a server, username, and password, then +% process all your code and write a |.sout| file and graphics files +% exactly as if you had used a local copy of Sage to process the |.sage| +% script. (With some minor limitations and differences; see below.) +% +% One important point: \emph{the script requires Python 2.6}. It will +% not work with earlier versions. (It will work with Python 3.0 or later +% with some trivial changes.) +% +% You can provide the server, username and password with the +% command-line switches |--server|, |--username|, and |--password|, or +% you can put that information into a file and use the |--file| switch +% to specify that file. The format of the file must be like the +% following: +% \begin{verbatim} + # hash mark at beginning of line marks a comment + server = "http://example.com:1234" + username = 'my_user_name' + password = 's33krit'\end{verbatim} +% As you can see, it's really just like assigning a string to a variable +% in Python. You can use single or double quotes and use hash marks to +% start comments. You can't have comments on the same line as an +% assignment, though. You can omit any of those pieces of information +% information; the script will ask for anything it needs to know. +% Information provided as a command line switch takes precedence over +% anything found in the file. +% +% You can keep this file separate from your \LTX documents in a secure +% location; for example, on a USB thumb drive or in an automatically +% encrypted directory (like |~/Private| in Ubuntu). This makes it much +% harder to accidentally upload your private login information to the +% arXiv, put it on a website, send it to a colleague, or otherwise make +% your private information public. +% +% \subsection{Limitations of \texttt{remote-sagetex.py}} +% \label{sec:remote-sagetex-limitations} +% +% The |remote-sagetex.py| script has several limitations. It completely +% ignores the |epstopdf| and |imagemagick| flags. The |epstopdf| flag is +% not a big deal, since it was originally introduced to work around a +% matplotlib bug which has since been fixed. Not having |imagemagick| +% support means that you cannot automatically convert 3D graphics to eps +% format; using |pdflatex| to make PDFs works around this issue. +% +% +% \subsection{Other caveats} +% \label{sec:remote-sagetex-caveats} +% +% Right now, the ``simple server API'' that |remote-sagetex.py| uses is +% not terribly robust, and if you interrupt the script, it's possible to +% leave an idle session running on the server. If many idle sessions +% accumulate on the server, it can use up a lot of memory and cause the +% server to be slow, unresponsive, or maybe even crash. For now, I +% recommend that you only run the script manually. It's probably best to +% not configure your \TeX{} editing environment to automatically run +% |remote-sagetex.py| whenever you typeset your document, at least not +% without showing you the output or alerting you about errors. +% + + +% \iffalse +% Local Variables: +% mode: doctex +% TeX-master: t +% End: +% \fi diff --git a/macros/latex/contrib/sagetex/sagetex.ins b/macros/latex/contrib/sagetex/sagetex.ins new file mode 100644 index 0000000000..dd8dabb80a --- /dev/null +++ b/macros/latex/contrib/sagetex/sagetex.ins @@ -0,0 +1,124 @@ +%% This is `sagetex.ins', part of the sagetex package. +%% +%% Copyright (C) 2008--2015 by Dan Drake <dr.dan.drake@gmail.com> +%% +%% This program is free software: you can redistribute it and/or modify +%% it under the terms of the GNU General Public License as published by +%% the Free Software Foundation, either version 2 of the License, or (at +%% your option) any later version. +%% +%% This program is distributed in the hope that it will be useful, but +%% WITHOUT ANY WARRANTY; without even the implied warranty of +%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%% General Public License for more details. +%% +%% You should have received a copy of the GNU General Public License +%% along with this program. If not, see <http://www.gnu.org/licenses/>. + +\input docstrip.tex +\keepsilent + +\usedir{tex/latex/sagetex} + +\declarepreamble\defaultpreamble + +This is a generated file. It is part of the SageTeX package. + +Copyright (C) 2008--2015 by Dan Drake <dr.dan.drake@gmail.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. + +\endpreamble + +\generate{\file{sagetex.sty}{\from{sagetex.dtx}{latex} + \from{py-and-sty.dtx}{latex}}} + + +\usedir{PYTHONLIBDIR} + +% Define a new preamble with #'s as comment characters for the Python +% files. I hate copying the same text, but defining a "\boilerplate" +% macro requires me to manually do \MetaPrefix\space and ^^J everywhere +% and it's more annoying than this. + +\catcode`\#=12 +\def\hash{#} +\catcode`\#=6 + +\def\MetaPrefix{\hash\hash} +\declarepreamble\pypreamble + +This is a generated file. It is part of the SageTeX package. + +Copyright (C) 2008--2015 by Dan Drake <dr.dan.drake@gmail.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. + +\endpreamble +\usepreamble\pypreamble +\nopostamble + +\generate{\file{sagetex.py}{\from{sagetex.dtx}{python} + \from{py-and-sty.dtx}{python}}} +\generate{\file{sagetexparse.py}{\from{scripts.dtx}{parsermod}}} + + +\usedir{scripts/sagetex} + +% Now define a new preamble with the shebang line at the top. + +\def\envpypreamble{\hash!/usr/bin/env python^^J\pypreamble} +\usepreamble\envpypreamble + +\generate{\file{run-sagetex-if-necessary.py}{\from{scripts.dtx}{ifnecessaryscript}}} +\generate{\file{makestatic.py}{\from{scripts.dtx}{staticscript}}} +\generate{\file{extractsagecode.py}{\from{scripts.dtx}{extractscript}}} +\generate{\file{remote-sagetex.py}{\from{remote-sagetex.dtx}{remotesagetex}}} + +\obeyspaces +\Msg{******************************************************************} +\Msg{* *} +\Msg{* To finish the installation, move the following files *} +\Msg{* into directories searched by TeX and Sage, respectively: *} +\Msg{* *} +\Msg{* sagetex.sty *} +\Msg{* sagetex.py *} +\Msg{* *} +\Msg{* See the documentation for complete installation details. *} +\Msg{* *} +\Msg{* To produce the documentation run the file sagetex.dtx through *} +\Msg{* LaTeX. To produce the change history, run *} +\Msg{* *} +\Msg{* makeindex -s gglo.ist -o sagetex.gls sagetex.glo *} +\Msg{* *} +\Msg{* and to get the regular index, do *} +\Msg{* *} +\Msg{* makeindex -s gind.ist -o sagetex.ind sagetex.idx *} +\Msg{* *} +\Msg{* Happy TeXing...and, uh, Saging? *} +\Msg{* *} +\Msg{******************************************************************} + +\endbatchfile diff --git a/macros/latex/contrib/sagetex/sagetex.pdf b/macros/latex/contrib/sagetex/sagetex.pdf Binary files differnew file mode 100644 index 0000000000..ac37a7258b --- /dev/null +++ b/macros/latex/contrib/sagetex/sagetex.pdf diff --git a/macros/latex/contrib/sagetex/scripts.dtx b/macros/latex/contrib/sagetex/scripts.dtx new file mode 100644 index 0000000000..aec62a08cb --- /dev/null +++ b/macros/latex/contrib/sagetex/scripts.dtx @@ -0,0 +1,520 @@ +% \section{Included Python scripts} +% \label{sec:included-scripts} +% +% Here we describe the Python code for |run-sagetex-if-necessary|, and +% also |makestatic.py|, which removes \ST commands to produce a +% ``static'' file, and |extractsagecode.py|, which extracts all the Sage +% code from a |.tex| file. +% +% \subsection{run-sagetex-if-necessary} +% \label{sec:run-sagetex-if-necessary} +% \iffalse +%<*ifnecessaryscript> +% \fi +% +% When working on a document that uses \ST, running Sage every time you +% typeset your document may take too long, especially since it often +% won't be necessary. This script is a drop-in replacement for Sage: +% instead of +% \begin{center} +% |sage document.sagetex.sage| +% \end{center} +% you can do +% \begin{center} +% |run-sagetex-if-necessary.py document.sagetex.sage| +% \end{center} +% and it will use the MD5 mechanism described in the |endofdoc| macro +% (page~{\pageref{macro:endofdoc}). With this, you can set up your editor +% (\TeX Shop, \TeX Works, etc) to typeset your document with a script +% that does +% \begin{quote} +% |pdflatex $1|\\ +% |run-sagetex-if-necessary.py $1| +% \end{quote} +% which will only, of course, run Sage when necessary. +% \begin{macrocode} + +# given a filename f, examines f.sagetex.sage and f.sagetex.sout and +# runs Sage if necessary. + +import hashlib +import sys +import os +import re +import subprocess + +# CHANGE THIS AS APPROPRIATE +path_to_sage = os.path.expanduser('~/bin/sage') +# or try to auto-find it: +# path_to_sage = subprocess.check_output(['which', 'sage']).strip() +# or just tell me: +# path_to_sage = '/usr/local/bin/sage' + +if sys.argv[1].endswith('.sagetex.sage'): + src = sys.argv[1][:-13] +else: + src = os.path.splitext(sys.argv[1])[0] + +commented_out = r'^\s*%' +usepackage = r'\usepackage{sagetex}' +uses_sagetex = False + +# if it doesn't use sagetex, obviously running sage is unnecessary +with open(src + '.tex') as texf: + for line in texf: + if not re.search(commented_out, line) and re.search(usepackage, line): + uses_sagetex = True + break + +if not uses_sagetex: + print(src + ".tex doesn't seem to use SageTeX, exiting.") + sys.exit(0) + +# if something goes wrong, assume we need to run Sage +run_sage = True + ignore = r"^( _st_.goboom|print('SageT| ?_st_.current_tex_line))" + +try: + with open(src + '.sagetex.sage', 'r') as sagef: + h = hashlib.md5() + for line in sagef: + if not re.search(ignore, line): + h.update(bytearray(line,'utf8')) +except IOError: + print('{0}.sagetex.sage not found, I think you need to typeset {0}.tex first.'.format(src)) + sys.exit(1) + +try: + with open(src + '.sagetex.sout', 'r') as outf: + for line in outf: + m = re.match('%([0-9a-f]+)% md5sum', line) + if m: + print('computed md5:', h.hexdigest()) + print('sagetex.sout md5:', m.group(1)) + if h.hexdigest() == m.group(1): + run_sage = False + break +except IOError: + pass + +if run_sage: + print('Need to run Sage on {0}.'.format(src)) + sys.exit(subprocess.call([path_to_sage, src + '.sagetex.sage'])) +else: + print('Not necessary to run Sage on {0}.'.format(src)) +% \end{macrocode} +% +% \subsection{makestatic.py} +% \label{sec:makestatic} +% \iffalse +%</ifnecessaryscript> +%<*staticscript> +% \fi +% +% Now the |makestatic.py| script. It's about the most basic, generic +% Python script taking command-line arguments that you'll find. The +% |#!/usr/bin/env python| line is provided for us by the |.ins| file's +% preamble, so we don't put it here. +% \begin{macrocode} +import sys +import time +import getopt +import os.path +from sagetexparse import DeSageTex + +def usage(): + print("""Usage: %s [-h|--help] [-o|--overwrite] inputfile [outputfile] + +Removes SageTeX macros from `inputfile' and replaces them with the +Sage-computed results to make a "static" file. You'll need to have run +Sage on `inputfile' already. + +`inputfile' can include the .tex extension or not. If you provide +`outputfile', the results will be written to a file of that name. +Specify `-o' or `--overwrite' to overwrite the file if it exists. + +See the SageTeX documentation for more details.""" % sys.argv[0]) + +try: + opts, args = getopt.getopt(sys.argv[1:], 'ho', ['help', 'overwrite']) +except getopt.GetoptError, err: + print(str(err)) + usage() + sys.exit(2) + +overwrite = False +for o, a in opts: + if o in ('-h', '--help'): + usage() + sys.exit() + elif o in ('-o', '--overwrite'): + overwrite = True + +if len(args) == 0 or len(args) > 2: + print('Error: wrong number of arguments. Make sure to specify options first.\n') + usage() + sys.exit(2) + +if len(args) == 2 and (os.path.exists(args[1]) and not overwrite): + print('Error: %s exists and overwrite option not specified.' % args[1]) + sys.exit(1) + +src, ext = os.path.splitext(args[0]) +% \end{macrocode} +% All the real work gets done in the line below. Sorry it's not more +% exciting-looking. +% \begin{macrocode} +desagetexed = DeSageTex(src) +% \end{macrocode} +% This part is cool: we need double percent signs at the beginning of +% the line because Python needs them (so they get turned into single +% percent signs) \emph{and} because \textsf{Docstrip} needs them (so the +% line gets passed into the generated file). It's perfect! +% \begin{macrocode} +header = "%% SageTeX commands have been automatically removed from this file and\n%% replaced with plain LaTeX. Processed %s.\n" % time.strftime('%a %d %b %Y %H:%M:%S', time.localtime()) + +if len(args) == 2: + dest = open(args[1], 'w') +else: + dest = sys.stdout + +dest.write(header) +dest.write(desagetexed.result) +% \end{macrocode} +% +% \iffalse +%</staticscript> +%<*extractscript> +% \fi +% +% \subsection{extractsagecode.py} +% +% Same idea as |makestatic.py|, except this does basically the opposite +% thing. +% \begin{macrocode} +import sys +import time +import getopt +import os.path +from sagetexparse import SageCodeExtractor + +def usage(): + print("""Usage: %s [-h|--help] [-o|--overwrite] inputfile [outputfile] + +Extracts Sage code from `inputfile'. + +`inputfile' can include the .tex extension or not. If you provide +`outputfile', the results will be written to a file of that name, +otherwise the result will be printed to stdout. + +Specify `-o' or `--overwrite' to overwrite the file if it exists. + +See the SageTeX documentation for more details.""" % sys.argv[0]) + +try: + opts, args = getopt.getopt(sys.argv[1:], 'ho', ['help', 'overwrite']) +except getopt.GetoptError, err: + print(str(err)) + usage() + sys.exit(2) + +overwrite = False +for o, a in opts: + if o in ('-h', '--help'): + usage() + sys.exit() + elif o in ('-o', '--overwrite'): + overwrite = True + +if len(args) == 0 or len(args) > 2: + print('Error: wrong number of arguments. Make sure to specify options first.\n') + usage() + sys.exit(2) + +if len(args) == 2 and (os.path.exists(args[1]) and not overwrite): + print('Error: %s exists and overwrite option not specified.' % args[1]) + sys.exit(1) + +src, ext = os.path.splitext(args[0]) +sagecode = SageCodeExtractor(src) +header = """\ +# This file contains Sage code extracted from %s%s. +# Processed %s. + +""" % (src, ext, time.strftime('%a %d %b %Y %H:%M:%S', time.localtime())) + +if len(args) == 2: + dest = open(args[1], 'w') +else: + dest = sys.stdout + +dest.write(header) +dest.write(sagecode.result) +% \end{macrocode} +% +% \iffalse +%</extractscript> +%<*parsermod> +% \fi +% +% \subsection{The parser module} +% \changes{v2.2}{2009/06/17}{Update parser module to handle pause/unpause} +% +% Here's the module that does the actual parsing and replacing. It's +% really quite simple, thanks to the awesome +% \href{http://pyparsing.wikispaces.com}{Pyparsing module}. The parsing +% code below is nearly self-documenting! Compare that to fancy regular +% expressions, which sometimes look like someone sneezed punctuation all +% over the screen. +% \begin{macrocode} +import sys +from pyparsing import * +% \end{macrocode} +% First, we define this very helpful parser: it finds the matching +% bracket, and doesn't parse any of the intervening text. It's basically +% like hitting the percent sign in Vim. This is useful for parsing \LTX +% stuff, when you want to just grab everything enclosed by matching +% brackets. +% \begin{macrocode} +def skipToMatching(opener, closer): + nest = nestedExpr(opener, closer) + nest.setParseAction(lambda l, s, t: l[s:getTokensEndLoc()]) + return nest + +curlybrackets = skipToMatching('{', '}') +squarebrackets = skipToMatching('[', ']') +% \end{macrocode} +% Next, parser for |\sage|, |\sageplot|, and pause/unpause calls: +% \begin{macrocode} +sagemacroparser = r'\sage' + curlybrackets('code') +sageplotparser = (r'\sageplot' + + Optional(squarebrackets)('opts') + + Optional(squarebrackets)('format') + + curlybrackets('code')) +sagetexpause = Literal(r'\sagetexpause') +sagetexunpause = Literal(r'\sagetexunpause') +% \end{macrocode} +% +% With those defined, let's move on to our classes. +% +% \begin{macro}{SoutParser} +% Here's the parser for the generated |.sout| file. The code below does +% all the parsing of the |.sout| file and puts the results into a +% list. Notice that it's on the order of 10 lines of code---hooray +% for Pyparsing! +% \begin{macrocode} +class SoutParser(): + def __init__(self, fn): + self.label = [] +% \end{macrocode} +% A label line looks like +% \begin{quote} +% |\newlabel{@sageinline|\meta{integer}|}{|\marg{bunch of \LTX code}|{}{}{}{}}| +% \end{quote} +% which makes the parser definition below pretty obvious. We assign some +% names to the interesting bits so the |newlabel| method can make the +% \meta{integer} and \meta{bunch of \LTX code} into the keys and values +% of a dictionary. The |DeSageTeX| class then uses that dictionary to +% replace bits in the |.tex| file with their Sage-computed results. +% \begin{macrocode} + parselabel = (r'\newlabel{@sageinline' + + Word(nums)('num') + + '}{' + + curlybrackets('result') + + '{}{}{}{}}') +% \end{macrocode} +% We tell it to ignore comments, and hook up the list-making method. +% \begin{macrocode} + parselabel.ignore('%' + restOfLine) + parselabel.setParseAction(self.newlabel) +% \end{macrocode} +% A |.sout| file consists of one or more such lines. Now go parse the +% file we were given. +% \begin{macrocode} + try: + OneOrMore(parselabel).parseFile(fn) + except IOError: + print('Error accessing {}; exiting. Does your .sout file exist?'.format(fn)) + sys.exit(1) +% \end{macrocode} +% Pyparser's parse actions get called with three arguments: the string +% that matched, the location of the beginning, and the resulting parse +% object. Here we just add a new key-value pair to the dictionary, +% remembering to strip off the enclosing brackets from the ``result'' +% bit. +% \begin{macrocode} + def newlabel(self, s, l, t): + self.label.append(t.result[1:-1]) +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{DeSageTeX} +% Now we define a parser for \LTX files that use \ST commands. We assume +% that the provided |fn| is just a basename. +% \begin{macrocode} +class DeSageTex(): + def __init__(self, fn): + self.sagen = 0 + self.plotn = 0 + self.fn = fn + self.sout = SoutParser(fn + '.sagetex.sout') +% \end{macrocode} +% Parse |\sage| macros. We just need to pull in the result from the +% |.sout| file and increment the counter---that's what |self.sage| does. +% \begin{macrocode} + smacro = sagemacroparser + smacro.setParseAction(self.sage) +% \end{macrocode} +% Parse the |\usepackage{sagetex}| line. Right now we don't support +% comma-separated lists of packages. +% \begin{macrocode} + usepackage = (r'\usepackage' + + Optional(squarebrackets) + + '{sagetex}') + usepackage.setParseAction(replaceWith(r"""% "\usepackage{sagetex}" line was here: +\RequirePackage{verbatim} +\RequirePackage{graphicx} +\newcommand{\sagetexpause}{\relax} +\newcommand{\sagetexunpause}{\relax}""")) +% \end{macrocode} +% Parse |\sageplot| macros. +% \begin{macrocode} + splot = sageplotparser + splot.setParseAction(self.plot) +% \end{macrocode} +% The printed environments (|sageblock| and |sageverbatim|) get turned +% into |verbatim| environments. +% \begin{macrocode} + beginorend = oneOf('begin end') + blockorverb = 'sage' + oneOf('block verbatim') + blockorverb.setParseAction(replaceWith('verbatim')) + senv = '\\' + beginorend + '{' + blockorverb + '}' +% \end{macrocode} +% The non-printed |sagesilent| environment gets commented out. We could +% remove all the text, but this works and makes going back to \ST +% commands (de-de-\ST{}ing?) easier. +% \begin{macrocode} + silent = Literal('sagesilent') + silent.setParseAction(replaceWith('comment')) + ssilent = '\\' + beginorend + '{' + silent + '}' +% \end{macrocode} +% The |\sagetexindent| macro is no longer relevant, so remove it from +% the output (``suppress'', in Pyparsing terms). +% \begin{macrocode} + stexindent = Suppress(r'\setlength{\sagetexindent}' + curlybrackets) +% \end{macrocode} +% Now we define the parser that actually goes through the file. It just +% looks for any one of the above bits, while ignoring anything that +% should be ignored. +% \begin{macrocode} + doit = smacro | senv | ssilent | usepackage | splot | stexindent + doit.ignore('%' + restOfLine) + doit.ignore(r'\begin{verbatim}' + SkipTo(r'\end{verbatim}')) + doit.ignore(r'\begin{comment}' + SkipTo(r'\end{comment}')) + doit.ignore(r'\sagetexpause' + SkipTo(r'\sagetexunpause')) +% \end{macrocode} +% We can't use the |parseFile| method, because that expects a ``complete +% grammar'' in which everything falls into some piece of the parser. +% Instead we suck in the whole file as a single string, and run +% |transformString| on it, since that will just pick out the interesting +% bits and munge them according to the above definitions. +% \begin{macrocode} + str = ''.join(open(fn + '.tex', 'r').readlines()) + self.result = doit.transformString(str) +% \end{macrocode} +% That's the end of the class constructor, and it's all we need to do +% here. You access the results of parsing via the |result| string. +% +% We do have two methods to define. The first does the same thing that +% |\ref| does in your \LTX file: returns the content of the label and +% increments a counter. +% \begin{macrocode} + def sage(self, s, l, t): + self.sagen += 1 + return self.sout.label[self.sagen - 1] +% \end{macrocode} +% The second method returns the appropriate |\includegraphics| command. +% It does need to account for the default argument. +% \begin{macrocode} + def plot(self, s, l, t): + self.plotn += 1 + if len(t.opts) == 0: + opts = r'[width=.75\textwidth]' + else: + opts = t.opts[0] + return (r'\includegraphics%s{sage-plots-for-%s.tex/plot-%s}' % + (opts, self.fn, self.plotn - 1)) +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{SageCodeExtractor} +% This class does the opposite of the first: instead of removing Sage +% stuff and leaving only \LTX, this removes all the \LTX and leaves only +% Sage. +% \begin{macrocode} +class SageCodeExtractor(): + def __init__(self, fn): + smacro = sagemacroparser + smacro.setParseAction(self.macroout) + + splot = sageplotparser + splot.setParseAction(self.plotout) +% \end{macrocode} +% Above, we used the general parsers for |\sage| and |\sageplot|. We +% have to redo the environment parsers because it seems too hard to +% define one parser object that will do both things we want: above, we +% just wanted to change the environment name, and here we want to suck +% out the code. Here, it's important that we find matching begin/end +% pairs; above it wasn't. At any rate, it's not a big deal to redo this +% parser. +% \begin{macrocode} + env_names = oneOf('sageblock sageverbatim sagesilent') + senv = r'\begin{' + env_names('env') + '}' + SkipTo( + r'\end{' + matchPreviousExpr(env_names) + '}')('code') + senv.leaveWhitespace() + senv.setParseAction(self.envout) + + spause = sagetexpause + spause.setParseAction(self.pause) + + sunpause = sagetexunpause + sunpause.setParseAction(self.unpause) + + doit = smacro | splot | senv | spause | sunpause + + str = ''.join(open(fn + '.tex', 'r').readlines()) + self.result = '' + + doit.transformString(str) + + def macroout(self, s, l, t): + self.result += '# \\sage{} from line %s\n' % lineno(l, s) + self.result += t.code[1:-1] + '\n\n' + + def plotout(self, s, l, t): + self.result += '# \\sageplot{} from line %s:\n' % lineno(l, s) + if t.format is not '': + self.result += '# format: %s' % t.format[0][1:-1] + '\n' + self.result += t.code[1:-1] + '\n\n' + + def envout(self, s, l, t): + self.result += '# %s environment from line %s:' % (t.env, + lineno(l, s)) + self.result += t.code[0] + '\n' + + def pause(self, s, l, t): + self.result += ('# SageTeX (probably) paused on input line %s.\n\n' % + (lineno(l, s))) + + def unpause(self, s, l, t): + self.result += ('# SageTeX (probably) unpaused on input line %s.\n\n' % + (lineno(l, s))) +% \end{macrocode} +% \end{macro} + +% \endinput +%</parsermod> +% Local Variables: +% mode: doctex +% TeX-master: "sagetex" +% End: diff --git a/macros/latex/contrib/sagetex/setup.py b/macros/latex/contrib/sagetex/setup.py new file mode 100644 index 0000000000..44631f6926 --- /dev/null +++ b/macros/latex/contrib/sagetex/setup.py @@ -0,0 +1,32 @@ +from distutils.core import setup +setup(name='sagetex', + description='Embed Sage code and plots into LaTeX', + long_description="""The SageTeX package allows you to embed code, + results of computations, and plots from the Sage mathematics + software suite (http://sagemath.org) into LaTeX documents.""", + version='3.2', + author='Dan Drake', + author_email='dr.dan.drake@gmail.com', + maintainer='SageMath developers', + maintainer_email='sage-devel@googlegroups.com', + url='https://github.com/sagemath/sagetex', + license='GPLv2+', + py_modules=['sagetex'], + data_files = [('share/texmf/tex/latex/sagetex', + ['example.tex', + 'CONTRIBUTORS', + 'extractsagecode.py', + 'run-sagetex-if-necessary.py', + 'makestatic.py', + 'scripts.dtx', + 'remote-sagetex.dtx', + 'remote-sagetex.py', + 'py-and-sty.dtx', + 'sagetex.dtx', + 'sagetex.ins', + 'sagetexparse.py', + 'sagetex.sty']), + ('share/doc/sagetex', [ + 'example.tex', + 'sagetex.pdf', + 'example.pdf'])]) |