Sagetex để tính toán trực tiếp trong LaTeX

Bài viết này hướng dẫn sử dụng SageTeX trong Ubuntu Linux. Các bạn sử dụng MS Windows xem trên Web hướng dẫn cài đặt Sage.

Bước 1: cài Sage. Từ giao diện dòng lệnh gõ lần lượt các lệnh sau đây:

sudo apt-add-repository -y ppa:aims/sagemath
sudo apt-get update
sudo apt-get install sagemath-upstream-binary

khoảng 600MB sẽ được download và cài đặt.

Bước 2: Cài SageTeX. Đơn giản chỉ cần copy hai file sau đây vào thư mục chứa file TeX. Tất nhiên khi cài Ubuntu các bạn phải cài luôn Python. Nếu chưa các bạn vào synaptic chọn Python và Apply để cài đặt.

Copy file sau đây dán vào TeXMaker lưu thành file sagetex.sty

%%
%% This is file `sagetex.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% sagetexpackage.dtx (with options: `latex')
%% py-and-sty.dtx (with options: `latex')
%%
%% This is a generated file. It is part of the SageTeX package.
%%
%% Copyright (C) 2008--2010 by Dan Drake <ddrake@member.ams.org>
%%
%% 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/>.
%%
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{sagetex}
  [2010/03/25 v2.2.5 embedding Sage into LaTeX documents]
\newcommand{\ST@ver}{2010/03/25 v2.2.5}
\RequirePackage{verbatim}
\RequirePackage{fancyvrb}
\RequirePackage{graphicx}
\RequirePackage{makecmds}
\RequirePackage{ifpdf}
\RequirePackage{ifthen}
\newcounter{ST@inline}
\newcounter{ST@plot}
\setcounter{ST@inline}{0}
\setcounter{ST@plot}{0}
\newlength{\sagetexindent}
\setlength{\sagetexindent}{5ex}
\newif\ifST@paused
\ST@pausedfalse
\AtBeginDocument{\@ifundefined{ST@final}{%
\newwrite\ST@sf%
\immediate\openout\ST@sf=\jobname.sage%
\newcommand{\ST@wsf}[1]{\immediate\write\ST@sf{#1}}%
\ST@wsf{%
# This file (\jobname.sage) was *autogenerated* from \jobname.tex with
sagetex.sty version \ST@ver.^^J%
import sagetex^^J%
_st_ = sagetex.SageTeXProcessor('\jobname')^^J%
_do_ver_check_ = \ST@versioncheck^^J%
if _do_ver_check_ and sagetex.__version__.find('\ST@ver') == -1:^^J
  import sys^^J
  print '{0}.sage was generated with sagetex.sty version \ST@ver,'.format(
    sys.argv[0].split('.')[0])^^J
  print 'but is being processed by sagetex.py version {0}.'.format(
    ' '.join(sagetex.__version__.strip().strip('[').split()[0:2]))^^J
  print 'SageTeX version mismatch! Exiting.'^^J
  sys.exit(int(1))}}%
{\newcommand{\ST@wsf}[1]{\relax}}}
\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}}
\newcommand{\ST@wdf}[1]{\immediate\write\ST@df{#1}}
\DeclareOption{final}{%
  \newcommand{\ST@final}{x}%
  \IfFileExists{\jobname.sout}{}{\AtEndDocument{\PackageWarningNoLine{sagetex}%
  {`final' option provided, but \jobname.sout^^Jdoesn't exist! No Sage
    input will appear in your document. Remove the `final'^^Joption and
    rerun LaTeX on your document}}}}
\DeclareOption{imagemagick}{%
  \newcommand{\ST@useimagemagick}{x}%
  \AtBeginDocument{%
  \@ifundefined{ST@final&nbsp;}{%
    \ST@wsf{_st_.useimagemagick = True}}{}}}
\DeclareOption{epstopdf}{%
\AtBeginDocument{%
\@ifundefined{ST@final}{%
  \ST@wsf{_st_.useepstopdf = True}}{}}}
\newcommand{\ST@versioncheck}{True}
\DeclareOption{noversioncheck}{%
  \renewcommand{\ST@versioncheck}{False}}
\ProcessOptions\relax
\InputIfFileExists{\jobname.sout}{}{\typeout{No file \jobname.sout.}}
\AtBeginDocument{\provideenvironment{NoHyper}{}{}}
\newcommand{\ST@sage}[1]{\ST@wsf{%
try:^^J
 _st_.inline(\theST@inline, #1)^^J%
except:^^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
\stepcounter{ST@inline}}
\newcommand{\sage}[1]{\ST@sage{latex(#1)}}
\newcommand{\sagestr}[1]{\ST@sage{#1}}
\catcode`\%=12
\newcommand{\percent}{%}
\catcode`\%=14
\newcommand{\ST@plotdir}{sage-plots-for-\jobname.tex}
\newcommand{\ST@missingfilebox}{\framebox[2cm]{\rule[-1cm]{0cm}{2cm}\textbf{??}}}
\newcommand{\sageplot}[1][width=.75\textwidth]{%
  \@ifnextchar[{\ST@sageplot[#1]}{\ST@sageplot[#1][notprovided]}}
\def\ST@sageplot[#1][#2]#3{\ST@wsf{try:^^J
 _st_.plot(\theST@plot, format='#2', _p_=#3)^^Jexcept:^^J
 _st_.goboom(\the\inputlineno)}%
\ifpdf
  \ifthenelse{\equal{#2}{notprovided}}%
    {\ST@inclgrfx{#1}{pdf}}%
    {\ST@inclgrfx{#1}{#2}}%
\else
  \ifthenelse{\equal{#2}{notprovided}}%
    {\ST@inclgrfx{#1}{eps}}%
    {\@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}}}%
    {\ST@inclgrfx{#1}{eps}}}%
\fi
\stepcounter{ST@plot}}
\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}}%
    {\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}
\newcommand{\ST@beginsfbl}{%
  \@bsphack\ST@wsf{%
_st_.blockbegin()^^Jtry:}%
  \let\do\@makeother\dospecials\catcode`\^^M\active}
\newcommand{\ST@endsfbl}{%
\ST@wsf{except:^^J
 _st_.goboom(\the\inputlineno)^^J_st_.blockend()}}
\newenvironment{sageblock}{\ST@beginsfbl%
\def\verbatim@processline{\ST@wsf{ \the\verbatim@line}%
\hspace{\sagetexindent}\the\verbatim@line\par}%
\verbatim}%
{\ST@endsfbl\endverbatim}
\newenvironment{sagesilent}{\ST@beginsfbl%
\def\verbatim@processline{\ST@wsf{ \the\verbatim@line}}%
\verbatim@start}%
{\ST@endsfbl\@esphack}
\newenvironment{sageverbatim}{%
\def\verbatim@processline{\hspace{\sagetexindent}\the\verbatim@line\par}%
\verbatim}%
{\endverbatim}
\newcommand{\sageexampleincludetextoutput}{False}
\newenvironment{sageexample}{%
   \ST@wsf{%
try:^^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{%</pre>
<span style="color: #000000;">Đơn giản chỉ cần copy hai file sau đây vào thư mục chứa file TeX. Tất nhiên khi cài Ubuntu các bạn phải cài luôn Python. Nếu chưa các bạn vào synaptic chọn Python và Apply để cài đặt.</span>

<span style="color: #000000;">Copy file sau đây dán vào TeXMaker lưu thành file sagetex.sty</span>
<pre>
 """, 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}}
\newcommand{\sagetexpause}{\ifST@paused\relax\else
\ST@wsf{print 'SageTeX paused on \jobname.tex line \the\inputlineno'^^J"""}
\ST@pausedtrue
\fi}
\newcommand{\sagetexunpause}{\ifST@paused
\ST@wsf{"""^^Jprint 'SageTeX unpaused on \jobname.tex line \the\inputlineno'}
\ST@pausedfalse
\fi}
\AtEndDocument{\ifST@paused
\ST@wsf{"""^^Jprint 'SageTeX unpaused at end of \jobname.tex'}
\fi
\ST@wsf{_st_.endofdoc()}%
\@ifundefined{ST@rerun}{}%
{\PackageWarningNoLine{sagetex}{There were undefined Sage formulas
and/or plots.^^JRun Sage on \jobname.sage, and then run
LaTeX on \jobname.tex again}}}
\endinput
%%
%% End of file `sagetex.sty'.

Tiếp theo copy file sau đây dán vào TeXMaker lưu thành file sagetex.py

##
## This is file `sagetex.py',
## generated with the docstrip utility.
##
## The original source files were:
##
## sagetexpackage.dtx  (with options: `python')
## py-and-sty.dtx  (with options: `python')
##
## This is a generated file. It is part of the SageTeX package.
##
## Copyright (C) 2008--2010 by Dan Drake <ddrake@member.ams.org>
##
## 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/>.
##
__version__ = """
  [2010/03/25 v2.2.5 embedding Sage into LaTeX documents]
""".strip()
import sys
if __name__ == "__main__":
  print("""This file is part of the SageTeX package.
It is not meant to be called directly.

This file will be automatically used by Sage scripts generated from a
LaTeX document using the SageTeX package.""")
  sys.exit()
version = ' '.join(__version__.strip('[').split()[0:2])
from sage.misc.latex import latex
from sage.misc.preparser import preparse
import os
import os.path
import hashlib
import traceback
import subprocess
import shutil
class SageTeXProcessor():
  def __init__(self, jobname):
    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.souttmp = open(self.filename + '.sout.tmp', 'w')
    self.souttmp.write("""% This file was *autogenerated* from {0}.sage with
 % sagetex.py version {1}\n""".format(os.path.splitext(jobname)[0], version))
  def progress(self, t,linebreak=True):
    if linebreak:
      print(t)
    else:
      sys.stdout.write(t)
      sys.stdout.flush()
  def initplot(self):
    self.progress('Initializing plots directory')
    if os.path.isdir(self.plotdir):
      shutil.rmtree(self.plotdir)
    os.mkdir(self.plotdir)
    self.didinitplot = True
  def inline(self, counter, s):
    self.progress('Inline formula {0}'.format(counter))
    self.souttmp.write('\\newlabel{@sageinline' + str(counter) + '}{{%\n' +
                 s.rstrip() + '}{}{}{}{}}\n')
  def blockbegin(self):
    self.progress('Code block begin...', False)
  def blockend(self):
    self.progress('end')
  def doctest(self, counter, str, globals, locals, include_text_output):
      print 'in doctest'
      current_statement = None
      current_lines = None
      latex_string = ""
      line_iterator = (line.lstrip() for line in str.splitlines())

      # Gobbles everything until the first "sage: ..." block
      for line in line_iterator:
          if line.startswith("sage: "):
              break
      else:
          return
      sage_block = 0
      while True:
          # At each
          assert line.startswith("sage: ")
          current_statement  = line[6:]
          current_lines = "  "+line
          for line in line_iterator:
              if line.startswith("sage: "):
                  break
              elif line.startswith("..."):
                  current_statement +="\n"+line[6:]
                  current_lines +="\n  "+line
              elif include_text_output:
                  current_lines +="\n  "+line
          else:
              line = None # we reached the last line
          # Now we have digested everything from the current sage: ... to the next one or to the last line
          # Let us handle it
          verbatimboxname = "@sageinline%s-code%s"%(counter,sage_block)
          self.souttmp.write("\\begin{SaveVerbatim}{%s}\n"%verbatimboxname)
          self.souttmp.write(current_lines)
          self.souttmp.write("\n\\end{SaveVerbatim}\n")
          latex_string += "\UseVerbatim{%s}\n"%verbatimboxname
          current_statement = preparse(current_statement)
          try: # How to test whether the code is an Python expression or a statement?
              # In the first case, we compute the result and include it in the latex
              result = eval(current_statement, globals, locals)
              latex_string += r"""\abovedisplayskip=0pt plus 3pt
\abovedisplayshortskip=0pt plus 3pt
\begin{displaymath}""" + "\n {0}\n".format(latex(result)) + r"\end{displaymath}" + "\n"
          except SyntaxError:
              # If this fails, we assume that the code was a statement, and just execute it
              exec current_statement in globals, locals
          current_lines = current_statement = None
          if line is None: break
          sage_block += 1
      self.inline(counter, latex_string)
  def plot(self, counter, _p_, format='notprovided', **kwargs):
      if not self.didinitplot:
          self.initplot()
      self.progress('Plot {0}'.format(counter))
      if format == 'notprovided':
          formats = ['eps', 'pdf']
      else:
          formats = [format]
      for fmt in formats:
          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
          plotfilename = os.path.join(self.plotdir, 'plot-{0}.{1}'.format(counter, fmt))
          try:
              _p_.save(filename=plotfilename, **kwargs)
          except ValueError as inst:
              if 'filetype not supported by save' in 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
          if format != 'notprovided' and self.useimagemagick:
              self.progress('Calling Imagemagick to convert plot-{0}.{1} to EPS'.format(
                counter, format))
              self.toeps(counter, format)
  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)])
  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 + '.sout.tmp')
    sys.exit(int(1))
  def endofdoc(self):
    sagef = open(self.filename + '.sage', 'r')
    m = hashlib.md5()
    for line in sagef:
      if line[0:12] != " _st_.goboom" and line[0:12] != "print 'SageT":
        m.update(line)
    s = '%' + m.hexdigest() + '% md5sum of corresponding .sage file\
 (minus "goboom" and pause/unpause lines)\n'
    self.souttmp.write(s)
    self.souttmp.close()
    os.rename(self.filename + '.sout.tmp', self.filename + '.sout')
    self.progress('Sage processing complete. Run LaTeX on {0}.tex again.'.format(
             self.filename))

Lưu ý quan trọng: Phải chắc chắn rằng hai file trên cùng có version 2010/03/25 v2.2.5

Lần lượt chúng tôi sẽ có hướng dẫn tính toán trực tiếp trên LaTeX. Sau đây là file pascal.tex chúng tôi lập tam giác Pascal với n=27. Nhiều hơn cũng thực hiện được dễ dàng nhưng không có tờ giấy đủ lớn để chứa.

Việc sử dụng sagetex như sau:

  1. Soạn một file tex như mẫu hoặc ở các bài tập tiếp theo. Ví dụ file tex là pascal.tex
  2. Biên dịch bằng pdflatex :
    pdflatex pascal
    tự động tạo ra một file tên là pascal.sage
  3. Sau đó bật command line, dẫn đến thư mục chứa file các tex, sagetex.sty, sagetex.py  biên dịch bằng sage như sau:
    sage pascal.sage
  4. Vào TexMaker trở lại biên dịch tiếp file pascal.tex
    pdflatex pascal

File pascal.tex sau đây viết một macro con để lập tam giác pascal với n tùy ý.

\documentclass[landscape]{article}
\usepackage[utf8]{inputenc}
\usepackage[vietnam]{babel}
\usepackage[paperwidth=42cm,paperheight=15cm,top=1cm,bottom=2cm,left=0cm,right=0cm]{geometry}
\usepackage[utopia]{mathdesign}
\usepackage{sagetex}
\begin{document}
\pagestyle{empty}

\begin{sagesilent}
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)
n = 27
\end{sagesilent}

\newpage
\begin{center}
\sagestr{pascals_triangle(n)}
\end{center}

\end{document}

Bấm vào hình để xem hình đúng kích thước:
pascal

6 responses to “Sagetex để tính toán trực tiếp trong LaTeX

  1. Thầy ơi, cho em hỏi cách cài đặt sage trên win7, mà em lại chưa biết về ubuntu!
    Em search trên web: http://www.scribd.com/doc/61349444/H%C6%B0%E1%BB%9Bng-d%E1%BA%ABn-cai-%C4%91%E1%BA%B7t-Sage
    thì trang sau lại ko mở được!
    Nhờ thầy chỉ bảo!

  2. Cảm ơn thầy, em sẽ tìm hiểu thêm để sử dụng sage trong linux!

  3. Sau khi em dùng lệnh sage pascal.sagetex.sage thi ket qua:
    File “pascal.sagetex.py”, line 13
    s = [r”\begin{tabular}{cc|” + “r” * (n+_sage_const_1 ) + “}”]
    ^
    IndentationError: expected an indented block
    Vậy cần chỉnh sửa điều gì vậy Thầy

  4. Thôi em làm được rồi. file.tex của Thầy có vấn đề

  5. ”Sau đó bật command line, dẫn đến thư mục chứa file các tex, sagetex.sty, sagetex.py biên dịch bằng sage như sau:
    sage pascal.sage” Em không hiểu chỗ này biên dịch như thế nào, Thầy có thể giải thích cụ thể hơn được không Thầy. Em cài đặt sage trên Win

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s