\documentclass{book} %\usepackage{axiom} \usepackage{graphicx} % struggle with latex figure-floating behavior \renewcommand\floatpagefraction{.9} \renewcommand\topfraction{.9} \renewcommand\bottomfraction{.9} \renewcommand\textfraction{.1} \setcounter{totalnumber}{50} \setcounter{topnumber}{50} \setcounter{bottomnumber}{50} % spadcommands are the actual text that you type at the axiom prompt \newcommand{\spadcommand}[1]% {\begin{flushleft}{\tt #1}\end{flushleft}\vskip .1cm } % spadgraph are the actual text that you type at the axiom prompt for draw \newcommand{\spadgraph}[1]% {\begin{flushleft}{\tt #1}\end{flushleft}\vskip .1cm } % returnType is the type signature returned by the axiom interpreter \newcommand{\returnType}[1]% {\begin{flushright}{\tt #1}\end{flushright}\vskip .1cm} % spadsig gives the standard -> notation for signatures \newcommand{\spadsig}[2]{{\sf #1 $\rightarrow$ #2}} % The book begins with some introductory material that is not really % listed as a chapter. This creates a header similar to \chapter. \newcommand{\pseudoChapter}[1]% {\vskip .5in \noindent {\Large{\bf #1}}\vskip .5in} % The book begins with some introductory material that is not really % listed as a section. This creates a header similar to \section. \newcommand{\pseudoSection}[1]% {\vskip .25in \noindent {\large{\bf #1}}\vskip .25in} % spadofFrom records the operation in the index and the domain in the index \newcommand{\spadopFrom}[2]{\index{library!operations!#1 @\begingroup \string\tt{} #1 \endgroup}\index{#2}``{\tt #1}''} % spadfunFrom records the function name and domain in the index \newcommand{\spadfunFrom}[2]{{\bf #1}\index{#1 @\begingroup \string\bf{} #1 \endgroup}\index{#2}} % special meanings for math characters \newcommand{\N}{\mbox{\bbold N}} \newcommand{\Natural}{\mbox{\bbold N}} \newcommand{\Z}{\mbox{\bbold Z}} \newcommand{\Integer}{\mbox{\bbold Z}} \newcommand{\Rational}{\mbox{\bbold Q}} \newcommand{\Q}{\mbox{\bbold Q}} \newcommand{\Complex}{\mbox{\bbold C}} \newcommand{\C}{{\mathcal C}} \newcommand{\Real}{\mbox{\bbold R}} \newcommand{\F}{{\mathcal F}} \newcommand{\R}{{\mathcal R}} % draw a box around a text block \newcommand\boxed[2]{% \begin{center} \begin{tabular}{|c|} \hline \begin{minipage}{#1} \normalsize {#2} \end{minipage}\\ \hline \end{tabular} \end{center}} \newcommand{\optArg}[1]{{{\tt [}{#1}{\tt ]}}} \newcommand{\argDef}[1]{{\tt ({#1})}} \newcommand{\funSyntax}[2]{{\bf #1}{\tt ({\small\it{#2}})}} \newcommand{\funArgs}[1]{{\tt ({\small\it {#1}})}\newline} \newcommand{\condata}[4]{{\bf #1} {\bf #2} {\bf #3} {\bf #4}} \def\glossaryTerm#1{{\bf #1}\index{#1}} \def\glossaryTermNoIndex#1{{\bf #1}} \def\glossarySyntaxTerm#1{{\tt #1}\index{#1}} \long\def\ourGloss#1#2{\par\pagebreak[3]{#1}\newline{#2}} \def\csch{\mathop{\rm csch}\nolimits} \def\erf{\mathop{\rm erf}\nolimits} \def\zag#1#2{ {{\hfill \left. {#1} \right|} \over {\left| {#2} \right. \hfill} } } % these bitmaps are used by HyperDoc \newdimen\commentWidth \commentWidth=11pc \newdimen\colGutterWidth \colGutterWidth=1pc \newdimen\baseLeftSkip \baseLeftSkip=\commentWidth \advance\baseLeftSkip by \colGutterWidth \newcommand\ExitBitmap{{\setlength{\unitlength}{0.01in}\begin{picture}(50,16)(0,0)\special{psfile=ps/exit.ps}\end{picture}}} \newcommand\ReturnBitmap{{\setlength{\unitlength}{0.01in}\begin{picture}(50,16)(0,0)\special{psfile=ps/home.ps}\end{picture}}} \newcommand\HelpBitmap{{\setlength{\unitlength}{0.01in}\begin{picture}(50,16)(0,0)\special{psfile=ps/help.ps}\end{picture}}} \newcommand\UpBitmap{{\setlength{\unitlength}{0.01in}\begin{picture}(50,16)(0,0)\special{psfile=ps/up.ps}\end{picture}}} \newcommand{\tpd}[5]{{\setlength{\unitlength}{0.01in}\begin{picture}(#1,#2)(#3,#4)\special{psfile=#5}\end{picture}}} \begin{document} \begin{titlepage} \center{\includegraphics{ps/axiomFront.ps}} \vskip 0.1in \includegraphics{ps/bluebayou.ps}\\ \vskip 0.1in {\Huge{The 30 Year Horizon}} \vskip 0.1in $$ \begin{array}{lll} Manuel\ Bronstein & William\ Burge & Timothy\ Daly \\ James\ Davenport & Michael\ Dewar & Martin\ Dunstan \\ Albrecht\ Fortenbacher & Patrizia\ Gianni & Johannes\ Grabmeier \\ Jocelyn\ Guidry & Richard\ Jenks & Larry\ Lambe \\ Michael\ Monagan & Scott\ Morrison & William\ Sit \\ Jonathan\ Steinbach & Robert\ Sutor & Barry\ Trager \\ Stephen\ Watt & Jim\ Wen & Clifton\ Williamson \end{array} $$ \center{\large{VOLUME 2: PROGRAMMING}} \end{titlepage} \pagenumbering{roman} \begin{verbatim} The Blue Bayou image Copyright (c) 2004 Jocelyn Guidry Portions Copyright (c) 2004 Martin Dunstan Portions Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. All rights reserved. This book and the Axiom software is licensed as follows: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of The Numerical ALgorithms Group Ltd. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \end{verbatim} \tableofcontents \vfill \eject \setlength{\parindent}{0em} \setlength{\parskip}{1ex} {\Large{\bf New Foreword}} \vskip .25in On October 1, 2001 Axiom was withdrawn from the market and ended life as a commercial product. On September 3, 2002 Axiom was released under the Modified BSD license, including this document. On August 27, 2003 Axiom was released as free and open source software available for download from the Free Software Foundation's website, Savannah. Work on Axiom has had the generous support of the Center for Algorithms and Interactive Scientific Computation (CAISS) at City College of New York. Special thanks go to Dr. Gilbert Baumslag for his support of the long term goal. The online version of this documentation is roughly 1000 pages. In order to make printed versions we've broken it up into three volumes. The first volume is tutorial in nature. The second volume is for programmers. The third volume is reference material. We've also added a fourth volume for developers. All of these changes represent an experiment in print-on-demand delivery of documentation. Time will tell whether the experiment succeeded. Axiom has been in existence for over thirty years. It is estimated to contain about three hundred man-years of research and has, as of September 3, 2003, 143 people listed in the credits. All of these people have contributed directly or indirectly to making Axiom available. Axiom is being passed to the next generation. I'm looking forward to future milestones. With that in mind I've introduced the theme of the ``30 year horizon''. We must invent the tools that support the Computational Mathematician working 30 years from now. How will research be done when every bit of mathematical knowledge is online and instantly available? What happens when we scale Axiom by a factor of 100, giving us 1.1 million domains? How can we integrate theory with code? How will we integrate theorems and proofs of the mathematics with space-time complexity proofs and running code? What visualization tools are needed? How do we support the conceptual structures and semantics of mathematics in effective ways? How do we support results from the sciences? How do we teach the next generation to be effective Computational Mathematicians? The ``30 year horizon'' is much nearer than it appears. \vskip .25in %\noindent Tim Daly\\ CAISS, City College of New York\\ November 10, 2003 ((iHy)) \vfill \eject \pagenumbering{arabic} \pseudoChapter{Introduction to Axiom} \label{ugNewIntro} \section{Introduction to Axiom} Welcome to the world of Axiom. We call Axiom a scientific computation system: a self-contained toolbox designed to meet your scientific programming needs, from symbolics, to numerics, to graphics. This introduction is a quick overview of what Axiom offers. \subsection{Symbolic Computation} Axiom provides a wide range of simple commands for symbolic mathematical problem solving. Do you need to solve an equation, to expand a series, or to obtain an integral? If so, just ask Axiom to do it. Given $$\int\left({{1\over{(x^3 \ {(a+b x)}^{1/3})}}}\right)dx$$ we would enter this into Axiom as: \spadcommand{integrate(1/(x**3 * (a+b*x)**(1/3)),x)} which would give the result: $$ {\left( \begin{array}{@{}l} \displaystyle -{2 \ {b^2}\ {x^2}\ {\sqrt{3}}\ {\log \left({{{\root{3}\of{a}}\ {{\root{3}\of{{b \ x}+ a}}^2}}+{{{\root{3}\of{a}}^2}\ {\root{3}\of{{b \ x}+ a}}}+ a}\right)}}+ \\ \\ \displaystyle {4 \ {b^2}\ {x^2}\ {\sqrt{3}}\ {\log \left({{{{\root{3}\of{a}}^ 2}\ {\root{3}\of{{b \ x}+ a}}}- a}\right)}}+ \\ \\ \displaystyle {{12}\ {b^2}\ {x^2}\ {\arctan \left({{{2 \ {\sqrt{3}}\ {{\root{3}\of{a}}^ 2}\ {\root{3}\of{{b \ x}+ a}}}+{a \ {\sqrt{3}}}}\over{3 \ a}}\right)}}+ \\ \\ \displaystyle {{\left({{12}\ b \ x}-{9 \ a}\right)}\ {\sqrt{3}}\ {\root{3}\of{a}}\ {{\root{3}\of{{b \ x}+ a}}^2}} \end{array} \right)}\over{{18}\ {a^2}\ {x^2}\ {\sqrt{3}}\ {\root{3}\of{a}}} $$ \returnType{Type: Union(Expression Integer,...)} Axiom provides state-of-the-art algebraic machinery to handle your most advanced symbolic problems. For example, Axiom's integrator gives you the answer when an answer exists. If one does not, it provides a proof that there is no answer. Integration is just one of a multitude of symbolic operations that Axiom provides. \subsection{Numeric Computation} Axiom has a numerical library that includes operations for linear algebra, solution of equations, and special functions. For many of these operations, you can select any number of floating point digits to be carried out in the computation. Solve $x^{49}-49x^4+9$ to 49 digits of accuracy. First we need to change the default output length of numbers: \spadcommand{digits(49)} and then we execute the command: \spadcommand{solve(x**49-49*x**4+9 = 0,1.e-49)} $$ \begin{array}{@{}l} \displaystyle \left[{x = -{0.6546536706904271136718122105095984761851224331 556}}, \right. \\ \\ \displaystyle \left.{x ={1.086921395653859508493939035954893289009213388763}}, \right. \\ \\ \displaystyle \left.{x ={0.654653670725527173969468606613676483536148760766 1}}\right] \end{array} $$ \returnType{Type: List Equation Polynomial Float} The output of a computation can be converted to FORTRAN to be used in a later numerical computation. Besides floating point numbers, Axiom provides literally dozens of kinds of numbers to compute with. These range from various kinds of integers, to fractions, complex numbers, quaternions, continued fractions, and to numbers represented with an arbitrary base. What is $10$ to the $90$-th power in base $32$? \spadcommand{radix(10**90,32)} returns: %\noindent {\tt FMM3O955CSEIV0ILKH820CN3I7PICQU0OQMDOFV6TP000000000000000000 } \returnType{Type: RadixExpansion 32} The AXIOM numerical library can be enhanced with a substantial number of functions from the NAG library of numerical and statistical algorithms. These functions will provide coverage of a wide range of areas including roots of functions, Fourier transforms, quadrature, differential equations, data approximation, non-linear optimization, linear algebra, basic statistics, step-wise regression, analysis of variance, time series analysis, mathematical programming, and special functions. Contact the Numerical Algorithms Group Limited, Oxford, England. \subsection{Graphics} You may often want to visualize a symbolic formula or draw a graph from a set of numerical values. To do this, you can call upon the Axiom graphics capability. Draw $J_0(\sqrt{x^2+y^2})$ for $-20 \leq x,y \leq 20$. \spadcommand{draw(5*besselJ(0,sqrt(x**2+y**2)), x=-20..20, y=-20..20)} \begin{figure}[htbp] \includegraphics[bbllx=1, bblly=39, bburx=298, bbury=290]{ps/bessintr.ps} \caption{$J_0(\sqrt{x^2+y^2})$ for $-20 \leq x,y \leq 20$} \label{tpdhere} \end{figure} Graphs in Axiom are interactive objects you can manipulate with your mouse. Just click on the graph, and a control panel pops up. Using this mouse and the control panel, you can translate, rotate, zoom, change the coloring, lighting, shading, and perspective on the picture. You can also generate a PostScript copy of your graph to produce hard-copy output. \subsection{HyperDoc} \begin{figure}[htbp] \includegraphics[bbllx=1, bblly=1, bburx=298, bbury=290]{ps/h-root.ps} \caption{Hyperdoc opening menu} \label{fig-intro-br} \end{figure} HyperDoc presents you windows on the world of Axiom, offering on-line help, examples, tutorials, a browser, and reference material. HyperDoc gives you on-line access to this document in a ``hypertext'' format. Words that appear in a different font (for example, {\tt Matrix}, {\bf factor}, and {\it category}) are generally mouse-active; if you click on one with your mouse, HyperDoc shows you a new window for that word. As another example of a HyperDoc facility, suppose that you want to compute the roots of $x^{49} - 49x^4 + 9$ to 49 digits (as in our previous example) and you don't know how to tell Axiom to do this. The ``basic command'' facility of HyperDoc leads the way. Through the series of HyperDoc windows shown in Figure \ref{fig-intro-br} on page~\pageref{fig-intro-br} and the specified mouse clicks, you and HyperDoc generate the correct command to issue to compute the answer. \subsection{Interactive Programming } Axiom's interactive programming language lets you define your own functions. A simple example of a user-defined function is one that computes the successive Legendre polynomials. Axiom lets you define these polynomials in a piece-wise way. The first Legendre polynomial. \spadcommand{p(0) == 1} \returnType{Type: Void} The second Legendre polynomial. \spadcommand{p(1) == x} \returnType{Type: Void} The $n$-th Legendre polynomial for $(n > 1)$. \spadcommand{p(n) == ((2*n-1)*x*p(n-1) - (n-1) * p(n-2))/n} \returnType{Type: Void} In addition to letting you define simple functions like this, the interactive language can be used to create entire application packages. All the graphs in the Axiom images section were created by programs written in the interactive language. The above definitions for $p$ do no computation---they simply tell Axiom how to compute $p(k)$ for some positive integer $k$. To actually get a value of a Legendre polynomial, you ask for it. \index{Legendre polynomials} What is the tenth Legendre polynomial? \spadcommand{p(10)} \begin{verbatim} Compiling function p with type Integer -> Polynomial Fraction Integer Compiling function p as a recurrence relation. \end{verbatim} $$ {{{46189} \over {256}} \ {x \sp {10}}} -{{{109395} \over {256}} \ {x \sp 8}}+{{{45045} \over {128}} \ {x \sp 6}} -{{{15015} \over {128}} \ {x \sp 4}}+{{{3465} \over {256}} \ {x \sp 2}} -{{63} \over {256}} $$ \returnType{Type: Polynomial Fraction Integer} Axiom applies the above pieces for $p$ to obtain the value of $p(10)$. But it does more: it creates an optimized, compiled function for $p$. The function is formed by putting the pieces together into a single piece of code. By {\it compiled}, we mean that the function is translated into basic machine-code. By {\it optimized}, we mean that certain transformations are performed on that code to make it run faster. For $p$, Axiom actually translates the original definition that is recursive (one that calls itself) to one that is iterative (one that consists of a simple loop). What is the coefficient of $x^{90}$ in $p(90)$? \spadcommand{coefficient(p(90),x,90)} $$ {5688265542052017822223458237426581853561497449095175} \over {77371252455336267181195264} $$ \returnType{Type: Polynomial Fraction Integer} In general, a user function is type-analyzed and compiled on first use. Later, if you use it with a different kind of object, the function is recompiled if necessary. \subsection{Data Structures} A variety of data structures are available for interactive use. These include strings, lists, vectors, sets, multisets, and hash tables. A particularly useful structure for interactive use is the infinite stream: Create the infinite stream of derivatives of Legendre polynomials. \spadcommand{[D(p(i),x) for i in 1..]} $$ \begin{array}{@{}l} \displaystyle \left[ 1, {3 \ x}, {{{{15}\over 2}\ {x^2}}-{3 \over 2}}, {{{{35}\over 2}\ {x^3}}-{{{15}\over 2}\ x}}, {{{{315}\over 8}\ {x^4}}-{{{105}\over 4}\ {x^2}}+{{15}\over 8}}, \right. \\ \\ \displaystyle \left.{{{{693}\over 8}\ {x^5}}-{{{315}\over 4}\ {x^3}}+{{{105}\over 8}\ x}}, {{{{3003}\over{16}}\ {x^6}}-{{{3465}\over{16}}\ {x^ 4}}+{{{945}\over{16}}\ {x^2}}-{{35}\over{16}}}, \right. \\ \\ \displaystyle \left.{{{{6435}\over{16}}\ {x^7}}-{{{9009}\over{16}}\ {x^5}}+ {{{3465}\over{16}}\ {x^3}}-{{{315}\over{16}}\ x}}, \right. \\ \\ \displaystyle \left.{{{{109395}\over{128}}\ {x^8}}-{{{45045}\over{32}}\ {x^ 6}}+{{{45045}\over{64}}\ {x^4}}-{{{3465}\over{32}}\ {x^2}}+{{3 15}\over{128}}}, \right. \\ \\ \displaystyle \left.{{{{230945}\over{128}}\ {x^9}}-{{{109395}\over{32}}\ {x^ 7}}+{{{135135}\over{64}}\ {x^5}}-{{{15015}\over{32}}\ {x^3}}+ {{{3465}\over{128}}\ x}}, \ldots \right] \end{array} $$ \returnType{Type: Stream Polynomial Fraction Integer} Streams display only a few of their initial elements. Otherwise, they are ``lazy'': they only compute elements when you ask for them. Data structures are an important component for building application software. Advanced users can represent data for applications in optimal fashion. In all, Axiom offers over forty kinds of aggregate data structures, ranging from mutable structures (such as cyclic lists and flexible arrays) to storage efficient structures (such as bit vectors). As an example, streams are used as the internal data structure for power series. What is the series expansion of $\log(\cot(x))$ about $x=\pi/2$? %NOTE: The book has a different answer (see p6) \spadcommand{series(log(cot(x)),x = \%pi/2)} $$ \begin{array}{@{}l} \displaystyle {\log \left({{-{2 \ x}+ \pi}\over 2}\right)}+ {{1 \over 3}\ {{\left(x -{\pi \over 2}\right)}^2}}+ {{7 \over{90}}\ {{\left(x -{\pi \over 2}\right)}^4}}+ {{{62}\over{2835}}\ {{\left(x -{\pi \over 2}\right)}^6}}+ \\ \\ \displaystyle {{{127}\over{18900}}\ {{\left(x -{\pi \over 2}\right)}^8}}+ {{{146}\over{66825}}\ {{\left(x -{\pi \over 2}\right)}^{10}}}+ {O \left({{\left(x -{\pi \over 2}\right)}^{11}}\right)} \end{array} $$ \returnType{Type: GeneralUnivariatePowerSeries(Expression Integer,x,pi/2)} Series and streams make no attempt to compute {\it all} their elements! Rather, they stand ready to deliver elements on demand. What is the coefficient of the $50$-th term of this series? \spadcommand{coefficient(\%,50)} $$ {44590788901016030052447242300856550965644} \over {7131469286438669111584090881309360354581359130859375} $$ \returnType{Type: Expression Integer} \subsection{Mathematical Structures} Axiom also has many kinds of mathematical structures. These range from simple ones (like polynomials and matrices) to more esoteric ones (like ideals and Clifford algebras). Most structures allow the construction of arbitrarily complicated ``types.'' Even a simple input expression can result in a type with several levels. \spadcommand{matrix [ [x + \%i,0], [1,-2] ]} $$ \left[ \begin{array}{cc} {x+i} & 0 \\ 1 & -2 \end{array} \right] $$ \returnType{Type: Matrix Polynomial Complex Integer} The Axiom interpreter builds types in response to user input. Often, the type of the result is changed in order to be applicable to an operation. The inverse operation requires that elements of the above matrices are fractions. \spadcommand{inverse(\%)} $$ \left[ \begin{array}{cc} {1 \over {x+i}} & 0 \\ {1 \over {{2 \ x}+{2 \ i}}} & -{1 \over 2} \end{array} \right] $$ \returnType{Type: Union(Matrix Fraction Polynomial Complex Integer,...)} \subsection{Pattern Matching} A convenient facility for symbolic computation is ``pattern matching.'' Suppose you have a trigonometric expression and you want to transform it to some equivalent form. Use a $rule$ command to describe the transformation rules you \index{rule} need. Then give the rules a name and apply that name as a function to your trigonometric expression. Introduce two rewrite rules. \spadcommand{sinCosExpandRules := rule\\ \ \ sin(x+y) == sin(x)*cos(y) + sin(y)*cos(x)\\ \ \ cos(x+y) == cos(x)*cos(y) - sin(x)*sin(y)\\ \ \ sin(2*x) == 2*sin(x)*cos(x)\\ \ \ cos(2*x) == cos(x)**2 - sin(x)**2 } \begin{verbatim} {sin(y + x) == cos(x)sin(y) + cos(y)sin(x), cos(y + x) == - sin(x)sin(y) + cos(x)cos(y), sin(2x) == 2cos(x)sin(x), 2 2 cos(2x) == - sin(x) + cos(x) } \end{verbatim} \returnType{Type: Ruleset(Integer,Integer,Expression Integer)} Apply the rules to a simple trigonometric expression. \spadcommand{sinCosExpandRules(sin(a+2*b+c))} $$ \begin{array}{@{}l} \displaystyle {{\left(-{{\cos \left({a}\right)}\ {{\sin \left({b}\right)}^2}}- {2 \ {\cos \left({b}\right)}\ {\sin \left({a}\right)}\ {\sin \left({b}\right)}}+{{\cos \left({a}\right)}\ {{\cos \left({b}\right)}^ 2}}\right)}\ {\sin \left({c}\right)}}- \\ \\ \displaystyle {{\cos \left({c}\right)}\ {\sin \left({a}\right)}\ {{\sin \left({b}\right)}^ 2}}+{2 \ {\cos \left({a}\right)}\ {\cos \left({b}\right)}\ {\cos \left({c}\right)}\ {\sin \left({b}\right)}}+ \\ \\ \displaystyle {{{\cos \left({b}\right)}^2}\ {\cos \left({c}\right)}\ {\sin \left({a}\right)}} \end{array} $$ \returnType{Type: Expression Integer} Using input files, you can create your own library of transformation rules relevant to your applications, then selectively apply the rules you need. \subsection{Polymorphic Algorithms} All components of the Axiom algebra library are written in the Axiom library language. This language is similar to the interactive language except for protocols that authors are obliged to follow. The library language permits you to write ``polymorphic algorithms,'' algorithms defined to work in their most natural settings and over a variety of types. Define a system of polynomial equations $S$. \spadcommand{S := [3*x**3 + y + 1 = 0,y**2 = 4]} $$ \left[ {{y+{3 \ {x \sp 3}}+1}=0}, {{y \sp 2}=4} \right] $$ \returnType{Type: List Equation Polynomial Integer} Solve the system $S$ using rational number arithmetic and 30 digits of accuracy. \spadcommand{solve(S,1/10**30)} $$ \left[ {\left[ {y=-2}, {x={{1757879671211184245283070414507} \over {2535301200456458802993406410752}}} \right]}, {\left[ {y=2}, {x=-1} \right]} \right] $$ \returnType{Type: List List Equation Polynomial Fraction Integer} Solve $S$ with the solutions expressed in radicals. \spadcommand{radicalSolve(S)} $$ \begin{array}{@{}l} \displaystyle \left[{\left[{y = 2}, {x = - 1}\right]}, {\left[{y = 2}, {x ={{-{\sqrt{- 3}}+ 1}\over 2}}\right]}, \right. \\ \\ \displaystyle \left.{\left[{y = 2}, {x ={{{\sqrt{- 3}}+ 1}\over 2}}\right]}, {\left[{y = - 2}, {x ={1 \over{\root{3}\of{3}}}}\right]}, \right. \\ \\ \displaystyle \left.{\left[{y = - 2}, {x ={{{{\sqrt{- 1}}\ {\sqrt{3}}}- 1}\over{2 \ {\root{3}\of{3}}}}}\right]}, {\left[{y = - 2}, {x ={{-{{\sqrt{- 1}}\ {\sqrt{3}}}- 1}\over{2 \ {\root{3}\of{3}}}}}\right]}\right] \end{array} $$ \returnType{Type: List List Equation Expression Integer} While these solutions look very different, the results were produced by the same internal algorithm! The internal algorithm actually works with equations over any ``field.'' Examples of fields are the rational numbers, floating point numbers, rational functions, power series, and general expressions involving radicals. \subsection{Extensibility} Users and system developers alike can augment the Axiom library, all using one common language. Library code, like interpreter code, is compiled into machine binary code for run-time efficiency. Using this language, you can create new computational types and new algorithmic packages. All library code is polymorphic, described in terms of a database of algebraic properties. By following the language protocols, there is an automatic, guaranteed interaction between your code and that of colleagues and system implementers. \vfill\eject \pseudoChapter{A Technical Introduction} \label{ugTechIntro} Axiom has both an {\it interactive language} for user interactions and a {\it programming language} for building library modules. Like Modula 2, \index{Modula 2} PASCAL, \index{PASCAL} FORTRAN, \index{FORTRAN} and Ada, \index{Ada} the programming language emphasizes strict type-checking. Unlike these languages, types in Axiom are dynamic objects: they are created at run-time in response to user commands. Here is the idea of the Axiom programming language in a nutshell. Axiom types range from algebraic ones (like polynomials, matrices, and power series) to data structures (like lists, dictionaries, and input files). Types combine in any meaningful way. You can build polynomials of matrices, matrices of polynomials of power series, hash tables with symbolic keys and rational function entries, and so on. {\it Categories} define algebraic properties to ensure mathematical correctness. They ensure, for example, that matrices of polynomials are OK, but matrices of input files are not. Through categories, programs can discover that polynomials of continued fractions have a commutative multiplication whereas polynomials of matrices do not. Categories allow algorithms to be defined in their most natural setting. For example, an algorithm can be defined to solve polynomial equations over {\it any} field. Likewise a greatest common divisor can compute the ``gcd'' of two elements from {\it any} Euclidean domain. Categories foil attempts to compute meaningless ``gcds'', for example, of two hashtables. Categories also enable algorithms to be compiled into machine code that can be run with arbitrary types. The Axiom interactive language is oriented towards ease-of-use. The Axiom interpreter uses type-inferencing to deduce the type of an object from user input. Type declarations can generally be omitted for common types in the interactive language. So much for the nutshell. Here are these basic ideas described by ten design principles: \subsection{Types are Defined by Abstract Datatype Programs} Basic types are called {\it domains of computation}, or, simply, {\it domains.} \index{domain} Domains are defined by Axiom programs of the form: \begin{verbatim} Name(...): Exports == Implementation \end{verbatim} Each domain has a capitalized {\tt Name} that is used to refer to the class of its members. For example, {\tt Integer} denotes ``the class of integers,'' {\tt Float}, ``the class of floating point numbers,'' and {\tt String}, ``the class of strings.'' The ``{\tt ...}'' part following {\tt Name} lists zero or more parameters to the constructor. Some basic ones like {\tt Integer} take no parameters. Others, like {\tt Matrix}, {\tt Polynomial} and {\tt List}, take a single parameter that again must be a domain. For example, {\tt Matrix(Integer)} denotes ``matrices over the integers,'' {\tt Polynomial (Float)} denotes ``polynomial with floating point coefficients,'' and {\tt List (Matrix (Polynomial (Integer)))} denotes ``lists of matrices of polynomials over the integers.'' There is no restriction on the number or type of parameters of a domain constructor. SquareMatrix(2,Integer) is an example of a domain constructor that accepts both a particular data value as well as an integer. In this case the number 2 specifies the number of rows and columns the square matrix will contain. Elements of the matricies are integers. The {\tt Exports} part specifies operations for creating and manipulating objects of the domain. For example, type {\tt Integer} exports constants $0$ and $1$, and operations \spadopFrom{+}{Integer}, \spadopFrom{-}{Integer}, and \spadopFrom{*}{Integer}. While these operations are common, others such as \spadfunFrom{odd?}{Integer} and \spadfunFrom{bit?}{Integer} are not. In addition the Exports section can contain symbols that represent properties that can be tested. For example, the Category {\tt EntireRing} has the symbol {\tt noZeroDivisors} which asserts that if a product is zero then one of the factors must be zero. The {\tt Implementation} part defines functions that implement the exported operations of the domain. These functions are frequently described in terms of another lower-level domain used to represent the objects of the domain. Thus the operation of adding two vectors of real numbers can be described and implemented using the addition operation from {\tt Float}. \subsection{The Type of Basic Objects is a Domain or Subdomain} Every Axiom object belongs to a {\it unique} domain. The domain of an object is also called its {\it type.} Thus the integer $7$ has type {\tt Integer} and the string {\tt "daniel"} has type {\tt String}. The type of an object, however, is not unique. The type of integer $7$ is not only {\tt Integer} but {\tt NonNegativeInteger}, {\tt PositiveInteger}, and possibly, in general, any other ``subdomain'' of the domain {\tt Integer}. A {\it subdomain} \index{subdomain} is a domain with a ``membership predicate''. {\tt PositiveInteger} is a subdomain of {\tt Integer} with the predicate ``is the integer $> 0$?''. Subdomains with names are defined by abstract datatype programs similar to those for domains. The {\it Export} part of a subdomain, however, must list a subset of the exports of the domain. The {\tt Implementation} part optionally gives special definitions for subdomain objects. \subsection{Domains Have Types Called Categories} Domain and subdomains in Axiom are themselves objects that have types. The type of a domain or subdomain is called a {\it category}. \index{category} Categories are described by programs of the form: \begin{verbatim} Name(...): Category == Exports \end{verbatim} The type of every category is the distinguished symbol {\tt Category.} The category {\tt Name} is used to designate the class of domains of that type. For example, category {\tt Ring} designates the class of all rings. Like domains, categories can take zero or more parameters as indicated by the ``{\tt ...}'' part following {\tt Name.} Two examples are {\tt Module(R)} and {\tt MatrixCategory(R,Row,Col)}. The {\tt Exports} part defines a set of operations. For example, {\tt Ring} exports the operations \spadopFrom{0}{Ring}, \spadopFrom{1}{Ring}, \spadopFrom{+}{Ring}, \spadopFrom{-}{Ring}, and \spadopFrom{*}{Ring}. Many algebraic domains such as {\tt Integer} and {\tt Polynomial (Float)} are rings. {\tt String} and {\tt List (R)} (for any domain $R$) are not. Categories serve to ensure the type-correctness. The definition of matrices states {\tt Matrix(R: Ring)} requiring its single parameter $R$ to be a ring. Thus a ``matrix of polynomials'' is allowed, but ``matrix of lists'' is not. Categories say nothing about representation. Domains, which are instances of category types, specify representations. \subsection{Operations Can Refer To Abstract Types} All operations have prescribed source and target types. Types can be denoted by symbols that stand for domains, called ``symbolic domains.'' The following lines of Axiom code use a symbolic domain $R$: \begin{verbatim} R: Ring power: (R, NonNegativeInteger): R -> R power(x, n) == x ** n \end{verbatim} Line 1 declares the symbol $R$ to be a ring. Line 2 declares the type of $power$ in terms of $R$. From the definition on line 3, $power(3,2)$ produces 9 for $x = 3$ and $R =$ {\tt Integer}. Also, $power(3.0,2)$ produces $9.0$ for $x = 3.0$ and $R =$ {\tt Float}. $power("oxford",2)$ however fails since $"oxford"$ has type {\tt String} which is not a ring. Using symbolic domains, algorithms can be defined in their most natural or general setting. \subsection{Categories Form Hierarchies} Categories form hierarchies (technically, directed-acyclic graphs). A simplified hierarchical world of algebraic categories is shown below. At the top of this world is {\tt SetCategory}, the class of algebraic sets. The notions of parents, ancestors, and descendants is clear. Thus ordered sets (domains of category {\tt OrderedSet}) and rings are also algebraic sets. Likewise, fields and integral domains are rings and algebraic sets. However fields and integral domains are not ordered sets. \begin{verbatim} SetCategory +---- Ring ---- IntegralDomain ---- Field | +---- Finite ---+ | \ +---- OrderedSet -----+ OrderedFinite \end{verbatim} \begin{center} Figure 1. A simplified category hierarchy. \end{center} \subsection{Domains Belong to Categories by Assertion} A category designates a class of domains. Which domains? You might think that {\tt Ring} designates the class of all domains that export $0$, $1$, \spadopFrom{+}{Integer}, \spadopFrom{-}{Integer}, and \spadopFrom{*}{Integer}. But this is not so. Each domain must {\it assert} which categories it belongs to. The {\tt Export} part of the definition for {\tt Integer} reads, for example: \begin{verbatim} Join(OrderedSet, IntegralDomain, ...) with ... \end{verbatim} This definition asserts that {\tt Integer} is both an ordered set and an integral domain. In fact, {\tt Integer} does not explicitly export constants $0$ and $1$ and operations \spadopFrom{+}{Ring}, \spadopFrom{-}{Ring} and \spadopFrom{*}{Ring} at all: it inherits them all from $Ring$! Since {\tt IntegralDomain} is a descendant of $Ring$, {\tt Integer} is therefore also a ring. Assertions can be conditional. For example, {\tt Complex(R)} defines its exports by: \begin{verbatim} Ring with ... if R has Field then Field ... \end{verbatim} Thus {\tt Complex(Float)} is a field but {\tt Complex(Integer)} is not since {\tt Integer} is not a field. You may wonder: ``Why not simply let the set of operations determine whether a domain belongs to a given category?''. Axiom allows operation names (for example, {\bf norm}) to have very different meanings in different contexts. The meaning of an operation in Axiom is determined by context. By associating operations with categories, operation names can be reused whenever appropriate or convenient to do so. As a simple example, the operation {\tt <} might be used to denote lexicographic-comparison in an algorithm. However, it is wrong to use the same {\tt <} with this definition of absolute-value: $$abs(x) == if\ x < 0\ then -x\ else\ x$$ Such a definition for {\tt abs} in Axiom is protected by context: argument $x$ is required to be a member of a domain of category {\tt OrderedSet}. \subsection{Packages Are Clusters of Polymorphic Operations} In Axiom, facilities for symbolic integration, solution of equations, and the like are placed in ``packages''. A {\it package} \index{package} is a special kind of domain: one whose exported operations depend solely on the parameters of the constructor and/or explicit domains. Packages, unlike Domains, do not specify the representation. If you want to use Axiom, for example, to define some algorithms for solving equations of polynomials over an arbitrary field $F$, you can do so with a package of the form: \begin{verbatim} MySolve(F: Field): Exports == Implementation \end{verbatim} where {\tt Exports} specifies the {\bf solve} operations you wish to export from the domain and the {\tt Implementation} defines functions for implementing your algorithms. Once Axiom has compiled your package, your algorithms can then be used for any {\tt F}: floating-point numbers, rational numbers, complex rational functions, and power series, to name a few. \subsection{The Interpreter Builds Domains Dynamically} The Axiom interpreter reads user input then builds whatever types it needs to perform the indicated computations. For example, to create the matrix $$M = \pmatrix{x^2+1&0\cr0&x / 2\cr}$$ using the command: \spadcommand{M = [ [x**2+1,0],[0,x / 2] ]::Matrix(POLY(FRAC(INT)))} $$ M={\left[ \begin{array}{cc} x^2+1 & 0 \\ 0 & x/2 \end{array} \right]} $$ \returnType{Type: Matrix Polynomial Fraction Integer} the interpreter first loads the modules {\tt Matrix}, {\tt Polynomial}, {\tt Fraction}, and {\tt Integer} from the library, then builds the {\it domain tower} ``matrices of polynomials of rational numbers (i.e. fractions of integers)''. You can watch the loading process by first typing \spadcommand{)set message autoload on} In addition to the named domains above many additional domains and categories are loaded. Most systems are preloaded with such common types. For efficiency reasons the most common domains are preloaded but most (there are more than 1100 domains, categories, and packages) are not. Once these domains are loaded they are immediately available to the interpreter. Once a domain tower is built, it contains all the operations specific to the type. Computation proceeds by calling operations that exist in the tower. For example, suppose that the user asks to square the above matrix. To do this, the function \spadopFrom{*}{Matrix} from {\tt Matrix} is passed the matrix $M$ to compute $M * M$. The function is also passed an environment containing $R$ that, in this case, is {\tt Polynomial (Fraction (Integer))}. This results in the successive calling of the \spadopFrom{*}{Fraction} operations from {\tt Polynomial}, then from {\tt Fraction}, and then finally from {\tt Integer}. Categories play a policing role in the building of domains. Because the argument of {\tt Matrix} is required to be a {\tt Ring}, Axiom will not build nonsensical types such as ``matrices of input files''. \subsection{Axiom Code is Compiled} Axiom programs are statically compiled to machine code, then placed into library modules. Categories provide an important role in obtaining efficient object code by enabling: \begin{itemize} \item static type-checking at compile time; \item fast linkage to operations in domain-valued parameters; \item optimization techniques to be used for partially specified types (operations for ``vectors of $R$'', for instance, can be open-coded even though {\tt R} is unknown). \end{itemize} \subsection{Axiom is Extensible} Users and system implementers alike use the Axiom language to add facilities to the Axiom library. The entire Axiom library is in fact written in the Axiom source code and available for user modification and/or extension. Axiom's use of abstract datatypes clearly separates the exports of a domain (what operations are defined) from its implementation (how the objects are represented and operations are defined). Users of a domain can thus only create and manipulate objects through these exported operations. This allows implementers to ``remove and replace'' parts of the library safely by newly upgraded (and, we hope, correct) implementations without consequence to its users. Categories protect names by context, making the same names available for use in other contexts. Categories also provide for code-economy. Algorithms can be parameterized categorically to characterize their correct and most general context. Once compiled, the same machine code is applicable in all such contexts. Finally, Axiom provides an automatic, guaranteed interaction between new and old code. For example: \begin{itemize} \item if you write a new algorithm that requires a parameter to be a field, then your algorithm will work automatically with every field defined in the system; past, present, or future. \item if you introduce a new domain constructor that produces a field, then the objects of that domain can be used as parameters to any algorithm using field objects defined in the system; past, present, or future. \end{itemize} These are the key ideas. For further information, we particularly recommend your reading chapters 11, 12, and 13, where these ideas are explained in greater detail. \section{Using Axiom as a Pocket Calculator} At the simplest level Axiom can be used as a pocket calculator where expressions involving numbers and operators are entered directly in infix notation. In this sense the more advanced features of the calculator can be regarded as operators (e.g {\bf sin}, {\bf cos}, etc). \subsection{Basic Arithmetic} An example of this might be to calculate the cosine of 2.45 (in radians). To do this one would type: \spadcommand{cos 2.45} $$ -{0.7702312540 473073417} $$ \returnType{Type: Float} Before proceeding any further it would be best to explain the previous three lines. Firstly the text ``(1) {\tt ->} '' is part of the prompt that the Axiom system provides when in interactive mode. The full prompt has other text preceding this but it is not relevant here. The number in parenthesis is the step number of the input which may be used to refer to the {\sl results} of previous calculations. The step number appears at the start of the second line to tell you which step the result belongs to. Since the interpreter probably loaded numberous libraries to calculate the result given above and listed each one in the prcess, there could easily be several pages of text between your input and the answer. The last line contains the type of the result. The type {\tt Float} is used to represent real numbers of arbitrary size and precision (where the user is able to define how big arbitrary is -- the default is 20 digits but can be as large as your computer system can handle). The type of the result can help track down mistakes in your input if you don't get the answer you expected. Other arithmetic operations such as addition, subtraction, and multiplication behave as expected: \spadcommand{6.93 * 4.1328} $$ 28.640304 $$ \returnType{Type: Float} \spadcommand{6.93 / 4.1328} $$ 1.6768292682 926829268 $$ \returnType{Type: Float} but integer division isn't quite so obvious. For example, if one types: \spadcommand{4/6} $$ 2 \over 3 $$ \returnType{Type: Fraction Integer} a fractional result is obtained. The function used to display fractions attempts to produce the most readable answer. In the example: \spadcommand{4/2} $$ 2 $$ \returnType{Type: Fraction Integer} the result is stored as the fraction 2/1 but is displayed as the integer 2. This fraction could be converted to type {\tt Integer} with no loss of informatin but Axiom will not do so automatically. \subsection{Type Conversion} To obtain the floating point value of a fraction one must convert ( {\bf conversions} are applied by the user and {\bf coercions} are applied automatically by the interpreter) the result to type {\tt Float} using the ``::'' operator as follows: \spadcommand{(4.6)::Float} $$ 4.6 $$ \returnType{Type: Float} Although Axiom can convert this back to a fraction it might not be the same fraction you started with as due to rounding errors. For example, the following conversion appears to be without error but others might not: \spadcommand{\%::Fraction Integer} $$ {23} \over 5 $$ \returnType{Type: Fraction Integer} where ``\%'' represents the previous {\it result} (not the calculation). Although Axiom has the ability to work with floating-point numbers to a very high precision it must be remembered that calculations with these numbers are {\bf not} exact. Since Axiom is a computer algebra package and not a numerical solutions package this should not create too many problems. The idea is that the user should use Axiom to do all the necessary symbolic manipulation and only at the end should actual numerical results be extracted. If you bear in mind that Axiom appears to store expressions just as you have typed them and does not perform any evalutation of them unless forced to then programming in the system will be much easier. It means that anything you ask Axiom to do (within reason) will be carried with complete accuracy. In the previous examples the ``::'' operator was used to convert values from one type to another. This type conversion is not possible for all values. For instance, it is not possible to convert the number 3.4 to an integer type since it can't be represented as an integer. The number 4.0 can be converted to an integer type since it has no fractional part. Conversion from floating point values to integers is performed using the functions {\bf round} and {\bf truncate}. The first of these rounds a floating point number to the nearest integer while the other truncates (i.e. removes the fractional part). Both functions return the result as a {\bf floating point} number. To extract the fractional part of a floating point number use the function {\bf fractionPart} but note that the sign of the result depends on the sign of the argument. Axiom obtains the fractional partof $x$ using $x - truncate(x)$: \spadcommand{round(3.77623)} $$ 4.0 $$ \returnType{Type: Float} \spadcommand{round(-3.77623)} $$ -{4.0} $$ \returnType{Type: Float} \spadcommand{truncate(9.235)} $$ 9.0 $$ \returnType{Type: Float} \spadcommand{truncate(-9.654)} $$ -{9.0} $$ \returnType{Type: Float} \spadcommand{fractionPart(-3.77623)} $$ -{0.77623} $$ \returnType{Type: Float} \subsection{Useful Functions} To obtain the absolute value of a number the {\bf abs} function can be used. This takes a single argument which is usually an integer or a floating point value but doesn't necessarily have to be. The sign of a value can be obtained via the {\bf sign} function which rturns $-1$, $0$, or $1$ depending on the sign of the argument. \spadcommand{abs(4)} $$ 4 $$ \returnType{Type: PositiveInteger} \spadcommand{abs(-3)} $$ 3 $$ \returnType{Type: PositiveInteger} \spadcommand{abs(-34254.12314)} $$ 34254.12314 $$ \returnType{Type: Float} \spadcommand{sign(-49543.2345346)} $$ -1 $$ \returnType{Type: Integer} \spadcommand{sign(0)} $$ 0 $$ \returnType{Type: NonNegativeInteger} \spadcommand{sign(234235.42354)} $$ 1 $$ \returnType{Type: PositiveInteger} Tests on values can be done using various functions which are generally more efficient than using relational operators such as $=$ particularly if the value is a matrix. Examples of some of these functions are: \spadcommand{positive?(-234)} $$ {\tt false} $$ \returnType{Type: Boolean} \spadcommand{negative?(-234)} $$ {\tt true} $$ \returnType{Type: Boolean} \spadcommand{zero?(42)} $$ {\tt false} $$ \returnType{Type: Boolean} \spadcommand{one?(1)} $$ {\tt true} $$ \returnType{Type: Boolean} \spadcommand{odd?(23)} $$ {\tt true} $$ \returnType{Type: Boolean} \spadcommand{odd?(9.435)} $$ {\tt false} $$ \returnType{Type: Boolean} \spadcommand{even?(-42)} $$ {\tt true} $$ \returnType{Type: Boolean} \spadcommand{prime?(37)} $$ {\tt true} $$ \returnType{Type: Boolean} \spadcommand{prime?(-37)} $$ {\tt false} $$ \returnType{Type: Boolean} Some other functions that are quite useful for manipulating numerical values are: \begin{verbatim} sin(x) Sine of x cos(x) Cosine of x tan(x) Tangent of x asin(x) Arcsin of x acos(x) Arccos of x atan(x) Arctangent of x gcd(x,y) Greatest common divisor of x and y lcm(x,y) Lowest common multiple of x and y max(x,y) Maximum of x and y min(x,y) Minimum of x and y factorial(x) Factorial of x factor(x) Prime factors of x divide(x,y) Quotient and remainder of x/y \end{verbatim} Some simple infix and prefix operators: \begin{verbatim} + Addition - Subtraction - Numerical Negation ~ Logical Negation /\ Conjunction (AND) \/ Disjunction (OR) and Logical AND (/\) or Logical OR (\/) not Logical Negation ** Exponentiation * Multiplication / Division quo Quotient rem Remainder < less than > greater than <= less than or equal >= greater than or equal \end{verbatim} Some useful Axiom macros: \begin{verbatim} %i The square root of -1 %e The base of the natural logarithm %pi Pi %infinity Infinity %plusInfinity Positive Infinity %minusInfinity Negative Infinity \end{verbatim} \section{Using Axiom as a Symbolic Calculator} In the previous section all the examples involved numbers and simple functions. Also none of the expressions entered were assigned to anything. In this section we will move on to simple algebra (i.e. expressions involving symbols and other features available on more sophisticated calculators). \subsection{Expressions Involving Symbols} Expressions involving symbols are entered just as they are written down, for example: \spadcommand{xSquared := x**2} $$ x \sp 2 $$ \returnType{Type: Polynomial Integer} where the assignment operator ``:='' represents immediate assignment. Later it will be seen that this form of assignment is not always desirable and the use of the delayed assignment operator ``=='' will be introduced. The type of the result is {\tt Polynomial Integer} which is used to represent polynomials with integer coefficients. Some other examples along similar lines are: \spadcommand{xDummy := 3.21*x**2} $$ {3.21} \ {x \sp 2} $$ \returnType{Type: Polynomial Float} \spadcommand{xDummy := x**2.5} $$ {x \sp 2} \ {\sqrt {x}} $$ \returnType{Type: Expression Float} \spadcommand{xDummy := x**3.3} $$ {x \sp 3} \ {{\root {{10}} \of {x}} \sp 3} $$ \returnType{Type: Expression Float} \spadcommand{xyDummy := x**2 - y**2} $$ -{y \sp 2}+{x \sp 2} $$ \returnType{Type: Polynomial Integer} Given that we can define expressions involving symbols, how do we actually compute the result when the symbols are assigned values? The answer is to use the {\bf eval} function which takes an expression as its first argument followed by a list of assignments. For example, to evaluate the expressions {\bf XDummy} and {xyDummy} resulting from their respective assignments above we type: \spadcommand{eval(xDummy,x=3)} $$ 37.5405075985 29552193 $$ \returnType{Type: Expression Float} \spadcommand{eval(xyDummy, [x=3, y=2.1])} $$ 4.59 $$ \returnType{Type: Polynomial Float} \subsection{Complex Numbers} For many scientific calculations real numbers aren't sufficient and support for complex numbers is also required. Complex numbers are handled in an intuitive manner and Axiom, which uses the {\bf \%i} macro to represent the square root of $-1$. Thus expressions involving complex numbers are entered just like other expressions. \spadcommand{(2/3 + \%i)**3} $$ -{{46} \over {27}}+{{1 \over 3} \ i} $$ \returnType{Type: Complex Fraction Integer} The real and imaginary parts of a complex number can be extracted using the {\bf real} and {\bf imag} functions and the complex conjugate of a number can be obtained using {\bf conjugate}: \spadcommand{real(3 + 2*\%i)} $$ 3 $$ \returnType{Type: PositiveInteger} \spadcommand{imag(3+ 2*\%i)} $$ 2 $$ \returnType{Type: PositiveInteger} \spadcommand{conjugate(3 + 2*\%i)} $$ 3 -{2 \ i} $$ \returnType{Type: Complex Integer} The function {\bf factor} can also be applied to complex numbers but the results aren't quite so obvious as for factoring integer: \spadcommand{144 + 24*\%i} $$ {144}+{{24} \ i} $$ \returnType{Type: Complex Integer} \subsection{Number Representations} By default all numerical results are displayed in decimal with real numbers shown to 20 significant figures. If the integer part of a number is longer than 20 digits then nothing after the decimal point is shown and the integer part is given in full. To alter the number of digits shown the function {\bf digits} can be called. The result returned by this function is the previous setting. For example, to find the value of $\pi$ to 40 digits we type: \spadcommand{digits(40)} $$ 20 $$ \returnType{Type: PositiveInteger} \spadcommand{\%pi::Float} $$ 3.1415926535\ 8979323846\ 2643383279\ 502884197 $$ \returnType{Type: Float} As can be seen in the example above, there is a gap after every ten digits. This can be changed using the {\bf outputSpacing} function where the argument is the number of digits to be displayed before a space is inserted. If no spaces are desired then use the value $0$. Two other functions controlling the appearance of real numbers are {\bf outputFloating} and {\bf outputFixed}. The former causes Axiom to display floating-point values in exponent notation and the latter causes it to use fixed-point notation. For example: \spadcommand{outputFloating(); \%} $$ 0.3141592653 5897932384 6264338327 9502884197 E 1 $$ \returnType{Type: Float} \spadcommand{outputFloating(3); 0.00345} $$ 0.345 E -2 $$ \returnType{Type: Float} \spadcommand{outputFixed(); \%} $$ 0.00345 $$ \returnType{Type: Float} \spadcommand{outputFixed(3); \%} $$ 0.003 $$ \returnType{Type: Float} \spadcommand{outputGeneral(); \%} $$ 0.00345 $$ \returnType{Type: Float} Note that the semicolon ``;'' in the examples above allows several expressions to be entered on one line. The result of the last expression is displayed. remember also that the percent symbol ``\%'' is used to represent the result of a previous calculation. To display rational numbers in a base other than 10 the function {\bf radix} is used. The first argument of this function is the expression to be displayed and the second is the base to be used. \spadcommand{radix(10**10,32)} $$ {\rm 9A0NP00 } $$ \returnType{Type: RadixExpansion 32} \spadcommand{radix(3/21,5)} $$ 0.{\overline {032412}} $$ \returnType{Type: RadixExpansion 5} Rational numbers can be represented as a repeated decimal expansion using the {\bf decimal} function or as a continued fraction using {\bf continuedFraction}. Any attempt to call these functions with irrational values will fail. \spadcommand{decimal(22/7)} $$ 3.{\overline {142857}} $$ \returnType{Type: DecimalExpansion} \spadcommand{continuedFraction(6543/210)} $$ {31}+ \zag{1}{6}+ \zag{1}{2}+ \zag{1}{1}+ \zag{1}{3} $$ \returnType{Type: ContinuedFraction Integer} Finally, partial fractions in compact and expanded form are available via the functions {\bf partialFraction} and {\bf padicFraction} respectively. The former takes two arguments, the first being the numerator of the fraction and the second being the denominator. The latter function takes a fraction and expands it further while the function {\bf compactFraction} does the reverse: \spadcommand{partialFraction(234,40)} $$ 6 -{3 \over {2 \sp 2}}+{3 \over 5} $$ \returnType{Type: PartialFraction Integer} \spadcommand{padicFraction(\%)} $$ 6 -{1 \over 2} -{1 \over {2 \sp 2}}+{3 \over 5} $$ \returnType{Type: PartialFraction Integer} \spadcommand{compactFraction(\%)} $$ 6 -{3 \over {2 \sp 2}}+{3 \over 5} $$ \returnType{Type: PartialFraction Integer} \spadcommand{padicFraction(234/40)} $$ {117} \over {20} $$ \returnType{Type: PartialFraction Fraction Integer} To extract parts of a partial fraction the function {\bf nthFractionalTerm} is available and returns a partial fraction of one term. To decompose this further the numerator can be obtained using {\bf firstNumer} and the denominator with {\bf firstDenom}. The whole part of a partial fraction can be retrieved using {\bf wholePart} and the number of fractional parts can be found using the function {\bf numberOf FractionalTerms}: \spadcommand{t := partialFraction(234,40)} $$ 6 -{3 \over {2 \sp 2}}+{3 \over 5} $$ \returnType{Type: PartialFraction Integer} \spadcommand{wholePart(t)} $$ 6 $$ \returnType{Type: PositiveInteger} \spadcommand{numberOfFractionalTerms(t)} $$ 2 $$ \returnType{Type: PositiveInteger} \spadcommand{p := nthFractionalTerm(t,1)} $$ -{3 \over {2 \sp 2}} $$ \returnType{Type: PartialFraction Integer} \spadcommand{firstNumer(p)} $$ -3 $$ \returnType{Type: Integer} \spadcommand{firstDenom(p)} $$ 2 \sp 2 $$ \returnType{Type: Factored Integer} \subsection{Modular Arithmetic} By using the type constructor {\tt PrimeField} it is possible to do arithmetic modulo some prime number. For example, arithmetic module $7$ can be performed as follows: \spadcommand{x : PrimeField 7 := 5} $$ 5 $$ \returnType{Type: PrimeField 7} \spadcommand{x**5 + 6} $$ 2 $$ \returnType{Type: PrimeField 7} \spadcommand{1/x} $$ 3 $$ \returnType{Type: PrimeField 7} The first example should be read as: \begin{center} {\tt Let $x$ be of type PrimeField(7) and assign to it the value $5$} \end{center} Note that it is only possible to invert non-zero values if the arithmetic is performed modulo a prime number. Thus arithmetic modulo a non-prime integer is possible but the reciprocal operation is undefined and will generate an error. Attempting to use the {\tt PrimeField} type constructor with a non-prime argument will generate an error. An example of non-prime modulo arithmetic is: \spadcommand{y : IntegerMod 8 := 11} $$ 3 $$ \returnType{Type: IntegerMod 8} \spadcommand{y*4 + 27} $$ 7 $$ \returnType{Type: IntegerMod 8} Note that polynomials can be constructed in a similar way: \spadcommand{(3*a**4 + 27*a - 36)::Polynomial PrimeField 7} $$ {3 \ {a \sp 4}}+{6 \ a}+6 $$ \returnType{Type: Polynomial PrimeField 7} \section{General Points about Axiom} \subsection{Computation Without Output} It is sometimes desirable to enter an expression and prevent Axiom from displaying the result. To do this the expression should be terminated with a semicolon ``;''. In a previous section it was mentioned that a set of expressions separated by semicolons would be evaluated and the result of the last one displayed. Thus if a single expression is followed by a semicolon no output will be produced (except for its type): \spadcommand{2 + 4*5;} \returnType{Type: PositiveInteger} \subsection{Accessing Earlier Results} The ``\%'' macro represents the result of the previous computation. The ``\%\%'' macro is available which takes a single integer argument. If the argument is positive then it refers to the step number of the calculation where the numbering begins from one and can be seen at the end of each prompt (the number in parentheses). If the argument is negative then it refers to previous results counting backwards from the last result. That is, ``\%\%(-1)'' is the same as ``\%''. The value of ``\%\%(0)'' is not defined and will generate an error if requested. \subsection{Splitting Expressions Over Several Lines} Although Axiom will quite happily accept expressions that are longer than the width of the screen (just keep typing without pressing the {\bf Return} key) it is often preferable to split the expression being entered at a point where it would result in more readable input. To do this the underscore ``\_'' symbol is placed before the break point and then the {\bf Return} key is pressed. The rest of the expression is typed on the next line, can be preceeded by any number of whitespace chars, for example: \begin{verbatim} 2_ +_ 3 \end{verbatim} $$ 5 $$ \returnType{Type: PositiveInteger} The underscore symbol is an excape character and its presence alters the meaning of the characters that follow it. As mentions above whitespace following an underscore is ignored (the {\bf Return} key generates a whitespace character). Any other character following an underscore loses whatever special meaning it may have had. Thus one can create the identifier ``a+b'' by typing ``a\_+b'' although this might lead to confusions. Also note the result of the following example: \spadcommand{ThisIsAVeryLong\_\\ VariableName} $$ ThisIsAVeryLongVariableName $$ \returnType{Type: Variable ThisIsAVeryLongVariableName} \subsection{Comments and Descriptions} Comments and descriptions are really only of use in files of Axiom code but can be used when the output of an interactive session is being spooled to a file (via the system command {\bf )spool}). A comment begins with two dashes ``- -'' and continues until the end of the line. Multi-line comments are only possible if each individual line begins with two dashes. Descriptions are the same as comments except that the Axiom compiler will include them in the object files produced and make them availabe to the end user for documentation purposes. A description is placed {\bf before} a calculation begins with three ``+++'' signs and a description placed after a calculation begins with two plus symbols ``+''. The so-called ``plus plus'' comments are used within the algebra files and are processed by the compiler to add to the documentation. The so-called ``minus minus'' comments are ignored everywhere. \subsection{Control of Result Types} In earlier sections the type of an expression was converted to another via the ``::'' operator. However, this is not the only method for converting between types and two other operators need to be introduced and explained. The first operator is ``\$'' and is used to specify the package to be used to calculate the result. Thus: \spadcommand{(2/3)\$Float} $$ 0.6666666666\ 6666666667 $$ \returnType{Type: Float} tells Axiom to use the ``/'' operator from the {\tt Float} package to evaluate the expression $2/3$. This doe not necessarily mean that the result will be of the same type as the domain from which the operator was taken. In the following example the {\bf sign} operator is taken from the {\tt Float} package but the result is of type {\tt Integer}. \spadcommand{sign(2.3)\$Float} $$ 1 $$ \returnType{Type: Integer} The other operator is ``@'' which is used to tell Axiom what the desired type of the result of the calculation is. In most situations all three operators yield the same results but the example below should help distinguish them. \spadcommand{(2 + 3)::String} $$ \mbox{\tt "5"} $$ \returnType{Type: String} \spadcommand{(2 + 3)@String} \begin{verbatim} An expression involving @ String actually evaluated to one of type PositiveInteger . Perhaps you should use :: String . \end{verbatim} \spadcommand{(2 + 3)\$String} \begin{verbatim} The function + is not implemented in String . \end{verbatim} If an expression {\sl X} is converted using one of the three operators to type {\sl T} the interpretations are: {\bf ::} means explicitly convert {\sl X} to type {\sl T} if possible. {\bf \$} means use the available operators for type {\sl T} to compute {\sl X}. {\bf @} means choose operators to compute {\sl X} so that the result is of type {\sl T}. \section{Data Structures in Axiom} This chapter is an overview of {\sl some} of the data structures provided by Axiom. \subsection{Lists} The Axiom {\tt List} type constructor is used to create homogenous lists of finite size. The notation for lists and the names of the functions that operate over them are similar to those found in functional languages such as ML. Lists can be created by placing a comma separated list of values inside square brackets or if a list with just one element is desired then the function {\bf list} is available: \spadcommand{[4]} $$ \left[ 4 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{list(4)} $$ \left[ 4 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{[1,2,3,5,7,11]} $$ \left[ 1, 2, 3, 5, 7, {11} \right] $$ \returnType{Type: List PositiveInteger} The function {\bf append} takes two lists as arguments and returns the list consisting of the second argument appended to the first. A single element can be added to the front of a list using {\bf cons}: \spadcommand{append([1,2,3,5],[7,11])} $$ \left[ 1, 2, 3, 5, 7, {11} \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{cons(23,[65,42,19])} $$ \left[ {23}, {65}, {42}, {19} \right] $$ \returnType{Type: List PositiveInteger} Lists are accessed sequentially so if Axiom is asked for the value of the twentieth element in the list it will move from the start of the list over nineteen elements before it reaches the desired element. Each element of a list is stored as a node consisting of the value of the element and a pointer to the rest of the list. As a result the two main operations on a list are called {\bf first} and {\bf rest}. Both of these functions take a second optional argument which specifies the length of the first part of the list: \spadcommand{first([1,5,6,2,3])} $$ 1 $$ \returnType{Type: PositiveInteger} \spadcommand{first([1,5,6,2,3],2)} $$ \left[ 1, 5 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{rest([1,5,6,2,3])} $$ \left[ 5, 6, 2, 3 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{rest([1,5,6,2,3],2)} $$ \left[ 6, 2, 3 \right] $$ \returnType{Type: List PositiveInteger} Other functions are {\bf empty?} which tests to see if a list contains no elements, {\bf member?} which tests to see if the first argument is a member of the second, {\bf reverse} which reverses the order of the list, {\bf sort} which sorts a list, and {\bf removeDuplicates} which removes any duplicates. The length of a list can be obtained using the ``\#'' operator. \spadcommand{empty?([7,2,-1,2])} $$ {\tt false} $$ \returnType{Type: Boolean} \spadcommand{member?(-1,[7,2,-1,2])} $$ {\tt true} $$ \returnType{Type: Boolean} \spadcommand{reverse([7,2,-1,2])} $$ \left[ 2, -1, 2, 7 \right] $$ \returnType{Type: List Integer} \spadcommand{sort([7,2,-1,2])} $$ \left[ -1, 2, 2, 7 \right] $$ \returnType{Type: List Integer} \spadcommand{removeDuplicates([1,5,3,5,1,1,2])} $$ \left[ 1, 5, 3, 2 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{\#[7,2,-1,2]} $$ 4 $$ \returnType{Type: PositiveInteger} Lists in Axiom are mutable and so their contents (the elements and the links) can be modified in place. Functions that operator over lists in this way have names ending in the symbol ``!''. For example, {\bf concat!} takes two lists as arguments and appends the second argument to the first (except when the first argument is an empty list) and {\bf setrest!} changes the link emanating from the first argument to point to the second argument: \spadcommand{u := [9,2,4,7]} $$ \left[ 9, 2, 4, 7 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{concat!(u,[1,5,42]); u} $$ \left[ 9, 2, 4, 7, 1, 5, {42} \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{endOfu := rest(u,4)} $$ \left[ 1, 5, {42} \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{partOfu := rest(u,2)} $$ \left[ 4, 7, 1, 5, {42} \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{setrest!(endOfu,partOfu); u} $$ \left[ 9, 2, {\overline {4, 7, 1}} \right] $$ \returnType{Type: List PositiveInteger} From this it can be seen that the lists returned by {\bf first} and {\bf rest} are pointers to the original list and {\sl not} a copy. Thus great care must be taken when dealing with lists in Axiom. Although the {\sl n}th element of the list {\sl l} can be obtained by applying the {\bf first} function to $n-1$ applications of {\bf rest} to {\sl l}, Axiom provides a more useful access method in the form of the ``.'' operator: \spadcommand{u.3} $$ 4 $$ \returnType{Type: PositiveInteger} \spadcommand{u.5} $$ 1 $$ \returnType{Type: PositiveInteger} \spadcommand{u.6} $$ 4 $$ \returnType{Type: PositiveInteger} \spadcommand{first rest rest u -- Same as u.3} $$ 4 $$ \returnType{Type: PositiveInteger} \spadcommand{u.first} $$ 9 $$ \returnType{Type: PositiveInteger} \spadcommand{u(3)} $$ 4 $$ \returnType{Type: PositiveInteger} The operation {\sl u.i} is referred to as {\sl indexing into u} or {\sl elting into u}. The latter term comes from the {\bf elt} function which is used to extract elements (the first element of the list is at index $1$). \spadcommand{elt(u,4)} $$ 7 $$ \returnType{Type: PositiveInteger} If a list has no cycles then any attempt to access an element beyond the end of the list will generate an error. However, in the example above there was a cycle starting at the third element so the access to the sixth element wrapped around to give the third element. Since lists are mutable it is possible to modify elements directly: \spadcommand{u.3 := 42; u} $$ \left[ 9, 2, {\overline {{42}, 7, 1}} \right] $$ \returnType{Type: List PositiveInteger} Other list operations are: \spadcommand{L := [9,3,4,7]; \#L} $$ 4 $$ \returnType{Type: PositiveInteger} \spadcommand{last(L)} $$ 7 $$ \returnType{Type: PositiveInteger} \spadcommand{L.last} $$ 7 $$ \returnType{Type: PositiveInteger} \spadcommand{L.(\#L - 1)} $$ 4 $$ \returnType{Type: PositiveInteger} Note that using the ``\#'' operator on a list with cycles causes Axiom to enter an infinite loop. Note that any operation on a list {\sl L} that returns a list ${\sl L}L^{'}$ will, in general, be such that any changes to ${\sl L}L^{'}$ will have the side-effect of altering {\sl L}. For example: \spadcommand{m := rest(L,2)} $$ \left[ 4, 7 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{m.1 := 20; L} $$ \left[ 9, 3, {20}, 7 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{n := L} $$ \left[ 9, 3, {20}, 7 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{n.2 := 99; L} $$ \left[ 9, {99}, {20}, 7 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{n} $$ \left[ 9, {99}, {20}, 7 \right] $$ \returnType{Type: List PositiveInteger} Thus the only save way of copying lists is to copy each element from one to another and not use the assignment operator: \spadcommand{p := [i for i in n] -- Same as `p := copy(n)'} $$ \left[ 9, {99}, {20}, 7 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{p.2 := 5; p} $$ \left[ 9, 5, {20}, 7 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{n} $$ \left[ 9, {99}, {20}, 7 \right] $$ \returnType{Type: List PositiveInteger} In the previous example a new way of constructing lists was given. This is a powerful method which gives the reader more information about the contents of the list than before and which is extremely flexible. The example \spadcommand{[i for i in 1..10]} $$ \left[ 1, 2, 3, 4, 5, 6, 7, 8, 9, {10} \right] $$ \returnType{Type: List PositiveInteger} should be read as \begin{center} ``Using the expression {\sl i}, generate each element of the list by iterating the symbol {\sl i} over the range of integers [1,10]'' \end{center} To generate the list of the squares of the first ten elements we just use: \spadcommand{[i**2 for i in 1..10]} $$ \left[ 1, 4, 9, {16}, {25}, {36}, {49}, {64}, {81}, {100} \right] $$ \returnType{Type: List PositiveInteger} For more complex lists we can apply a condition to the elements that are to be placed into the list to obtain a list of even numbers between 0 and 11: \spadcommand{[i for i in 1..10 | even?(i)]} $$ \left[ 2, 4, 6, 8, {10} \right] $$ \returnType{Type: List PositiveInteger} This example should be read as: \begin{center} ``Using the expression {\sl i}, generate each element of the list by iterating the symbol {\sl i} over the range of integers [1,10] such that {\sl i} is even'' \end{center} The following achieves the same result: \spadcommand{[i for i in 2..10 by 2]} $$ \left[ 2, 4, 6, 8, {10} \right] $$ \returnType{Type: List PositiveInteger} \subsection{Segmented Lists} A segmented list is one in which some of the elements are ranges of values. The {\bf expand} function converts lists of this type into ordinary lists: \spadcommand{[1..10]} $$ \left[ {1..{10}} \right] $$ \returnType{Type: List Segment PositiveInteger} \spadcommand{[1..3,5,6,8..10]} $$ \left[ {1..3}, {5..5}, {6..6}, {8..{10}} \right] $$ \returnType{Type: List Segment PositiveInteger} \spadcommand{expand(\%)} $$ \left[ 1, 2, 3, 5, 6, 8, 9, {10} \right] $$ \returnType{Type: List Integer} If the upper bound of a segment is omitted then a different type of segmented list is obtained and expanding it will produce a stream (which will be considered in the next section): \spadcommand{[1..]} $$ \left[ {1..} \right] $$ \returnType{Type: List UniversalSegment PositiveInteger} \spadcommand{expand(\%)} $$ \left[ 1, 2, 3, 4, 5, 6, 7, 8, 9, {10}, \ldots \right] $$ \returnType{Type: Stream Integer} \subsection{Streams} Streams are infinite lists which have the ability to calculate the next element should it be required. For example, a stream of positive integers and a list of prime numbers can be generated by: \spadcommand{[i for i in 1..]} $$ \left[ 1, 2, 3, 4, 5, 6, 7, 8, 9, {10}, \ldots \right] $$ \returnType{Type: Stream PositiveInteger} \spadcommand{[i for i in 1.. | prime?(i)]} $$ \left[ 2, 3, 5, 7, {11}, {13}, {17}, {19}, {23}, {29}, \ldots \right] $$ \returnType{Type: Stream PositiveInteger} In each case the first few elements of the stream are calculated for display purposes but the rest of the stream remains unevaluated. The value of items in a stream are only calculated when they are needed which gives rise to their alternative name of ``lazy lists''. Another method of creating streams is to use the {\bf generate(f,a)} function. This applies its first argument repeatedly onto its second to produce the stream $[a,f(a),f(f(a)),f(f(f(a)))\ldots]$. Given that the function {\bf nextPrime} returns the lowest prime number greater than its argument we can generate a stream of primes as follows: \spadcommand{generate(nextPrime,2)\$Stream Integer} $$ \left[ 2, 3, 5, 7, {11}, {13}, {17}, {19}, {23}, {29}, \ldots \right] $$ \returnType{Type: Stream Integer} As a longer example a stream of Fibonacci numbers will be computed. The Fibonacci numbers start at $1$ and each following number is the addition of the two numbers that precede it so the Fibonacci sequence is: $$1,1,2,3,5,8,\ldots$$. Since the generation of any Fibonacci number only relies on knowing the previous two numbers we can look at the series through a window of two elements. To create the series the window is placed at the start over the values $[1,1]$ and their sum obtained. The window is now shifted to the right by one position and the sum placed into the empty slot of the window; the process is then repeated. To implement this we require a function that takes a list of two elements (the current view of the window), adds them, and outputs the new window. The result is the function $[a,b]$~{\tt ->}~$[b,a+b]$: \spadcommand{win : List Integer -> List Integer} \returnType{Type: Void} \spadcommand{win(x) == [x.2, x.1 + x.2]} \returnType{Type: Void} \spadcommand{win([1,1])} $$ \left[ 1, 2 \right] $$ \returnType{Type: List Integer} \spadcommand{win(\%)} $$ \left[ 2, 3 \right] $$ \returnType{Type: List Integer} Thus it can be seen that repeatedly applying {\bf win} to the {\sl results} of the previous invocation each element of the series is obtained. Clearly {\bf win} is an ideal function to construct streams using the {\bf generate} function: \spadcommand{fibs := [generate(win,[1,1])]} $$ \left[ {\left[ 1, 1 \right]}, {\left[ 1, 2 \right]}, {\left[ 2, 3 \right]}, {\left[ 3, 5 \right]}, {\left[ 5, 8 \right]}, {\left[ 8, {13} \right]}, {\left[ {13}, {21} \right]}, {\left[ {21}, {34} \right]}, {\left[ {34}, {55} \right]}, {\left[ {55}, {89} \right]}, \ldots \right] $$ \returnType{Type: Stream List Integer} This isn't quite what is wanted -- we need to extract the first element of each list and place that in our series: \spadcommand{fibs := [i.1 for i in [generate(win,[1,1])] ]} $$ \left[ 1, 1, 2, 3, 5, 8, {13}, {21}, {34}, {55}, \ldots \right] $$ \returnType{Type: Stream Integer} Obtaining the 200th Fibonacci number is trivial: \spadcommand{fibs.200} $$ 280571172992510140037611932413038677189525 $$ \returnType{Type: PositiveInteger} One other function of interest is {\bf complete} which expands a finite stream derived from an infinite one (and thus was still stored as an infinite stream) to form a finite stream. \subsection{Arrays, Vectors, Strings, and Bits} The simplest array data structure is the {\sl one-dimensional array} which can be obtained by applying the {\bf oneDimensionalArray} function to a list: \spadcommand{oneDimensionalArray([7,2,5,4,1,9])} $$ \left[ 7, 2, 5, 4, 1, 9 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} One-dimensional array are homogenous (all elements must have the same type) and mutable (elements can be changed) like lists but unlike lists they are constant in size and have uniform access times (it is just as quick to read the last element of a one-dimensional array as it is to read the first; this is not true for lists). Since these arrays are mutable all the warnings that apply to lists apply to arrays. That is, it is possible to modify an element in a copy of an array and change the original: \spadcommand{x := oneDimensionalArray([7,2,5,4,1,9])} $$ \left[ 7, 2, 5, 4, 1, 9 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} \spadcommand{y := x} $$ \left[ 7, 2, 5, 4, 1, 9 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} \spadcommand{y.3 := 20 ; x} $$ \left[ 7, 2, {20}, 4, 1, 9 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} Note that because these arrays are of fixed size the {\bf concat!} function cannot be applied to them without generating an error. If arrays of this type are required use the {\bf FlexibleArray} constructor. One-dimensional arrays can be created using {\bf new} which specifies the size of the array and the initial value for each of the elements. Other operations that can be applied to one-dimensional arrays are {\bf map!} which applies a mapping onto each element, {\bf swap!} which swaps two elements and {\bf copyInto!(a,b,c)} which copies the array {\sl b} onto {\sl a} starting at position {\sl c}. \spadcommand{a : ARRAY1 PositiveInteger := new(10,3)} $$ \left[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} (note that {\tt ARRAY1} is an abbreviation for the type {\tt OneDimensionalArray}.) Other types based on one-dimensional arrays are {\tt Vector}, {\tt String}, and {tt Bits}. \spadcommand{map!(i +-> i+1,a); a} $$ \left[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} \spadcommand{b := oneDimensionalArray([2,3,4,5,6])} $$ \left[ 2, 3, 4, 5, 6 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} \spadcommand{swap!(b,2,3); b} $$ \left[ 2, 4, 3, 5, 6 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} \spadcommand{copyInto!(a,b,3)} $$ \left[ 4, 4, 2, 4, 3, 5, 6, 4, 4, 4 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} \spadcommand{a} $$ \left[ 4, 4, 2, 4, 3, 5, 6, 4, 4, 4 \right] $$ \returnType{Type: OneDimensionalArray PositiveInteger} \spadcommand{vector([1/2,1/3,1/14])} $$ \left[ {1 \over 2}, {1 \over 3}, {1 \over {14}} \right] $$ \returnType{Type: Vector Fraction Integer} \spadcommand{"Hello, World"} $$ \mbox{\tt "Hello, World"} $$ \returnType{Type: String} \spadcommand{bits(8,true)} $$ \mbox{\tt "11111111"} $$ \returnType{Type: Bits} A vector is similar to a one-dimensional array except that if its components belong to a ring then arithmetic operations are provided. \subsection{Flexible Arrays} Flexible arrays are designed to provide the efficiency of one-dimensional arrays while retaining the flexibility of lists. They are implemented by allocating a fixed block of storage for the array. If the array needs to be expanded then a larger block of storage is allocated and the contents of the old block are copied into the new one. There are several operations that can be applied to this type, most of which modify the array in place. As a result these functions all have names ending in ``!''. The {\bf physicalLength} returns the actual length of the array as stored in memory while the {\bf physicalLength!} allows this value to be changed by the user. \spadcommand{f : FARRAY INT := new(6,1)} $$ \left[ 1, 1, 1, 1, 1, 1 \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{f.1:=4; f.2:=3 ; f.3:=8 ; f.5:=2 ; f} $$ \left[ 4, 3, 8, 1, 2, 1 \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{insert!(42,f,3); f} $$ \left[ 4, 3, {42}, 8, 1, 2, 1 \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{insert!(28,f,8); f} $$ \left[ 4, 3, {42}, 8, 1, 2, 1, {28} \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{removeDuplicates!(f)} $$ \left[ 4, 3, {42}, 8, 1, 2, {28} \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{delete!(f,5)} $$ \left[ 4, 3, {42}, 8, 2, {28} \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{g:=f(3..5)} $$ \left[ {42}, 8, 2 \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{g.2:=7; f} $$ \left[ 4, 3, {42}, 8, 2, {28} \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{insert!(g,f,1)} $$ \left[ {42}, 7, 2, 4, 3, {42}, 8, 2, {28} \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{physicalLength(f)} $$ 10 $$ \returnType{Type: PositiveInteger} \spadcommand{physicalLength!(f,20)} $$ \left[ {42}, 7, 2, 4, 3, {42}, 8, 2, {28} \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{merge!(sort!(f),sort!(g))} $$ \left[ 2, 2, 2, 3, 4, 7, 7, 8, {28}, {42}, {42}, {42} \right] $$ \returnType{Type: FlexibleArray Integer} \spadcommand{shrinkable(false)\$FlexibleArray(Integer)} $$ {\tt true} $$ \returnType{Type: Boolean} There are several things to point out concerning these examples. First, although flexible arrays are mutable, making copies of these arrays creates separate entities. This can be seen by the fact that the modification of element {\sl b.2} above did not alter {\sl a}. Second, the {\bf merge!} function can take an extra argument before the two arrays are merged. The argument is a comparison function and defaults to ``{\tt <=}'' if omitted. Lastly, {\bf shrinkable} tells the system whether or not to let flexible arrays contract when elements are deleted from them. An explicit package reference must be given as in the example above. \section{Functions, Choices, and Loops} By now the reader should be able to construct simple one-line expressions involving variables and different data structures. This section builds on this knowledge and shows how to use iteration, make choices, and build functions in Axiom. At the moment it is assumed that the reader has a rough idea of how types are specified and constructed so that they can follow the examples given. From this point on most examples will be taken from input files. \subsection{Reading Code from a File} Input files contain code that will be fed to the command prompt. The primary different between the command line and an input file is that indentation matters. In an input file you can specify ``piles'' of code by using indentation. The names of all input files in Axiom should end in ``.input'' otherwise Axiom will refuse to read them. If an input file is named {\bf foo.input} you can feed the contents of the file to the command prompt (as though you typed them) by writing: {\bf )read foo.input}. It is good practice to start each input file with the {\bf )clear all} command so that all functions and variables in the current environment are erased. \subsection{Blocks} The Axiom constructs that provide looping, choices, and user-defined functions all rely on the notion of blocks. A block is a sequence of expressions which are evaluated in the order that they appear except when it is modified by control expressions such as loops. To leave a block prematurely use an expression of the form: {\sl BoolExpr}~{\tt =>}~{\sl Expr} where {\sl BoolExpr} is any Axiom expression that has type {\tt Boolean}. The value and type of {\sl Expr} determines the value and type returned by the block. If blocks are entered at the keyboard (as opposed to reading them from a text file) then there is only one way of creating them. The syntax is: $$( expression1 ; expression2; \ldots ; expressionN )$$ In an input file a block can be constructed as above or by placing all the statements at the same indentation level. When indentation is used to indicate program structure the block is called a {\sl pile}. As an example of a simple block a list of three integers can be constructed using parentheses: \spadcommand{( a:=4; b:=1; c:=9; L:=[a,b,c])} $$ \left[ 4, 1, 9 \right] $$ \returnType{Type: List PositiveInteger} Doing the same thing using piles in an input file you could type: \begin{verbatim} L := a:=4 b:=1 c:=9 [a,b,c] \end{verbatim} $$ \left[ 4, 1, 9 \right] $$ \returnType{Type: List PositiveInteger} Since blocks have a type and a value they can be used as arguments to functions or as part of other expressions. It should be pointed out that the following example is not recommended practice but helps to illustrate the idea of blocks and their ability to return values: \begin{verbatim} sqrt(4.0 + a:=3.0 b:=1.0 c:=a + b c ) \end{verbatim} $$ 2.8284271247\ 461900976 $$ \returnType{Type: Float} Note that indentation is {\bf extremely} important. If the example above had the pile starting at ``a:='' moved left by two spaces so that the ``a'' was under the ``('' of the first line then the interpreter would signal an error. Furthermore if the closing parenthesis ``)'' is moved up to give \begin{verbatim} sqrt(4.0 + a:=3.0 b:=1.0 c:=a + b c) \end{verbatim} \begin{verbatim} Line 1: sqrt(4.0 + ....A Error A: Missing mate. Line 2: a:=3.0 Line 3: b:=1.0 Line 4: c:=a + b Line 5: c) .........AB Error A: (from A up to B) Ignored. Error B: Improper syntax. Error B: syntax error at top level Error B: Possibly missing a ) 5 error(s) parsing \end{verbatim} then the parser will generate errors. If the parenthesis is shifted right by several spaces so that it is in line with the ``c'' thus: \begin{verbatim} sqrt(4.0 + a:=3.0 b:=1.0 c:=a + b c ) \end{verbatim} \begin{verbatim} Line 1: sqrt(4.0 + ....A Error A: Missing mate. Line 2: a:=3.0 Line 3: b:=1.0 Line 4: c:=a + b Line 5: c Line 6: ) .........A Error A: (from A up to A) Ignored. Error A: Improper syntax. Error A: syntax error at top level Error A: Possibly missing a ) 5 error(s) parsing \end{verbatim} a similar error will be raised. Finally, the ``)'' must be indented by at least one space relative to the sqrt thus: \begin{verbatim} sqrt(4.0 + a:=3.0 b:=1.0 c:=a + b c ) \end{verbatim} $$ 2.8284271247\ 461900976 $$ \returnType{Type: Float} or an error will be generated. It can be seen that great care needs to be taken when constructing input files consisting of piles of expressions. It would seem prudent to add one pile at a time and check if it is acceptable before adding more, particularly if piles are nested. However, it should be pointed out that the use of piles as values for functions is not very readable and so perhaps the delicate nature of their interpretation should deter programmers from using them in these situations. Using piles should really be restricted to constructing functions, etc. and a small amount of rewriting can remove the need to use them as arguments. For example, the previous block could easily be implemented as: \begin{verbatim} a:=3.0 b:=1.0 c:=a + b sqrt(4.0 + c) \end{verbatim} \begin{verbatim} a:=3.0 \end{verbatim} $$ 3.0 $$ \returnType{Type: Float} \begin{verbatim} b:=1.0 \end{verbatim} $$ 1.0 $$ \returnType{Type: Float} \begin{verbatim} c:=a + b \end{verbatim} $$ 4.0 $$ \returnType{Type: Float} \begin{verbatim} sqrt(4.0 + c) \end{verbatim} $$ 2.8284271247\ 461900976 $$ \returnType{Type: Float} which achieves the same result and is easier to understand. Note that this is still a pile but it is not as fragile as the previous version. \subsection{Functions} Definitions of functions in Axiom are quite simple providing two things are observed. First, the type of the function must either be completely specified or completely unspecified. Second, the body of the function is assigned to the function identifier using the delayed assignment operator ``==''. To specify the type of something the ``:'' operator is used. Thus to define a variable {\sl x} to be of type {\tt Fraction Integer} we enter: \spadcommand{x : Fraction Integer} \returnType{Type: Void} For functions the method is the same except that the arguments are placed in parentheses and the return type is placed after the symbol ``{\tt ->}''. Some examples of function definitions taking zero, one, two, or three arguments and returning a list of integers are: \spadcommand{f : () -> List Integer} \returnType{Type: Void} \spadcommand{g : (Integer) -> List Integer} \returnType{Type: Void} \spadcommand{h : (Integer, Integer) -> List Integer} \returnType{Type: Void} \spadcommand{k : (Integer, Integer, Integer) -> List Integer} \returnType{Type: Void} Now the actual function definitions might be: \spadcommand{f() == [\ ]} \returnType{Type: Void} \spadcommand{g(a) == [a]} \returnType{Type: Void} \spadcommand{h(a,b) == [a,b]} \returnType{Type: Void} \spadcommand{k(a,b,c) == [a,b,c]} \returnType{Type: Void} with some invocations of these functions: \spadcommand{f()} \begin{verbatim} Compiling function f with type () -> List Integer \end{verbatim} $$ \left[\ \right] $$ \returnType{Type: List Integer} \spadcommand{g(4)} \begin{verbatim} Compiling function g with type Integer -> List Integer \end{verbatim} $$ \left[ 4 \right] $$ \returnType{Type: List Integer} \spadcommand{h(2,9)} \begin{verbatim} Compiling function h with type (Integer,Integer) -> List Integer \end{verbatim} $$ \left[ 2, 9 \right] $$ \returnType{Type: List Integer} \spadcommand{k(-3,42,100)} \begin{verbatim} Compiling function k with type (Integer,Integer,Integer) -> List Integer \end{verbatim} $$ \left[ -3, {42}, {100} \right] $$ \returnType{Type: List Integer} The value returned by a function is either the value of the last expression evaluated or the result of a {\bf return} statement. For example, the following are effectively the same: \spadcommand{p : Integer -> Integer} \returnType{Type: Void} \spadcommand{p x == (a:=1; b:=2; a+b+x)} \returnType{Type: Void} \spadcommand{p x == (a:=1; b:=2; return(a+b+x))} \returnType{Type: Void} Note that a block (pile) is assigned to the function identifier {\bf p} and thus all the rules about blocks apply to function definitions. Also there was only one argument so the parenthese are not needed. This is basically all that one needs to know about defining functions in Axiom -- first specify the complete type and then assign a block to the function name. The rest of this section is concerned with defining more complex blocks than those in this section and as a result function definitions will crop up continually particularly since they are a good way of testing examples. Since the block structure is more complex we will use the {\bf pile} notation and thus have to use input files to read the piles. \subsection{Choices} Apart from the ``{\tt =>}'' operator that allows a block to exit before the end Axiom provides the standard {\bf if-then-else} construct. The general syntax is: {\center{if {\sl BooleanExpr} then {\sl Expr1} else {\sl Expr2}}} where ``else {\sl Expr2}'' can be omitted. If the expression {\sl BooleanExpr} evaluates to {\tt true} then {\sl Expr1} is executed otherwise {\sl Expr2} (if present) will be executed. An example of piles and {\bf if-then-else} is: (read from an input file) \begin{verbatim} h := 2.0 if h > 3.1 then 1.0 else z:= cos(h) max(x,0.5) \end{verbatim} \begin{verbatim} h := 2.0 \end{verbatim} $$ 2.0 $$ \returnType{Type: Float} \begin{verbatim} if h > 3.1 then 1.0 else z:= cos(h) max(x,0.5) \end{verbatim} $$ x $$ \returnType{Type: Polynomial Float} Note the indentation -- the ``else'' must be indented relative to the ``if'' otherwise it will generate an error (Axiom will think there are two piles, the second one beginning with ``else''). Any expression that has type {\tt Boolean} can be used as {\tt BooleanExpr} and the most common will be those involving the relational operators ``$>$'', ``$<$'', and ``=''. Usually the type of an expression involving the equality operator ``='' will be {\bf Boolean} but in those situations when it isn't you may need to use the ``@'' operator to ensure that it is. \subsection{Loops} Loops in Axiom are regarded as expressions containing another expression called the {\sl loop body}. The loop body is executed zero or more times depending on the kind of loop. Loops can be nested to any depth. \subsubsection{The {\tt repeat} loop} The simplest kind of loop provided by Axiom is the {\bf repeat} loop. The general syntax of this is: {\center{{\bf repeat} {\sl loopBody}}} This will cause Axiom to execute {\sl loopBody} repeatedly until either a {\bf break} or {\bf return} statement is encountered. If {\sl loopBody} contains neither of these statements then it will loop forever. The following piece of code will display the numbers from $1$ to $4$: \begin{verbatim} i:=1 repeat if i > 4 then break output(i) i:=i+1 \end{verbatim} \begin{verbatim} i:=1 \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} repeat if i > 4 then break output(i) i:=i+1 1 2 3 4 \end{verbatim} \returnType{Type: Void} It was mentioned that loops will only be left when either a {\bf break} or {\bf return} statement is encountered so why can't one use the ``{\tt =>}'' operator? The reason is that the ``{\tt =>}'' operator tells Axiom to leave the current block whereas {\bf break} leaves the current loop. The {\bf return} statement leave the current function. To skip the rest of a loop body and continue the next iteration of the loop use the {\bf iterate} statement (the -- starts a comment in Axiom) \begin{verbatim} i := 0 repeat i := i + 1 if i > 6 then break -- Return to start if i is odd if odd?(i) then iterate output(i) \end{verbatim} \begin{verbatim} i := 0 \end{verbatim} $$ 0 $$ \returnType{Type: NonNegativeInteger} \begin{verbatim} repeat i := i + 1 if i > 6 then break -- Return to start if i is odd if odd?(i) then iterate output(i) 2 4 6 \end{verbatim} \returnType{Type: Void} \subsubsection{The {\tt while} loop} The while statement extends the basic {\bf repeat} loop to place the control of leaving the loop at the start rather than have it buried in the middle. Since the body of the loop is still part of a {\bf repeat} loop, {\bf break} and ``{\tt =>}'' work in the same way as in the previous section. The general syntax of a {\bf while} loop is: {\center{while {\sl BoolExpr} repeat {\sl loopBody}}} As before, {\sl BoolExpr} must be an expression of type {\bf Boolean}. Before the body of the loop is executed {\sl BoolExpr} is tested. If it evaluates to {\tt true} then the loop body is entered otherwise the loop is terminated. Multiple conditions can be applied using the logical operators such as {\bf and} or by using several {\bf while} statements before the {\bf repeat}. \begin{verbatim} x:=1 y:=1 while x < 4 and y < 10 repeat output [x,y] x := x + 1 y := y + 2 \end{verbatim} \begin{verbatim} x:=1 \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} y:=1 \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} while x < 4 and y < 10 repeat output [x,y] x := x + 1 y := y + 2 [1,1] [2,3] [3,5] \end{verbatim} \returnType{Type: Void} \begin{verbatim} x:=1 y:=1 while x < 4 while y < 10 repeat output [x,y] x := x + 1 y := y + 2 \end{verbatim} \begin{verbatim} x:=1 \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} y:=1 \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} while x < 4 while y < 10 repeat output [x,y] x := x + 1 y := y + 2 [1,1] [2,3] [3,5] \end{verbatim} \returnType{Type: Void} Note that the last example using two {\bf while} statements is {\sl not} a nested loop but the following one is: \begin{verbatim} x:=1 y:=1 while x < 4 repeat while y < 10 repeat output [x,y] x := x + 1 y := y + 2 \end{verbatim} \begin{verbatim} x:=1 \begin{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} y:=1 \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} while x < 4 repeat while y < 10 repeat output [x,y] x := x + 1 y := y + 2 [1,1] [2,3] [3,5] [4,7] [5,9] \end{verbatim} \returnType{Type: Void} Suppose we that, given a matrix of arbitrary size, find the position and value of the first negative element by examining the matrix in row-major order: \begin{verbatim} m := matrix [ [ 21, 37, 53, 14 ],_ [ 8, 22,-24, 16 ],_ [ 2, 10, 15, 14 ],_ [ 26, 33, 55,-13 ] ] lastrow := nrows(m) lastcol := ncols(m) r := 1 while r <= lastrow repeat c := 1 -- Index of first column while c <= lastcol repeat if elt(m,r,c) < 0 then output [r,c,elt(m,r,c)] r := lastrow break -- Don't look any further c := c + 1 r := r + 1 \end{verbatim} \begin{verbatim} m := matrix [ [ 21, 37, 53, 14 ],_ [ 8, 22,-24, 16 ],_ [ 2, 10, 15, 14 ],_ [ 26, 33, 55,-13 ] ] \end{verbatim} $$ \left[ \begin{array}{cccc} {21} & {37} & {53} & {14} \\ 8 & {22} & -{24} & {16} \\ 2 & {10} & {15} & {14} \\ {26} & {33} & {55} & -{13} \end{array} \right] $$ \returnType{Type: Matrix Integer} \begin{verbatim} lastrow := nrows(m) \end{verbatim} $$ 4 $$ \returnType{Type: PositiveInteger} \begin{verbatim} lastcol := ncols(m) \end{verbatim} $$ 4 $$ \returnType{Type: PositiveInteger} \begin{verbatim} r := 1 \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} while r <= lastrow repeat c := 1 -- Index of first column while c <= lastcol repeat if elt(m,r,c) < 0 then output [r,c,elt(m,r,c)] r := lastrow break -- Don't look any further c := c + 1 r := r + 1 [2,3,- 24] \end{verbatim} \returnType{Type: Void} \subsubsection{The {\tt for} loop} The last loop statement of interest is the {\bf for} loop. There are two ways of creating a {\bf for} loop. The first way uses either a list or a segment: \begin{center} for {\sl var} in {\sl seg} repeat {\sl loopBody}\\ for {\sl var} in {\sl list} repeat {\sl loopBody} \end{center} where {\sl var} is an index variable which is iterated over the values in {\sl seg} or {\sl list}. The value {\sl seg} is a segment such as $1\ldots10$ or $1\ldots$ and {\sl list} is a list of some type. For example: \begin{verbatim} for i in 1..10 repeat ~prime?(i) => iterate output(i) \end{verbatim} \begin{verbatim} for i in 1..10 repeat ~prime?(i) => iterate output(i) 2 3 5 7 \end{verbatim} \returnType{Type: Void} \begin{verbatim} for w in ["This", "is", "your", "life!"] repeat output(w) \end{verbatim} \begin{verbatim} for w in ["This", "is", "your", "life!"] repeat output(w) This is your life! \end{verbatim} \returnType{Type: Void} The second form of the {\bf for} loop syntax includes a ``{\bf such that}'' clause which must be of type {\bf Boolean}: \begin{center} for {\sl var} | {\sl BoolExpr} in {\sl seg} repeat {\sl loopBody}\\ for {\sl var} | {\sl BoolExpr} in {\sl list} repeat {\sl loopBody} \end{center} Some examples are: \begin{verbatim} for i in 1..10 | prime?(i) repeat output(i) \end{verbatim} \begin{verbatim} for i in 1..10 | prime?(i) repeat output(i) 2 3 5 7 \end{verbatim} \returnType{Type: Void} \begin{verbatim} for i in [1,2,3,4,5,6,7,8,9,10] | prime?(i) repeat output(i) \end{verbatim} \begin{verbatim} for i in [1,2,3,4,5,6,7,8,9,10] | prime?(i) repeat output(i) 2 3 5 7 \end{verbatim} \returnType{Type: Void} You can also use a {\bf while} clause: \begin{verbatim} for i in 1.. while i < 7 repeat if even?(i) then output(i) \end{verbatim} \begin{verbatim} for i in 1.. while i < 7 repeat if even?(i) then output(i) 2 4 6 \end{verbatim} \returnType{Type: Void} Using the ``{\bf such that}'' clause makes this appear simpler: \begin{verbatim} for i in 1.. | even?(i) while i < 7 repeat output(i) \{verbatim} \begin{verbatim} for i in 1.. | even?(i) while i < 7 repeat output(i) 2 4 6 \end{verbatim} \returnType{Type: Void} You can use multiple {\bf for} clauses to iterate over several sequences in parallel: \begin{verbatim} for a in 1..4 for b in 5..8 repeat output [a,b] \end{verbatim} \begin{verbatim} for a in 1..4 for b in 5..8 repeat output [a,b] [1,5] [2,6] [3,7] [4,8] \end{verbatim} \returnType{Type: Void} As a general point it should be noted that any symbols referred to in the ``{\bf such that}'' and {\bf while} clauses must be pre-defined. This either means that the symbols must have been defined in an outer level (e.g. in an enclosing loop) or in a {\bf for} clause appearing before the ``{\bf such that}'' or {\bf while}. For example: \begin{verbatim} for a in 1..4 repeat for b in 7..9 | prime?(a+b) repeat output [a,b,a+b] \end{verbatim} \begin{verbatim} for a in 1..4 repeat for b in 7..9 | prime?(a+b) repeat output [a,b,a+b] [2,9,11] [3,8,11] [4,7,11] [4,9,13] \end{verbatim} \returnType{Type: Void} Finally, the {\bf for} statement has a {\bf by} clause to specify the step size. This makes it possible to iterate over the segment in reverse order: \begin{verbatim} for a in 1..4 for b in 8..5 by -1 repeat output [a,b] \end{verbatim} \begin{verbatim} for a in 1..4 for b in 8..5 by -1 repeat output [a,b] [1,8] [2,7] [3,6] [4,5] \end{verbatim} \returnType{Type: Void} Note that without the ``by -1'' the segment 8..5 is empty so there is nothing to iterate over and the loop exits immediately. \setcounter{chapter}{0} % Chapter 1 \hyphenation{ multi-set Uni-var-iate-Poly-nomial Mul-ti-var-iate-Poly-nomial Distributed-Mul-ti-var-iate-Poly-nomial Homo-gen-eous-Distributed-Mul-ti-var-iate-Poly-nomial New-Distributed-Mul-ti-var-iate-Poly-nomial General-Distributed-Mul-ti-var-iate-Poly-nomial } \setcounter{chapter}{1} \chapter{Overview of Interactive Language} \label{ugLang} In this chapter we look at some of the basic components of the Axiom language that you can use interactively. We show how to create a {\it block} of expressions, how to form loops and list iterations, how to modify the sequential evaluation of a block and how to use {\tt if-then-else} to evaluate parts of your program conditionally. We suggest you first read the boxed material in each section and then proceed to a more thorough reading of the chapter. \section{Immediate and Delayed Assignments} \label{ugLangAssign} A {\it variable} in Axiom refers to a value. A variable has a name beginning with an uppercase or lowercase alphabetic character, ``{\tt \%}'', or ``{\tt !}''. Successive characters (if any) can be any of the above, digits, or ``{\tt ?}''. Case is distinguished. The following are all examples of valid, distinct variable names: \begin{verbatim} a tooBig? a1B2c3%!? A %j numberOfPoints beta6 %J numberofpoints \end{verbatim} The ``{\tt :=}'' operator is the immediate {\it assignment} operator. \index{assignment!immediate} Use it to associate a value with a variable. \index{immediate assignment} \boxed{4.6in}{ \vskip 0.1cm The syntax for immediate assignment for a single variable is \begin{center} {\it variable} $:=$ {\it expression} \end{center} The value returned by an immediate assignment is the value of {\it expression}.\\ } The right-hand side of the expression is evaluated, yielding $1$. This value is then assigned to $a$. \spadcommand{a := 1} $$ 1 $$ \returnType{Type: PositiveInteger} The right-hand side of the expression is evaluated, yielding $1$. This value is then assigned to $b$. Thus $a$ and $b$ both have the value $1$ after the sequence of assignments. \spadcommand{b := a} $$ 1 $$ \returnType{Type: PositiveInteger} What is the value of $b$ if $a$ is assigned the value $2$? \spadcommand{a := 2} $$ 2 $$ \returnType{Type: PositiveInteger} As you see, the value of $b$ is left unchanged. \spadcommand{b} $$ 1 $$ \returnType{Type: PositiveInteger} This is what we mean when we say this kind of assignment is {\it immediate}; $b$ has no dependency on $a$ after the initial assignment. This is the usual notion of assignment found in programming languages such as C, \index{C language!assignment} PASCAL \index{PASCAL!assignment} and FORTRAN. \index{FORTRAN!assignment} Axiom provides delayed assignment with ``{\tt ==}''. \index{assignment!delayed} This implements a \index{delayed assignment} delayed evaluation of the right-hand side and dependency checking. \boxed{4.6in}{ \vskip 0.1cm The syntax for delayed assignment is \begin{center} {\it variable} $==$ {\it expression} \end{center} The value returned by a delayed assignment is the unique value of {\tt Void}.\\ } Using $a$ and $b$ as above, these are the corresponding delayed assignments. \spadcommand{a == 1} \returnType{Type: Void} \spadcommand{b == a} \returnType{Type: Void} The right-hand side of each delayed assignment is left unevaluated until the variables on the left-hand sides are evaluated. Therefore this evaluation and \ldots \spadcommand{a} \begin{verbatim} Compiling body of rule a to compute value of type PositiveInteger \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} this evaluation seem the same as before. \spadcommand{b} \begin{verbatim} Compiling body of rule b to compute value of type PositiveInteger \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} If we change $a$ to $2$ \spadcommand{a == 2} \begin{verbatim} Compiled code for a has been cleared. Compiled code for b has been cleared. 1 old definition(s) deleted for function or rule a \end{verbatim} \returnType{Type: Void} then $a$ evaluates to $2$, as expected, but \spadcommand{a} \begin{verbatim} Compiling body of rule a to compute value of type PositiveInteger +++ |*0;a;1;G82322| redefined \end{verbatim} $$ 2 $$ \returnType{Type: PositiveInteger} the value of $b$ reflects the change to $a$. \spadcommand{b} \begin{verbatim} Compiling body of rule b to compute value of type PositiveInteger +++ |*0;b;1;G82322| redefined \end{verbatim} $$ 2 $$ \returnType{Type: PositiveInteger} It is possible to set several variables at the same time \index{assignment!multiple immediate} by using \index{multiple immediate assignment} a {\it tuple} of variables and a tuple of expressions. Note that a {\it tuple} is a collection of things separated by commas, often surrounded by parentheses. \boxed{4.6in}{ \vskip 0.1cm The syntax for multiple immediate assignments is \begin{center} {\tt ( $\hbox{\it var}_{1}$, $\hbox{\it var}_{2}$, \ldots, $\hbox{\it var}_{N}$ ) := ( $\hbox{\it expr}_{1}$, $\hbox{\it expr}_{2}$, \ldots, $\hbox{\it expr}_{N}$ ) } \end{center} The value returned by an immediate assignment is the value of $\hbox{\it expr}_{N}$.\\ } This sets $x$ to $1$ and $y$ to $2$. \spadcommand{(x,y) := (1,2)} $$ 2 $$ \returnType{Type: PositiveInteger} Multiple immediate assigments are parallel in the sense that the expressions on the right are all evaluated before any assignments on the left are made. However, the order of evaluation of these expressions is undefined. You can use multiple immediate assignment to swap the values held by variables. \spadcommand{(x,y) := (y,x)} $$ 1 $$ \returnType{Type: PositiveInteger} $x$ has the previous value of $y$. \spadcommand{x} $$ 2 $$ \returnType{Type: PositiveInteger} $y$ has the previous value of $x$. \spadcommand{y} $$ 1 $$ \returnType{Type: PositiveInteger} There is no syntactic form for multiple delayed assignments. See the discussion in section \ref{ugUserDelay} on page~\pageref{ugUserDelay} about how Axiom differentiates between delayed assignments and user functions of no arguments. \section{Blocks} \label{ugLangBlocks} A {\it block} is a sequence of expressions evaluated in the order that they appear, except as modified by control expressions such as {\tt break}, \index{break} {\tt return}, \index{return} {\tt iterate} and \index{iterate} {\tt if-then-else} constructions. The value of a block is the value of the expression last evaluated in the block. To leave a block early, use ``{\tt =>}''. For example, $i < 0 => x$. The expression before the ``{\tt =>}'' must evaluate to {\tt true} or {\tt false}. The expression following the ``{\tt =>}'' is the return value for the block. A block can be constructed in two ways: \begin{enumerate} \item the expressions can be separated by semicolons and the resulting expression surrounded by parentheses, and \item the expressions can be written on succeeding lines with each line indented the same number of spaces (which must be greater than zero). \index{indentation} A block entered in this form is called a {\it pile}. \end{enumerate} Only the first form is available if you are entering expressions directly to Axiom. Both forms are available in {\bf .input} files. \boxed{4.6in}{ \vskip 0.1cm The syntax for a simple block of expressions entered interactively is \begin{center} {\tt ( $\hbox{\it expression}_{1}$; $\hbox{\it expression}_{2}$; \ldots; $\hbox{\it expression}_{N}$ )} \end{center} The value returned by a block is the value of an {\tt =>} expression, or $\hbox{\it expression}_{N}$ if no {\tt =>} is encountered.\\ } In {\bf .input} files, blocks can also be written using piles. The examples throughout this book are assumed to come from {\bf .input} files. In this example, we assign a rational number to $a$ using a block consisting of three expressions. This block is written as a pile. Each expression in the pile has the same indentation, in this case two spaces to the right of the first line. \begin{verbatim} a := i := gcd(234,672) i := 3*i**5 - i + 1 1 / i \end{verbatim} $$ 1 \over {23323} $$ \returnType{Type: Fraction Integer} Here is the same block written on one line. This is how you are required to enter it at the input prompt. \spadcommand{a := (i := gcd(234,672); i := 3*i**5 - i + 1; 1 / i)} $$ 1 \over {23323} $$ \returnType{Type: Fraction Integer} Blocks can be used to put several expressions on one line. The value returned is that of the last expression. \spadcommand{(a := 1; b := 2; c := 3; [a,b,c])} $$ \left[ 1, 2, 3 \right] $$ \returnType{Type: List PositiveInteger} Axiom gives you two ways of writing a block and the preferred way in an {\bf .input} file is to use a pile. \index{file!input} Roughly speaking, a pile is a block whose constituent expressions are indented the same amount. You begin a pile by starting a new line for the first expression, indenting it to the right of the previous line. You then enter the second expression on a new line, vertically aligning it with the first line. And so on. If you need to enter an inner pile, further indent its lines to the right of the outer pile. Axiom knows where a pile ends. It ends when a subsequent line is indented to the left of the pile or the end of the file. Blocks can be used to perform several steps before an assignment (immediate or delayed) is made. \begin{verbatim} d := c := a**2 + b**2 sqrt(c * 1.3) \end{verbatim} $$ 2.5495097567 96392415 $$ \returnType{Type: Float} Blocks can be used in the arguments to functions. (Here $h$ is assigned $2.1 + 3.5$.) \begin{verbatim} h := 2.1 + 1.0 3.5 \end{verbatim} $$ 5.6 $$ \returnType{Type: Float} Here the second argument to {\bf eval} is $x = z$, where the value of $z$ is computed in the first line of the block starting on the second line. \begin{verbatim} eval(x**2 - x*y**2, z := %pi/2.0 - exp(4.1) x = z ) \end{verbatim} $$ {{58.7694912705 67072878} \ {y \sp 2}}+{3453.8531042012 59382} $$ \returnType{Type: Polynomial Float} Blocks can be used in the clauses of {\tt if-then-else} expressions (see \ref{ugLangIf} on page~\pageref{ugLangIf}). \spadcommand{if h > 3.1 then 1.0 else (z := cos(h); max(z,0.5))} $$ 1.0 $$ \returnType{Type: Float} This is the pile version of the last block. \begin{verbatim} if h > 3.1 then 1.0 else z := cos(h) max(z,0.5) \end{verbatim} $$ 1.0 $$ \returnType{Type: Float} Blocks can be nested. \spadcommand{a := (b := factorial(12); c := (d := eulerPhi(22); factorial(d));b+c)} $$ 482630400 $$ \returnType{Type: PositiveInteger} This is the pile version of the last block. \begin{verbatim} a := b := factorial(12) c := d := eulerPhi(22) factorial(d) b+c \end{verbatim} $$ 482630400 $$ \returnType{Type: PositiveInteger} Since $c + d$ does equal $3628855$, $a$ has the value of $c$ and the last line is never evaluated. \begin{verbatim} a := c := factorial 10 d := fibonacci 10 c + d = 3628855 => c d \end{verbatim} $$ 3628800 $$ \returnType{Type: PositiveInteger} \section{if-then-else} \label{ugLangIf} Like many other programming languages, Axiom uses the three keywords \index{if} {\tt if}, {\tt then} \index{then} and {\tt else} \index{else} to form \index{conditional} conditional expressions. The {\tt else} part of the conditional is optional. The expression between the {\tt if} and {\tt then} keywords is a {\it predicate}: an expression that evaluates to or is convertible to either {\tt true} or {\tt false}, that is, a {\tt Boolean}. \index{Boolean} \boxed{4.6in}{ \vskip 0.1cm The syntax for conditional expressions is \begin{center} {\tt if\ }{\it predicate} {\tt then\ }$\hbox{\it expression}_{1}$ {\tt else\ }$\hbox{\it expression}_{2}$ \end{center} where the {\tt else} $\hbox{\it expression}_{2}$ part is optional. The value returned from a conditional expression is $\hbox{\it expression}_{1}$ if the predicate evaluates to {\tt true} and $\hbox{\it expression}_{2}$ otherwise. If no {\tt else} clause is given, the value is always the unique value of {\tt Void}.\\ } An {\tt if-then-else} expression always returns a value. If the {\tt else} clause is missing then the entire expression returns the unique value of {\tt Void}. If both clauses are present, the type of the value returned by {\tt if} is obtained by resolving the types of the values of the two clauses. See \ref{ugTypesResolve} on page~\pageref{ugTypesResolve} for more information. The predicate must evaluate to, or be convertible to, an object of type {\tt Boolean}: {\tt true} or {\tt false}. By default, the equal sign \spadopFrom{=}{Equation} creates \index{equation} an equation. This is an equation. \index{Equation} In particular, it is an object of type {\tt Equation Polynomial Integer}. \spadcommand{x + 1 = y} $$ {x+1}=y $$ \returnType{Type: Equation Polynomial Integer} However, for predicates in {\tt if} expressions, Axiom \index{equality testing} places a default target type of {\tt Boolean} on the predicate and equality testing is performed. \index{Boolean} Thus you need not qualify the ``{\tt =}'' in any way. In other contexts you may need to tell Axiom that you want to test for equality rather than create an equation. In those cases, use ``{\tt @}'' and a target type of {\tt Boolean}. See section \ref{ugTypesPkgCall} on page~\pageref{ugTypesPkgCall} for more information. The compound symbol meaning ``not equal'' in Axiom is \index{inequality testing} ``{$\sim =$}''. \index{\_notequal@$\sim =$} This can be used directly without a package call or a target specification. The expression $a$~$\sim =$~$b$ is directly translated into {\tt not}$(a = b)$. Many other functions have return values of type {\tt Boolean}. These include ``{\tt <}'', ``{\tt <=}'', ``{\tt >}'', ``{\tt >=}'', ``{\tt $\sim$=}'' and ``{\bf member?}''. By convention, operations with names ending in ``{\tt ?}'' return {\tt Boolean} values. The usual rules for piles are suspended for conditional expressions. In {\bf .input} files, the {\tt then} and {\tt else} keywords can begin in the same column as the corresponding {\tt if} but may also appear to the right. Each of the following styles of writing {\tt if-then-else} expressions is acceptable: \begin{verbatim} if i>0 then output("positive") else output("nonpositive") if i > 0 then output("positive") else output("nonpositive") if i > 0 then output("positive") else output("nonpositive") if i > 0 then output("positive") else output("nonpositive") if i > 0 then output("positive") else output("nonpositive") \end{verbatim} A block can follow the {\tt then} or {\tt else} keywords. In the following two assignments to {\tt a}, the {\tt then} and {\tt else} clauses each are followed by two-line piles. The value returned in each is the value of the second line. \begin{verbatim} a := if i > 0 then j := sin(i * pi()) exp(j + 1/j) else j := cos(i * 0.5 * pi()) log(abs(j)**5 + 1) a := if i > 0 then j := sin(i * pi()) exp(j + 1/j) else j := cos(i * 0.5 * pi()) log(abs(j)**5 + 1) \end{verbatim} These are both equivalent to the following: \begin{verbatim} a := if i > 0 then (j := sin(i * pi()); exp(j + 1/j)) else (j := cos(i * 0.5 * pi()); log(abs(j)**5 + 1)) \end{verbatim} \section{Loops} \label{ugLangLoops} A {\it loop} is an expression that contains another expression, \index{loop} called the {\it loop body}, which is to be evaluated zero or more \index{loop!body} times. All loops contain the {\tt repeat} keyword and return the unique value of {\tt Void}. Loops can contain inner loops to any depth. \boxed{4.6in}{ \vskip 0.1cm The most basic loop is of the form \begin{center} {\tt repeat\ }{\it loopBody} \end{center} Unless {\it loopBody} contains a {\tt break} or {\tt return} expression, the loop repeats forever. The value returned by the loop is the unique value of {\tt Void}.\\ } \subsection{Compiling vs. Interpreting Loops} \label{ugLangLoopsCompInt} Axiom tries to determine completely the type of every object in a loop and then to translate the loop body to LISP or even to machine code. This translation is called compilation. If Axiom decides that it cannot compile the loop, it issues a \index{loop!compilation} message stating the problem and then the following message: \begin{center} {\bf We will attempt to step through and interpret the code.} \end{center} It is still possible that Axiom can evaluate the loop but in {\it interpret-code mode}. See section \ref{ugUserCompInt} on page~\pageref{ugUserCompInt} where this is discussed in terms \index{panic!avoiding} of compiling versus interpreting functions. \subsection{return in Loops} \label{ugLangLoopsReturn} A {\tt return} expression is used to exit a function with \index{loop!leaving via return} a particular value. In particular, if a {\tt return} is in a loop within the \index{return} function, the loop is terminated whenever the {\tt return} is evaluated. %> This is a bug! The compiler should never accept allow %> Void to be the return type of a function when it has to use %> resolve to determine it. Suppose we start with this. \begin{verbatim} f() == i := 1 repeat if factorial(i) > 1000 then return i i := i + 1 \end{verbatim} \returnType{Type: Void} When {\tt factorial(i)} is big enough, control passes from inside the loop all the way outside the function, returning the value of $i$ (or so we think). \spadcommand{f()} \returnType{Type: Void} What went wrong? Isn't it obvious that this function should return an integer? Well, Axiom makes no attempt to analyze the structure of a loop to determine if it always returns a value because, in general, this is impossible. So Axiom has this simple rule: the type of the function is determined by the type of its body, in this case a block. The normal value of a block is the value of its last expression, in this case, a loop. And the value of every loop is the unique value of {\tt Void}.! So the return type of {\bf f} is {\tt Void}. There are two ways to fix this. The best way is for you to tell Axiom what the return type of $f$ is. You do this by giving $f$ a declaration {\tt f:()~->~Integer} prior to calling for its value. This tells Axiom: ``trust me---an integer is returned.'' We'll explain more about this in the next chapter. Another clumsy way is to add a dummy expression as follows. Since we want an integer, let's stick in a dummy final expression that is an integer and will never be evaluated. \begin{verbatim} f() == i := 1 repeat if factorial(i) > 1000 then return i i := i + 1 0 \end{verbatim} \returnType{Type: Void} When we try {\bf f} again we get what we wanted. See \ref{ugUserBlocks} on page~\pageref{ugUserBlocks} for more information. \spadcommand{f()} \begin{verbatim} Compiling function f with type () -> NonNegativeInteger \end{verbatim} $$ 7 $$ \returnType{Type: PositiveInteger} \subsection{break in Loops} \label{ugLangLoopsBreak} The {\tt break} keyword is often more useful \index{break} in terminating \index{loop!leaving via break} a loop. A {\tt break} causes control to transfer to the expression immediately following the loop. As loops always return the unique value of {\tt Void}., you cannot return a value with {\tt break}. That is, {\tt break} takes no argument. This example is a modification of the last example in the previous section \ref{ugLangLoopsReturn} on page~\pageref{ugLangLoopsReturn}. Instead of using {\tt return}, we'll use {\tt break}. \begin{verbatim} f() == i := 1 repeat if factorial(i) > 1000 then break i := i + 1 i \end{verbatim} \begin{verbatim} Compiled code for f has been cleared. 1 old definition(s) deleted for function or rule f \end{verbatim} \returnType{Type: Void} The loop terminates when {\tt factorial(i)} gets big enough, the last line of the function evaluates to the corresponding ``good'' value of $i$, and the function terminates, returning that value. \spadcommand{f()} \begin{verbatim} Compiling function f with type () -> PositiveInteger +++ |*0;f;1;G82322| redefined \end{verbatim} $$ 7 $$ \returnType{Type: PositiveInteger} You can only use {\tt break} to terminate the evaluation of one loop. Let's consider a loop within a loop, that is, a loop with a nested loop. First, we initialize two counter variables. \spadcommand{(i,j) := (1, 1)} $$ 1 $$ \returnType{Type: PositiveInteger} Nested loops must have multiple {\tt break} \index{loop!nested} expressions at the appropriate nesting level. How would you rewrite this so {\tt (i + j) > 10} is only evaluated once? \begin{verbatim} repeat repeat if (i + j) > 10 then break j := j + 1 if (i + j) > 10 then break i := i + 1 \end{verbatim} \returnType{Type: Void} \subsection{break vs. {\tt =>} in Loop Bodies} \label{ugLangLoopsBreakVs} Compare the following two loops: \begin{verbatim} i := 1 i := 1 repeat repeat i := i + 1 i := i + 1 i > 3 => i if i > 3 then break output(i) output(i) \end{verbatim} In the example on the left, the values $2$ and $3$ for $i$ are displayed but then the ``{\tt =>}'' does not allow control to reach the call to \spadfunFrom{output}{OutputForm} again. The loop will not terminate until you run out of space or interrupt the execution. The variable $i$ will continue to be incremented because the ``{\tt =>}'' only means to leave the {\it block}, not the loop. In the example on the right, upon reaching $4$, the {\tt break} will be executed, and both the block and the loop will terminate. This is one of the reasons why both ``{\tt =>}'' and {\tt break} are provided. Using a {\tt while} clause (see below) with the ``{\tt =>}'' \index{while} lets you simulate the action of {\tt break}. \subsection{More Examples of break} \label{ugLangLoopsBreakMore} Here we give four examples of {\tt repeat} loops that terminate when a value exceeds a given bound. First, initialize $i$ as the loop counter. \spadcommand{i := 0} $$ 0 $$ \returnType{Type: NonNegativeInteger} Here is the first loop. When the square of $i$ exceeds $100$, the loop terminates. \begin{verbatim} repeat i := i + 1 if i**2 > 100 then break \end{verbatim} \returnType{Type: Void} Upon completion, $i$ should have the value $11$. \spadcommand{i} $$ 11 $$ \returnType{Type: NonNegativeInteger} Do the same thing except use ``{\tt =>}'' instead an {\tt if-then} expression. \spadcommand{i := 0} $$ 0 $$ \returnType{Type: NonNegativeInteger} \begin{verbatim} repeat i := i + 1 i**2 > 100 => break \end{verbatim} \returnType{Type: Void} \spadcommand{i} $$ 11 $$ \returnType{Type: NonNegativeInteger} As a third example, we use a simple loop to compute $n!$. \spadcommand{(n, i, f) := (100, 1, 1)} $$ 1 $$ \returnType{Type: PositiveInteger} Use $i$ as the iteration variable and $f$ to compute the factorial. \begin{verbatim} repeat if i > n then break f := f * i i := i + 1 \end{verbatim} \returnType{Type: Void} Look at the value of $f$. \spadcommand{f} \begin{verbatim} 93326215443944152681699238856266700490715968264381621468_ 59296389521759999322991560894146397615651828625369792082_ 7223758251185210916864000000000000000000000000 \end{verbatim} \returnType{Type: PositiveInteger} Finally, we show an example of nested loops. First define a four by four matrix. \spadcommand{m := matrix [ [21,37,53,14], [8,-24,22,-16], [2,10,15,14], [26,33,55,-13] ]} $$ \left[ \begin{array}{cccc} {21} & {37} & {53} & {14} \\ 8 & -{24} & {22} & -{16} \\ 2 & {10} & {15} & {14} \\ {26} & {33} & {55} & -{13} \end{array} \right] $$ \returnType{Type: Matrix Integer} Next, set row counter $r$ and column counter $c$ to $1$. Note: if we were writing a function, these would all be local variables rather than global workspace variables. \spadcommand{(r, c) := (1, 1)} $$ 1 $$ \returnType{Type: PositiveInteger} Also, let {\tt lastrow} and {\tt lastcol} be the final row and column index. \spadcommand{(lastrow, lastcol) := (nrows(m), ncols(m))} $$ 4 $$ \returnType{Type: PositiveInteger} Scan the rows looking for the first negative element. We remark that you can reformulate this example in a better, more concise form by using a {\tt for} clause with {\tt repeat}. See \ref{ugLangLoopsForIn} on page~\pageref{ugLangLoopsForIn} for more information. \begin{verbatim} repeat if r > lastrow then break c := 1 repeat if c > lastcol then break if elt(m,r,c) < 0 then output [r, c, elt(m,r,c)] r := lastrow break -- don't look any further c := c + 1 r := r + 1 [2,2,- 24] \end{verbatim} \returnType{Type: Void} \subsection{iterate in Loops} \label{ugLangLoopsIterate} Axiom provides an {\tt iterate} expression that \index{iterate} skips over the remainder of a loop body and starts the next loop iteration. We first initialize a counter. \spadcommand{i := 0} $$ 0 $$ \returnType{Type: NonNegativeInteger} Display the even integers from $2$ to $5$. \begin{verbatim} repeat i := i + 1 if i > 5 then break if odd?(i) then iterate output(i) 2 4 \end{verbatim} \returnType{Type: Void} \subsection{while Loops} \label{ugLangLoopsWhile} The {\tt repeat} in a loop can be modified by adding one or more {\tt while} clauses. \index{while} Each clause contains a {\it predicate} immediately following the {\tt while} keyword. The predicate is tested {\it before} the evaluation of the body of the loop. The loop body is evaluated whenever the predicates in a {\tt while} clause are all {\tt true}. \boxed{4.6in}{ \vskip 0.1cm The syntax for a simple loop using {\tt while} is \begin{center} {\tt while} {\it predicate} {\tt repeat} {\it loopBody} \end{center} The {\it predicate} is evaluated before {\it loopBody} is evaluated. A {\tt while} loop terminates immediately when {\it predicate} evaluates to {\tt false} or when a {\tt break} or {\tt return} expression is evaluated in {\it loopBody}. The value returned by the loop is the unique value of {\tt Void}.\\ } Here is a simple example of using {\tt while} in a loop. We first initialize the counter. \spadcommand{i := 1} $$ 1 $$ \returnType{Type: PositiveInteger} The steps involved in computing this example are\\ (1) set $i$ to $1$,\\ (2) test the condition $i < 1$ and determine that it is not {\tt true}, and\\ (3) do not evaluate the loop body and therefore do not display $"hello"$. \begin{verbatim} while i < 1 repeat output "hello" i := i + 1 \end{verbatim} \returnType{Type: Void} If you have multiple predicates to be tested use the logical {\tt and} operation to separate them. Axiom evaluates these predicates from left to right. \spadcommand{(x, y) := (1, 1)} $$ 1 $$ \returnType{Type: PositiveInteger} \begin{verbatim} while x < 4 and y < 10 repeat output [x,y] x := x + 1 y := y + 2 [1,1] [2,3] [3,5] \end{verbatim} \returnType{Type: Void} A {\tt break} expression can be included in a loop body to terminate a loop even if the predicate in any {\tt while} clauses are not {\tt false}. \spadcommand{(x, y) := (1, 1)} $$ 1 $$ \returnType{Type: PositiveInteger} This loop has multiple {\tt while} clauses and the loop terminates before any one of their conditions evaluates to {\tt false}. \begin{verbatim} while x < 4 while y < 10 repeat if x + y > 7 then break output [x,y] x := x + 1 y := y + 2 [1,1] [2,3] \end{verbatim} \returnType{Type: Void} Here's a different version of the nested loops that looked for the first negative element in a matrix. \spadcommand{m := matrix [ [21,37,53,14], [8,-24,22,-16], [2,10,15,14], [26,33,55,-13] ]} $$ \left[ \begin{array}{cccc} {21} & {37} & {53} & {14} \\ 8 & -{24} & {22} & -{16} \\ 2 & {10} & {15} & {14} \\ {26} & {33} & {55} & -{13} \end{array} \right] $$ \returnType{Type: Matrix Integer} Initialized the row index to $1$ and get the number of rows and columns. If we were writing a function, these would all be local variables. \spadcommand{r := 1} $$ 1 $$ \returnType{Type: PositiveInteger} \spadcommand{(lastrow, lastcol) := (nrows(m), ncols(m))} $$ 4 $$ \returnType{Type: PositiveInteger} Scan the rows looking for the first negative element. \begin{verbatim} while r <= lastrow repeat c := 1 -- index of first column while c <= lastcol repeat if elt(m,r,c) < 0 then output [r, c, elt(m,r,c)] r := lastrow break -- don't look any further c := c + 1 r := r + 1 [2,2,- 24] \end{verbatim} \returnType{Type: Void} \subsection{for Loops} \label{ugLangLoopsForIn} Axiom provides the {\tt for} \index{for} and {\tt in\ } \index{in} keywords in {\tt repeat} loops, allowing you to iterate across all \index{iteration} elements of a list, or to have a variable take on integral values from a lower bound to an upper bound. We shall refer to these modifying clauses of {\tt repeat} loops as {\tt for} clauses. These clauses can be present in addition to {\tt while} clauses. As with all other types of {\tt repeat} loops, {\tt break} can \index{break} be used to prematurely terminate the evaluation of the loop. \boxed{4.6in}{ \vskip 0.1cm The syntax for a simple loop using {\tt for} is \begin{center} {\tt for} {\it iterator} {\tt repeat} {\it loopBody} \end{center} The {\it iterator} has several forms. Each form has an end test which is evaluated before {\it loopBody} is evaluated. A {\tt for} loop terminates immediately when the end test succeeds (evaluates to {\tt true}) or when a {\tt break} or {\tt return} expression is evaluated in {\it loopBody}. The value returned by the loop is the unique value of {\tt Void}.\\ } \subsection{for i in n..m repeat} \label{ugLangLoopsForInNM} If {\tt for} \index{for} is followed by a variable name, the {\tt in\ } \index{in} keyword and then an integer segment of the form $n..m$, \index{segment} the end test for this loop is the predicate $i > m$. The body of the loop is evaluated $m-n+1$ times if this number is greater than 0. If this number is less than or equal to 0, the loop body is not evaluated at all. The variable $i$ has the value $n, n+1, ..., m$ for successive iterations of the loop body.The loop variable is a {\it local variable} within the loop body: its value is not available outside the loop body and its value and type within the loop body completely mask any outer definition of a variable with the same name. This loop prints the values of ${10}^3$, ${11}^3$, and $12^3$: \spadcommand{for i in 10..12 repeat output(i**3)} \begin{verbatim} 1000 1331 1728 \end{verbatim} \returnType{Type: Void} Here is a sample list. \spadcommand{a := [1,2,3]} $$ \left[ 1, 2, 3 \right] $$ \returnType{Type: List PositiveInteger} Iterate across this list, using ``{\tt .}'' to access the elements of a list and the ``{\bf \#}'' operation to count its elements. \spadcommand{for i in 1..\#a repeat output(a.i)} \begin{verbatim} 1 2 3 \end{verbatim} \returnType{Type: Void} This type of iteration is applicable to anything that uses ``{\tt .}''. You can also use it with functions that use indices to extract elements. Define $m$ to be a matrix. \spadcommand{m := matrix [ [1,2],[4,3],[9,0] ]} $$ \left[ \begin{array}{cc} 1 & 2 \\ 4 & 3 \\ 9 & 0 \end{array} \right] $$ \returnType{Type: Matrix Integer} Display the rows of $m$. \spadcommand{for i in 1..nrows(m) repeat output row(m,i)} \begin{verbatim} [1,2] [4,3] [9,0] \end{verbatim} \returnType{Type: Void} You can use {\tt iterate} with {\tt for}-loops.\index{iterate} Display the even integers in a segment. \begin{verbatim} for i in 1..5 repeat if odd?(i) then iterate output(i) 2 4 \end{verbatim} \returnType{Type: Void} See section \ref{SegmentXmpPage} on page~\pageref{SegmentXmpPage} for more information about segments. \subsection{for i in n..m by s repeat} \label{ugLangLoopsForInNMS} By default, the difference between values taken on by a variable in loops such as {\tt for i in n..m repeat ...} is $1$. It is possible to supply another, possibly negative, step value by using the {\tt by} \index{by} keyword along with {\tt for} and {\tt in\ }. Like the upper and lower bounds, the step value following the {\tt by} keyword must be an integer. Note that the loop {\tt for i in 1..2 by 0 repeat output(i)} will not terminate by itself, as the step value does not change the index from its initial value of $1$. This expression displays the odd integers between two bounds. \spadcommand{for i in 1..5 by 2 repeat output(i)} \begin{verbatim} 1 3 5 \end{verbatim} \returnType{Type: Void} Use this to display the numbers in reverse order. \spadcommand{for i in 5..1 by -2 repeat output(i)} \begin{verbatim} 5 3 1 \end{verbatim} \returnType{Type: Void} \subsection{for i in n.. repeat} \label{ugLangLoopsForInN} If the value after the ``{\tt ..}'' is omitted, the loop has no end test. A potentially infinite loop is thus created. The variable is given the successive values ${n}, {n+1}, {n+2}, ...$ and the loop is terminated only if a {\tt break} or {\tt return} expression is evaluated in the loop body. However you may also add some other modifying clause on the {\tt repeat} (for example, a {\tt while} clause) to stop the loop. This loop displays the integers greater than or equal to $15$ and less than the first prime greater than $15$. \spadcommand{for i in 15.. while not prime?(i) repeat output(i)} \begin{verbatim} 15 16 \end{verbatim} \returnType{Type: Void} \subsection{for x in l repeat} \label{ugLangLoopsForInXL} Another variant of the {\tt for} loop has the form: \begin{center} {\it {\tt for} x {\tt in\ } list {\tt repeat} loopBody} \end{center} This form is used when you want to iterate directly over the elements of a list. In this form of the {\tt for} loop, the variable {\tt x} takes on the value of each successive element in {\tt l}. The end test is most simply stated in English: ``are there no more {\tt x} in {\tt l}?'' If {\tt l} is this list, \spadcommand{l := [0,-5,3]} $$ \left[ 0, -5, 3 \right] $$ \returnType{Type: List Integer} display all elements of {\tt l}, one per line. \spadcommand{for x in l repeat output(x)} \begin{verbatim} 0 - 5 3 \end{verbatim} \returnType{Type: Void} Since the list constructing expression {\bf expand}{\tt [n..m]} creates the list $[n, {n+1}, ..., m]$. Note that this list is empty if $n > m$. You might be tempted to think that the loops \begin{verbatim} for i in n..m repeat output(i) \end{verbatim} and \begin{verbatim} for x in expand [n..m] repeat output(x) \end{verbatim} are equivalent. The second form first creates the list {\bf expand}{\tt [n..m]} (no matter how large it might be) and then does the iteration. The first form potentially runs in much less space, as the index variable $i$ is simply incremented once per loop and the list is not actually created. Using the first form is much more efficient. Of course, sometimes you really want to iterate across a specific list. This displays each of the factors of $2400000$. \spadcommand{for f in factors(factor(2400000)) repeat output(f)} \begin{verbatim} [factor= 2,exponent= 8] [factor= 3,exponent= 1] [factor= 5,exponent= 5] \end{verbatim} \returnType{Type: Void} \subsection{``Such that'' Predicates} \label{ugLangLoopsForInPred} A {\tt for} loop can be followed by a ``{\tt |}'' and then a predicate. The predicate qualifies the use of the values from the iterator following the {\tt for}. Think of the vertical bar ``{\tt |}'' as the phrase ``such that.'' This loop expression prints out the integers $n$ in the given segment such that $n$ is odd. \spadcommand{for n in 0..4 | odd? n repeat output n} \begin{verbatim} 1 3 \end{verbatim} \returnType{Type: Void} \boxed{4.6in}{ \vskip 0.1cm A {\tt for} loop can also be written $$ {\rm for} {\it \ iterator\ } | {\it \ predicate\ } {\rm repeat} {\it \ loopBody\ } $$ which is equivalent to: $$ {\rm for} {\it \ iterator\ } {\rm repeat\ if} {\it \ predicate\ } {\rm then} {\it \ loopBody\ } {\rm else\ }iterate $$ } The predicate need not refer only to the variable in the {\tt for} clause: any variable in an outer scope can be part of the predicate. In this example, the predicate on the inner {\tt for} loop uses $i$ from the outer loop and the $j$ from the {\tt for} \index{iteration!nested} clause that it directly modifies. \begin{verbatim} for i in 1..50 repeat for j in 1..50 | factorial(i+j) < 25 repeat output [i,j] [1,1] [1,2] [1,3] [2,1] [2,2] [3,1] \end{verbatim} \returnType{Type: Void} \subsection{Parallel Iteration} \label{ugLangLoopsPar} The last example of the previous section \ref{ugLangLoopsForInPred} on page~\pageref{ugLangLoopsForInPred} gives an example of {\it nested iteration}: a loop is contained \index{iteration!nested} in another loop. \index{iteration!parallel} Sometimes you want to iterate across two lists in parallel, or perhaps you want to traverse a list while incrementing a variable. \boxed{4.6in}{ \vskip 0.1cm The general syntax of a repeat loop is $$ iterator_1\ iterator_2\ \ldots\ iterator_N {\rm \ repeat\ } loopBody $$ where each {\it iterator} is either a {\tt for} or a {\tt while} clause. The loop terminates immediately when the end test of any {\it iterator} succeeds or when a {\tt break} or {\tt return} expression is evaluated in {\it loopBody}. The value returned by the loop is the unique value of {\tt Void}.\\ } Here we write a loop to iterate across two lists, computing the sum of the pairwise product of elements. Here is the first list. \spadcommand{l := [1,3,5,7]} $$ \left[ 1, 3, 5, 7 \right] $$ \returnType{Type: List PositiveInteger} And the second. \spadcommand{m := [100,200]} $$ \left[ {100}, {200} \right] $$ \returnType{Type: List PositiveInteger} The initial value of the sum counter. \spadcommand{sum := 0} $$ 0 $$ \returnType{Type: NonNegativeInteger} The last two elements of $l$ are not used in the calculation because $m$ has two fewer elements than $l$. \begin{verbatim} for x in l for y in m repeat sum := sum + x*y \end{verbatim} \returnType{Type: Void} Display the ``dot product.'' \spadcommand{sum} $$ 700 $$ \returnType{Type: NonNegativeInteger} Next, we write a loop to compute the sum of the products of the loop elements with their positions in the loop. \spadcommand{l := [2,3,5,7,11,13,17,19,23,29,31,37]} $$ \left[ 2, 3, 5, 7, {11}, {13}, {17}, {19}, {23}, {29}, {31}, {37} \right] $$ \returnType{Type: List PositiveInteger} The initial sum. \spadcommand{sum := 0} $$ 0 $$ \returnType{Type: NonNegativeInteger} Here looping stops when the list $l$ is exhausted, even though the $for i in 0..$ specifies no terminating condition. \spadcommand{for i in 0.. for x in l repeat sum := i * x} \returnType{Type: Void} Display this weighted sum. \spadcommand{sum} $$ 407 $$ \returnType{Type: NonNegativeInteger} When ``{\tt |}'' is used to qualify any of the {\tt for} clauses in a parallel iteration, the variables in the predicates can be from an outer scope or from a {\tt for} clause in or to the left of a modified clause. This is correct: % output from following is too long to show \begin{verbatim} for i in 1..10 repeat for j in 200..300 | odd? (i+j) repeat output [i,j] \end{verbatim} This is not correct since the variable $j$ has not been defined outside the inner loop. \begin{verbatim} for i in 1..10 | odd? (i+j) repeat -- wrong, j not defined for j in 200..300 repeat output [i,j] \end{verbatim} \subsection{Mixing Loop Modifiers} \label{ugLangLoopsMix} This example shows that it is possible to mix several of the \index{loop!mixing modifiers} forms of {\tt repeat} modifying clauses on a loop. \begin{verbatim} for i in 1..10 for j in 151..160 | odd? j while i + j < 160 repeat output [i,j] [1,151] [3,153] \end{verbatim} \returnType{Type: Void} Here are useful rules for composing loop expressions: \begin{enumerate} \item {\tt while} predicates can only refer to variables that are global (or in an outer scope) or that are defined in {\tt for} clauses to the left of the predicate. \item A ``such that'' predicate (something following ``{\tt |}'') must directly follow a {\tt for} clause and can only refer to variables that are global (or in an outer scope) or defined in the modified {\tt for} clause or any {\tt for} clause to the left. \end{enumerate} \section{Creating Lists and Streams with Iterators} \label{ugLangIts} All of what we did for loops in \ref{ugLangLoops} on page~\pageref{ugLangLoops} \index{iteration} can be transformed into expressions that create lists \index{list!created by iterator} and streams. \index{stream!created by iterator} The {\tt repeat}, {\tt break} or {\tt iterate} words are not used but all the other ideas carry over. Before we give you the general rule, here are some examples which give you the idea. This creates a simple list of the integers from $1$ to $10$. \spadcommand{list := [i for i in 1..10]} $$ \left[ 1, 2, 3, 4, 5, 6, 7, 8, 9, {10} \right] $$ \returnType{Type: List PositiveInteger} Create a stream of the integers greater than or equal to $1$. \spadcommand{stream := [i for i in 1..]} $$ \left[ 1, 2, 3, 4, 5, 6, 7, 8, 9, {10}, \ldots \right] $$ \returnType{Type: Stream PositiveInteger} This is a list of the prime integers between $1$ and $10$, inclusive. \spadcommand{[i for i in 1..10 | prime? i]} $$ \left[ 2, 3, 5, 7 \right] $$ \returnType{Type: List PositiveInteger} This is a stream of the prime integers greater than or equal to $1$. \spadcommand{[i for i in 1.. | prime? i]} $$ \left[ 2, 3, 5, 7, {11}, {13}, {17}, {19}, {23}, {29}, \ldots \right] $$ \returnType{Type: Stream PositiveInteger} This is a list of the integers between $1$ and $10$, inclusive, whose squares are less than $700$. \spadcommand{[i for i in 1..10 while i*i < 700]} $$ \left[ 1, 2, 3, 4, 5, 6, 7, 8, 9, {10} \right] $$ \returnType{Type: List PositiveInteger} This is a stream of the integers greater than or equal to $1$ whose squares are less than $700$. \spadcommand{[i for i in 1.. while i*i < 700]} $$ \left[ 1, 2, 3, 4, 5, 6, 7, 8, 9, {10}, \ldots \right] $$ \returnType{Type: Stream PositiveInteger} Here is the general rule. \index{collection} \boxed{4.6in}{ \vskip 0.1cm The general syntax of a collection is \begin{center} {\tt [ {\it collectExpression} $\hbox{\it iterator}_{1}$ $\hbox{\it iterator}_{2}$ \ldots $\hbox{\it iterator}_{N}$ ]} \end{center} where each $\hbox{\it iterator}_{i}$ is either a {\tt for} or a {\tt while} clause. The loop terminates immediately when the end test of any $\hbox{\it iterator}_{i}$ succeeds or when a {\tt return} expression is evaluated in {\it collectExpression}. The value returned by the collection is either a list or a stream of elements, one for each iteration of the {\it collectExpression}.\\ } Be careful when you use {\tt while} \index{stream!using while @{using {\tt while}}} to create a stream. By default, Axiom tries to compute and display the first ten elements of a stream. If the {\tt while} condition is not satisfied quickly, Axiom can spend a long (possibly infinite) time trying to compute \index{stream!number of elements computed} the elements. Use {\tt )set streams calculate} to change the default to something else. \index{set streams calculate} This also affects the number of terms computed and displayed for power series. For the purposes of this book, we have used this system command to display fewer than ten terms. Use nested iterators to create lists of \index{iteration!nested} lists which can then be given as an argument to {\bf matrix}. \spadcommand{matrix [ [x**i+j for i in 1..3] for j in 10..12]} $$ \left[ \begin{array}{ccc} {x+{10}} & {{x \sp 2}+{10}} & {{x \sp 3}+{10}} \\ {x+{11}} & {{x \sp 2}+{11}} & {{x \sp 3}+{11}} \\ {x+{12}} & {{x \sp 2}+{12}} & {{x \sp 3}+{12}} \end{array} \right] $$ \returnType{Type: Matrix Polynomial Integer} You can also create lists of streams, streams of lists and streams of streams. Here is a stream of streams. \spadcommand{[ [i/j for i in j+1..] for j in 1..]} $$ \begin{array}{@{}l} \left[ {\left[ 2, 3, 4, 5, 6, 7, 8, 9, {10}, {11}, \ldots \right]}, {\left[ {3 \over 2}, 2, {5 \over 2}, 3, {7 \over 2}, 4, {9 \over 2}, 5, {{11} \over 2}, 6, \ldots \right]}, \right. \\ \\ \displaystyle {\left[ {4 \over 3}, {5 \over 3}, 2, {7 \over 3}, {8 \over 3}, 3, {{10} \over 3}, {{11} \over 3}, 4, {{13} \over 3}, \ldots \right]}, {\left[ {5 \over 4}, {3 \over 2}, {7 \over 4}, 2, {9 \over 4}, {5 \over 2}, {{11} \over 4}, 3, {{13} \over 4}, {7 \over 2}, \ldots \right]}, \\ \\ \displaystyle {\left[ {6 \over 5}, {7 \over 5}, {8 \over 5}, {9 \over 5}, 2, {{11} \over 5}, {{12} \over 5}, {{13} \over 5}, {{14} \over 5}, 3, \ldots \right]}, {\left[ {7 \over 6}, {4 \over 3}, {3 \over 2}, {5 \over 3}, {{11} \over 6}, 2, {{13} \over 6}, {7 \over 3}, {5 \over 2}, {8 \over 3}, \ldots \right]}, \\ \\ \displaystyle {\left[ {8 \over 7}, {9 \over 7}, {{10} \over 7}, {{11} \over 7}, {{12} \over 7}, {{13} \over 7}, 2, {{15} \over 7}, {{16} \over 7}, {{17} \over 7}, \ldots \right]}, {\left[ {9 \over 8}, {5 \over 4}, {{11} \over 8}, {3 \over 2}, {{13} \over 8}, {7 \over 4}, {{15} \over 8}, 2, {{17} \over 8}, {9 \over 4}, \ldots \right]}, \\ \\ \displaystyle {\left[ {{10} \over 9}, {{11} \over 9}, {4 \over 3}, {{13} \over 9}, {{14} \over 9}, {5 \over 3}, {{16} \over 9}, {{17} \over 9}, 2, {{19} \over 9}, \ldots \right]}, \\ \\ \displaystyle \left. {\left[ {{11} \over {10}}, {6 \over 5}, {{13} \over {10}}, {7 \over 5}, {3 \over 2}, {8 \over 5}, {{17} \over {10}}, {9 \over 5}, {{19} \over {10}}, 2, \ldots \right]}, \ldots \right] \end{array} $$ \returnType{Type: Stream Stream Fraction Integer} You can use parallel iteration across lists and streams to create \index{iteration!parallel} new lists. \spadcommand{[i/j for i in 3.. by 10 for j in 2..]} $$ \left[ {3 \over 2}, {{13} \over 3}, {{23} \over 4}, {{33} \over 5}, {{43} \over 6}, {{53} \over 7}, {{63} \over 8}, {{73} \over 9}, {{83} \over {10}}, {{93} \over {11}}, \ldots \right] $$ \returnType{Type: Stream Fraction Integer} Iteration stops if the end of a list or stream is reached. \spadcommand{[i**j for i in 1..7 for j in 2.. ]} $$ \left[ 1, 8, {81}, {1024}, {15625}, {279936}, {5764801} \right] $$ \returnType{Type: Stream Integer} %or a while condition fails. %\spadcommand{[i**j for i in 1.. for j in 2.. while i + j < 5 ]} %tpdhere % There are no library operations named swhile % Use HyperDoc Browse or issue % )what op swhile % to learn if there is any operation containing " swhile " in its % name. % % Cannot find a definition or applicable library operation named % swhile with argument type(s) % (Record(part1: PositiveInteger,part2: PositiveInteger) -> Boolean) % InfiniteTuple Record(part1: PositiveInteger,part2: PositiveInteger) % % Perhaps you should use "@" to indicate the required return type, % or "$" to specify which version of the function you need. As with loops, you can combine these modifiers to make very complicated conditions. \spadcommand{[ [ [i,j] for i in 10..15 | prime? i] for j in 17..22 | j = squareFreePart j]} $$ \left[ {\left[ {\left[ {11}, {17} \right]}, {\left[ {13}, {17} \right]} \right]}, {\left[ {\left[ {11}, {19} \right]}, {\left[ {13}, {19} \right]} \right]}, {\left[ {\left[ {11}, {21} \right]}, {\left[ {13}, {21} \right]} \right]}, {\left[ {\left[ {11}, {22} \right]}, {\left[ {13}, {22} \right]} \right]} \right] $$ \returnType{Type: List List List PositiveInteger} See List (section \ref{ListXmpPage} on page~\pageref{ListXmpPage}) and Stream (section \ref{StreamXmpPage} on page~\pageref{StreamXmpPage}) for more information on creating and manipulating lists and streams, respectively. \section{An Example: Streams of Primes} \label{ugLangStreamsPrimes} We conclude this chapter with an example of the creation and manipulation of infinite streams of prime integers. This might be useful for experiments with numbers or other applications where you are using sequences of primes over and over again. As for all streams, the stream of primes is only computed as far out as you need. Once computed, however, all the primes up to that point are saved for future reference. Two useful operations provided by the Axiom library are \spadfunFrom{prime?}{IntegerPrimesPackage} and \spadfunFrom{nextPrime}{IntegerPrimesPackage}. A straight-forward way to create a stream of prime numbers is to start with the stream of positive integers $[2,..]$ and filter out those that are prime. Create a stream of primes. \spadcommand{primes : Stream Integer := [i for i in 2.. | prime? i]} $$ \left[ 2, 3, 5, 7, {11}, {13}, {17}, {19}, {23}, {29}, \ldots \right] $$ \returnType{Type: Stream Integer} A more elegant way, however, is to use the \spadfunFrom{generate}{Stream} operation from {\tt Stream}. Given an initial value $a$ and a function $f$, \spadfunFrom{generate}{Stream} constructs the stream $[a, f(a), f(f(a)), ...]$. This function gives you the quickest method of getting the stream of primes. This is how you use \spadfunFrom{generate}{Stream} to generate an infinite stream of primes. \spadcommand{primes := generate(nextPrime,2)} $$ \left[ 2, 3, 5, 7, {11}, {13}, {17}, {19}, {23}, {29}, \ldots \right] $$ \returnType{Type: Stream Integer} Once the stream is generated, you might only be interested in primes starting at a particular value. \spadcommand{smallPrimes := [p for p in primes | p > 1000]} $$ \left[ {1009}, {1013}, {1019}, {1021}, {1031}, {1033}, {1039}, {1049}, {1051}, {1061}, \ldots \right] $$ \returnType{Type: Stream Integer} Here are the first 11 primes greater than 1000. \spadcommand{[p for p in smallPrimes for i in 1..11]} $$ \left[ {1009}, {1013}, {1019}, {1021}, {1031}, {1033}, {1039}, {1049}, {1051}, {1061}, \ldots \right] $$ \returnType{Type: Stream Integer} Here is a stream of primes between 1000 and 1200. \spadcommand{[p for p in smallPrimes while p < 1200]} $$ \left[ {1009}, {1013}, {1019}, {1021}, {1031}, {1033}, {1039}, {1049}, {1051}, {1061}, \ldots \right] $$ \returnType{Type: Stream Integer} To get these expanded into a finite stream, you call \spadfunFrom{complete}{Stream} on the stream. \spadcommand{complete \%} $$ \left[ {1009}, {1013}, {1019}, {1021}, {1031}, {1033}, {1039}, {1049}, {1051}, {1061}, \ldots \right] $$ \returnType{Type: Stream Integer} Twin primes are consecutive odd number pairs which are prime. Here is the stream of twin primes. \spadcommand{twinPrimes := [ [p,p+2] for p in primes | prime?(p + 2)]} $$ \begin{array}{@{}l} \left[ {\left[ 3, 5 \right]}, {\left[ 5, 7 \right]}, {\left[ {11}, {13} \right]}, {\left[ {17}, {19} \right]}, {\left[ {29}, {31} \right]}, {\left[ {41}, {43} \right]}, {\left[ {59}, {61} \right]}, {\left[ {71}, {73} \right]}, \right. \\ \\ \displaystyle \left. {\left[ {101}, {103} \right]}, {\left[ {107}, {109} \right]}, \ldots \right] \end{array} $$ \returnType{Type: Stream List Integer} Since we already have the primes computed we can avoid the call to \spadfunFrom{prime?}{IntegerPrimesPackage} by using a double iteration. This time we'll just generate a stream of the first of the twin primes. \spadcommand{firstOfTwins:= [p for p in primes for q in rest primes | q=p+2]} $$ \left[ 3, 5, {11}, {17}, {29}, {41}, {59}, {71}, {101}, {107}, \ldots \right] $$ \returnType{Type: Stream Integer} Let's try to compute the infinite stream of triplet primes, the set of primes $p$ such that $[p,p+2,p+4]$ are primes. For example, $[3,5,7]$ is a triple prime. We could do this by a triple {\tt for} iteration. A more economical way is to use {\bf firstOfTwins}. This time however, put a semicolon at the end of the line. Create the stream of firstTriplets. Put a semicolon at the end so that no elements are computed. \spadcommand{firstTriplets := [p for p in firstOfTwins for q in rest firstOfTwins | q = p+2];} \returnType{Type: Stream Integer} What happened? As you know, by default Axiom displays the first ten elements of a stream when you first display it. And, therefore, it needs to compute them! If you want {\it no} elements computed, just terminate the expression by a semicolon (``{\tt ;}''). The semi-colon prevents the display of the result of evaluating the expression. Since no stream elements are needed for display (or anything else, so far), none are computed. Compute the first triplet prime. \spadcommand{firstTriplets.1} $$ 3 $$ \returnType{Type: PositiveInteger} If you want to compute another, just ask for it. But wait a second! Given three consecutive odd integers, one of them must be divisible by $3$. Thus there is only one triplet prime. But suppose that you did not know this and wanted to know what was the tenth triplet prime. \begin{verbatim} firstTriples.10 \end{verbatim} To compute the tenth triplet prime, Axiom first must compute the second, the third, and so on. But since there isn't even a second triplet prime, Axiom will compute forever. Nonetheless, this effort can produce a useful result. After waiting a bit, hit \fbox{\bf Ctrl-c}. The system responds as follows. \begin{verbatim} >> System error: Console interrupt. You are being returned to the top level of the interpreter. \end{verbatim} If you want to know how many primes have been computed, type: \begin{verbatim} numberOfComputedEntries primes \end{verbatim} and, for this discussion, let's say that the result is $2045$. How big is the $2045$-th prime? \spadcommand{primes.2045} $$ 17837 $$ \returnType{Type: PositiveInteger} What you have learned is that there are no triplet primes between 5 and 17837. Although this result is well known (some might even say trivial), there are many experiments you could make where the result is not known. What you see here is a paradigm for testing of hypotheses. Here our hypothesis could have been: ``there is more than one triplet prime.'' We have tested this hypothesis for 17837 cases. With streams, you can let your machine run, interrupt it to see how far it has progressed, then start it up and let it continue from where it left off. \setcounter{chapter}{2} \chapter{User-Defined Functions, Macros and Rules} \label{ugUser} In this chapter we show you how to write functions and macros, and we explain how Axiom looks for and applies them. We show some simple one-line examples of functions, together with larger ones that are defined piece-by-piece or through the use of piles. \section{Functions vs. Macros} \label{ugUserFunMac} A function is a program to perform some \index{function!vs. macro} computation. \index{macro!vs. function} Most functions have names so that it is easy to refer to them. A simple example of a function is one named \spadfunFrom{abs}{Integer} which computes the absolute value of an integer. This is a use of the ``absolute value'' library function for integers. \spadcommand{abs(-8)} $$ 8 $$ \returnType{Type: PositiveInteger} This is an unnamed function that does the same thing, using the ``maps-to'' syntax {\tt +->} that we discuss in section \ref{ugUserAnon} on page~\pageref{ugUserAnon}. \spadcommand{(x +-> if x < 0 then -x else x)(-8)} $$ 8 $$ \returnType{Type: PositiveInteger} Functions can be used alone or serve as the building blocks for larger programs. Usually they return a value that you might want to use in the next stage of a computation, but not always (for example, see \ref{ExitXmpPage} on page~\pageref{ExitXmpPage} and \ref{VoidXmpPage} on page~\pageref{VoidXmpPage}). They may also read data from your keyboard, move information from one place to another, or format and display results on your screen. In Axiom, as in mathematics, functions \index{function!parameters} are usually parameterized. Each time you {\it call} (some people say {\it apply} or invoke) a function, you give \index{parameters to a function} values to the parameters (variables). Such a value is called an {\it argument} of \index{function!arguments} the function. Axiom uses the arguments for the computation. In this way you get different results depending on what you ``feed'' the function. Functions can have local variables or refer to global variables in the workspace. Axiom can often compile functions so that they execute very efficiently. Functions can be passed as arguments to other functions. Macros are textual substitutions. They are used to clarify the meaning of constants or expressions and to be templates for frequently used expressions. Macros can be parameterized but they are not objects that can be passed as arguments to functions. In effect, macros are extensions to the Axiom expression parser. \section{Macros} \label{ugUserMacros} A {\it macro} provides general textual substitution of \index{macro} an Axiom expression for a name. You can think of a macro as being a generalized abbreviation. You can only have one macro in your workspace with a given name, no matter how many arguments it has. \boxed{4.6in}{ \vskip 0.1cm The two general forms for macros are \begin{center} {\tt macro} {\it name} {\tt ==} {\it body} \\ {\tt macro} {\it name(arg1,...)} {\tt ==} {\it body} \end{center} where the body of the macro can be any Axiom expression.\\ } For example, suppose you decided that you like to use {\tt df} for {\tt D}. You define the macro {\tt df} like this. \spadcommand{macro df == D} \returnType{Type: Void} Whenever you type {\tt df}, the system expands it to {\tt D}. \spadcommand{df(x**2 + x + 1,x)} $$ {2 \ x}+1 $$ \returnType{Type: Polynomial Integer} Macros can be parameterized and so can be used for many different kinds of objects. \spadcommand{macro ff(x) == x**2 + 1} \returnType{Type: Void} Apply it to a number, a symbol, or an expression. \spadcommand{ff z} $$ {z \sp 2}+1 $$ \returnType{Type: Polynomial Integer} Macros can also be nested, but you get an error message if you run out of space because of an infinite nesting loop. \spadcommand{macro gg(x) == ff(2*x - 2/3)} \returnType{Type: Void} This new macro is fine as it does not produce a loop. \spadcommand{gg(1/w)} $$ {{{13} \ {w \sp 2}} -{{24} \ w}+{36}} \over {9 \ {w \sp 2}} $$ \returnType{Type: Fraction Polynomial Integer} This, however, loops since {\tt gg} is defined in terms of {\tt ff}. \spadcommand{macro ff(x) == gg(-x)} \returnType{Type: Void} The body of a macro can be a block. \spadcommand{macro next == (past := present; present := future; future := past + present)} \returnType{Type: Void} Before entering {\tt next}, we need values for {\tt present} and {\tt future}. \spadcommand{present : Integer := 0} $$ 0 $$ \returnType{Type: Integer} \spadcommand{future : Integer := 1} $$ 1 $$ \returnType{Type: Integer} Repeatedly evaluating {\tt next} produces the next Fibonacci number. \spadcommand{next} $$ 1 $$ \returnType{Type: Integer} And the next one. \spadcommand{next} $$ 2 $$ \returnType{Type: Integer} Here is the infinite stream of the rest of the Fibonacci numbers. \spadcommand{[next for i in 1..]} $$ \left[ 3, 5, 8, {13}, {21}, {34}, {55}, {89}, {144}, {233}, \ldots \right] $$ \returnType{Type: Stream Integer} Bundle all the above lines into a single macro. \begin{verbatim} macro fibStream == present : Integer := 1 future : Integer := 1 [next for i in 1..] where macro next == past := present present := future future := past + present \end{verbatim} \returnType{Type: Void} Use \spadfunFrom{concat}{Stream} to start with the first two \index{Fibonacci numbers} Fibonacci numbers. \spadcommand{concat([0,1],fibStream)} $$ \left[ 0, 1, 2, 3, 5, 8, {13}, {21}, {34}, {55}, \ldots \right] $$ \returnType{Type: Stream Integer} The library operation {\bf fibonacci} is an easier way to compute these numbers. \spadcommand{[fibonacci i for i in 1..]} $$ \left[ 1, 1, 2, 3, 5, 8, {13}, {21}, {34}, {55}, \ldots \right] $$ \returnType{Type: Stream Integer} \section{Introduction to Functions} \label{ugUserIntro} Each name in your workspace can refer to a single object. This may be any kind of object including a function. You can use interactively any function from the library or any that you define in the workspace. In the library the same name can have very many functions, but you can have only one function with a given name, although it can have any number of arguments that you choose. If you define a function in the workspace that has the same name and number of arguments as one in the library, then your definition takes precedence. In fact, to get the library function you must {\sl package-call} it (see section \ref{ugTypesPkgCall} on page~\pageref{ugTypesPkgCall}). To use a function in Axiom, you apply it to its arguments. Most functions are applied by entering the name of the function followed by its argument or arguments. \spadcommand{factor(12)} $$ {2 \sp 2} \ 3 $$ \returnType{Type: Factored Integer} Some functions like ``{\tt +}'' have {\it infix} {\it operators} as names. \spadcommand{3 + 4} $$ 7 $$ \returnType{Type: PositiveInteger} The function ``{\tt +}'' has two arguments. When you give it more than two arguments, Axiom groups the arguments to the left. This expression is equivalent to $(1 + 2) + 7$. \spadcommand{1 + 2 + 7} $$ 10 $$ \returnType{Type: PositiveInteger} All operations, including infix operators, can be written in prefix form, that is, with the operation name followed by the arguments in parentheses. For example, $2 + 3$ can alternatively be written as $+(2,3)$. But $+(2,3,4)$ is an error since {\tt +} takes only two arguments. Prefix operations are generally applied before the infix operation. Thus the form ${\bf factorial\ } 3 + 1$ means ${\bf factorial}(3) + 1$ producing $7$, and $-2 + 5$ means $(-2) + 5$ producing $3$. An example of a prefix operator is prefix ``{\tt -}''. For example, $- 2 + 5$ converts to $(- 2) + 5$ producing the value $3$. Any prefix function taking two arguments can be written in an infix manner by putting an ampersand ``{\tt \&}'' before the name. Thus ${\tt D}(2*x,x)$ can be written as $2*x\ {\tt \&D} x$ returning $2$. Every function in Axiom is identified by a {\it name} and {\it type}. (An exception is an ``anonymous function'' discussed in \ref{ugUserAnon} on page~\pageref{ugUserAnon}.) The type of a function is always a mapping of the form \spadsig{Source}{Target} where {\tt Source} and {\tt Target} are types. To enter a type from the keyboard, enter the arrow by using a hyphen ``{\tt -}'' followed by a greater-than sign ``{\tt >}'', e.g. {\tt Integer -> Integer}. Let's go back to ``{\tt +}''. There are many ``{\tt +}'' functions in the Axiom library: one for integers, one for floats, another for rational numbers, and so on. These ``{\tt +}'' functions have different types and thus are different functions. You've seen examples of this {\it overloading} before---using the same name for different functions. Overloading is the rule rather than the exception. You can add two integers, two polynomials, two matrices or two power series. These are all done with the same function name but with different functions. \section{Declaring the Type of Functions} \label{ugUserDeclare} In \ref{ugTypesDeclare} on page~\pageref{ugTypesDeclare} we discussed how to declare a variable to restrict the kind of values that can be assigned to it. In this section we show how to declare a variable that refers to function objects. \boxed{4.6in}{ \vskip 0.1cm A function is an object of type \begin{center} {\sf Source $\rightarrow$ Type} \end{center} where {\tt Source} and {\tt Target} can be any type. A common type for {\tt Source} is {\tt Tuple}($\hbox{\it T}_{1}$, \ldots, $\hbox{\it T}_{n}$), usually written ($\hbox{\it T}_{1}$, \ldots, $\hbox{\it T}_{n}$), to indicate a function of $n$ arguments.\\ } If $g$ takes an {\tt Integer}, a {\tt Float} and another {\tt Integer}, and returns a {\tt String}, the declaration is written: \spadcommand{g: (Integer,Float,Integer) -> String} \returnType{Type: Void} The types need not be written fully; using abbreviations, the above declaration is: \spadcommand{g: (INT,FLOAT,INT) -> STRING} \returnType{Type: Void} It is possible for a function to take no arguments. If $ h$ takes no arguments but returns a {\tt Polynomial} {\tt Integer}, any of the following declarations is acceptable. \spadcommand{h: () -> POLY INT} \returnType{Type: Void} \spadcommand{h: () -> Polynomial INT} \returnType{Type: Void} \spadcommand{h: () -> POLY Integer} \returnType{Type: Void} \boxed{4.6in}{ \vskip 0.1cm Functions can also be declared when they are being defined. The syntax for combined declaration/definition is: \begin{center} \frenchspacing{\tt {\it functionName}($\hbox{\it parm}_{1}$: $\hbox{\it parmType}_{1}$, \ldots, $\hbox{\it parm}_{N}$: $\hbox{\it parmType}_{N}$): {\it functionReturnType}} \end{center} {\ }%force a blank line } The following definition fragments show how this can be done for the functions $g$ and $h$ above. \begin{verbatim} g(arg1: INT, arg2: FLOAT, arg3: INT): STRING == ... h(): POLY INT == ... \end{verbatim} A current restriction on function declarations is that they must involve fully specified types (that is, cannot include modes involving explicit or implicit ``{\tt ?}''). For more information on declaring things in general, see \ref{ugTypesDeclare} on page~\pageref{ugTypesDeclare}. \section{One-Line Functions} \label{ugUserOne} As you use Axiom, you will find that you will write many short functions \index{function!one-line definition} to codify sequences of operations that you often perform. In this section we write some simple one-line functions. This is a simple recursive factorial function for positive integers. \spadcommand{fac n == if n < 3 then n else n * fac(n-1)} \returnType{Type: Void} \spadcommand{fac 10} $$ 3628800 $$ \returnType{Type: PositiveInteger} This function computes $1 + 1/2 + 1/3 + ... + 1/n$. \spadcommand{s n == reduce(+,[1/i for i in 1..n])} \returnType{Type: Void} \spadcommand{s 50} $$ {13943237577224054960759} \over {3099044504245996706400} $$ \returnType{Type: Fraction Integer} This function computes a Mersenne number, several of which are prime. \index{Mersenne number} \spadcommand{mersenne i == 2**i - 1} \returnType{Type: Void} If you type {\tt mersenne}, Axiom shows you the function definition. \spadcommand{mersenne} $$ mersenne \ i \ == \ {{2 \sp i} -1} $$ \returnType{Type: FunctionCalled mersenne} Generate a stream of Mersenne numbers. \spadcommand{[mersenne i for i in 1..]} $$ \left[ 1, 3, 7, {15}, {31}, {63}, {127}, {255}, {511}, {1023}, \ldots \right] $$ \returnType{Type: Stream Integer} Create a stream of those values of $i$ such that {\tt mersenne(i)} is prime. \spadcommand{mersenneIndex := [n for n in 1.. | prime?(mersenne(n))]} \begin{verbatim} Compiling function mersenne with type PositiveInteger -> Integer \end{verbatim} $$ \left[ 2, 3, 5, 7, {13}, {17}, {19}, {31}, {61}, {89}, \ldots \right] $$ \returnType{Type: Stream PositiveInteger} Finally, write a function that returns the $n$-th Mersenne prime. \spadcommand{mersennePrime n == mersenne mersenneIndex(n)} \returnType{Type: Void} \spadcommand{mersennePrime 5} $$ 8191 $$ \returnType{Type: PositiveInteger} \section{Declared vs. Undeclared Functions} \label{ugUserDecUndec} If you declare the type of a function, you can apply it to any data that can be converted to the source type of the function. Define {\bf f} with type {\sf Integer $\rightarrow$ Integer}. \spadcommand{f(x: Integer): Integer == x + 1} \begin{verbatim} Function declaration f : Integer -> Integer has been added to workspace. \end{verbatim} \returnType{Type: Void} The function {\bf f} can be applied to integers, \ldots \spadcommand{f 9} \begin{verbatim} Compiling function f with type Integer -> Integer \end{verbatim} $$ 10 $$ \returnType{Type: PositiveInteger} and to values that convert to integers, \ldots \spadcommand{f(-2.0)} $$ -1 $$ \returnType{Type: Integer} but not to values that cannot be converted to integers. \spadcommand{f(2/3)} \begin{verbatim} Conversion failed in the compiled user function f . Cannot convert from type Fraction Integer to Integer for value 2 - 3 \end{verbatim} To make the function over a wide range of types, do not declare its type. Give the same definition with no declaration. \spadcommand{g x == x + 1} \returnType{Type: Void} If $x + 1$ makes sense, you can apply {\bf g} to $x$. \spadcommand{g 9} \begin{verbatim} Compiling function g with type PositiveInteger -> PositiveInteger \end{verbatim} $$ 10 $$ \returnType{Type: PositiveInteger} A version of {\bf g} with different argument types get compiled for each new kind of argument used. \spadcommand{g(2/3)} \begin{verbatim} Compiling function g with type Fraction Integer -> Fraction Integer \end{verbatim} $$ 5 \over 3 $$ \returnType{Type: Fraction Integer} Here $x+1$ for $x = "axiom"$ makes no sense. \spadcommand{g("axiom")} \begin{verbatim} There are 11 exposed and 5 unexposed library operations named + having 2 argument(s) but none was determined to be applicable. Use HyperDoc Browse, or issue )display op + to learn more about the available operations. Perhaps package-calling the operation or using coercions on the arguments will allow you to apply the operation. Cannot find a definition or applicable library operation named + with argument type(s) String PositiveInteger Perhaps you should use "@" to indicate the required return type, or "$" to specify which version of the function you need. AXIOM will attempt to step through and interpret the code. There are 11 exposed and 5 unexposed library operations named + having 2 argument(s) but none was determined to be applicable. Use HyperDoc Browse, or issue )display op + to learn more about the available operations. Perhaps package-calling the operation or using coercions on the arguments will allow you to apply the operation. Cannot find a definition or applicable library operation named + with argument type(s) String PositiveInteger Perhaps you should use "@" to indicate the required return type, or "$" to specify which version of the function you need. \end{verbatim} As you will see in Chapter \ref{ugCategories} on page~\pageref{ugCategories}, Axiom has a formal idea of categories for what ``makes sense.'' \section{Functions vs. Operations} \label{ugUserDecOpers} A function is an object that you can create, manipulate, pass to, and return from functions (for some interesting examples of library functions that manipulate functions, see \ref{MappingPackage1XmpPage} on page~\pageref{MappingPackage1XmpPage}). Yet, we often seem to use the term {\it operation} and {\it function} interchangeably in Axiom. What is the distinction? First consider values and types associated with some variable $n$ in your workspace. You can make the declaration {\tt n : Integer}, then assign $n$ an integer value. You then speak of the integer $n$. However, note that the integer is not the name $n$ itself, but the value that you assign to $n$. Similarly, you can declare a variable $f$ in your workspace to have type {\sf Integer $\rightarrow$ Integer}, then assign $f$, through a definition or an assignment of an anonymous function. You then speak of the function $f$. However, the function is not $f$, but the value that you assign to $f$. A function is a value, in fact, some machine code for doing something. Doing what? Well, performing some {\it operation}. Formally, an operation consists of the constituent parts of $f$ in your workspace, excluding the value; thus an operation has a name and a type. An operation is what domains and packages export. Thus {\tt Ring} exports one operation ``{\tt +}''. Every ring also exports this operation. Also, the author of every ring in the system is obliged under contract (see \ref{ugPackagesAbstract} on page~\pageref{ugPackagesAbstract}) to provide an implementation for this operation. This chapter is all about functions---how you create them interactively and how you apply them to meet your needs. In Chapter \ref{ugPackages} on page~\pageref{ugPackages} you will learn how to create them for the Axiom library. Then in Chapter \ref{ugCategories} on page~\pageref{ugCategories}, you will learn about categories and exported operations. \section{Delayed Assignments vs. Functions with No Arguments} \label{ugUserDelay} In \ref{ugLangAssign} on page~\pageref{ugLangAssign} we discussed the difference between immediate and \index{function!with no arguments} delayed assignments. In this section we show the difference between delayed assignments and functions of no arguments. A function of no arguments is sometimes called a {\it nullary function.} \spadcommand{sin24() == sin(24.0)} \returnType{Type: Void} You must use the parentheses ``{\tt ()}'' to evaluate it. Like a delayed assignment, the right-hand-side of a function evaluation is not evaluated until the left-hand-side is used. \spadcommand{sin24()} \begin{verbatim} Compiling function sin24 with type () -> Float \end{verbatim} $$ -{0.9055783620\ 0662384514} $$ \returnType{Type: Float} If you omit the parentheses, you just get the function definition. \spadcommand{sin24} $$ sin24 \ {\left( \right)} \ == \ {\sin \left( {{24.0}} \right)} $$ \returnType{Type: FunctionCalled sin24} You do not use the parentheses ``{\tt ()}'' in a delayed assignment\ldots \spadcommand{cos24 == cos(24.0)} \returnType{Type: Void} nor in the evaluation. \spadcommand{cos24} \begin{verbatim} Compiling body of rule cos24 to compute value of type Float \end{verbatim} $$ 0.4241790073\ 3699697594 $$ \returnType{Type: Float} The only syntactic difference between delayed assignments and nullary functions is that you use ``{\tt ()}'' in the latter case. \section{How Axiom Determines What Function to Use} \label{ugUserUse} What happens if you define a function that has the same name as a library function? Well, if your function has the same name and number of arguments (we sometimes say {\it arity}) as another function in the library, then your function covers up the library function. If you want then to call the library function, you will have to {\sl package-call} it. Axiom can use both the functions you write and those that come from the library. Let's do a simple example to illustrate this. Suppose you (wrongly!) define {\bf sin} in this way. \spadcommand{sin x == 1.0} \returnType{Type: Void} The value $1.0$ is returned for any argument. \spadcommand{sin 4.3} \begin{verbatim} Compiling function sin with type Float -> Float \end{verbatim} $$ 1.0 $$ \returnType{Type: Float} If you want the library operation, we have to package-call it (see \ref{ugTypesPkgCall} on page~\pageref{ugTypesPkgCall} for more information). \spadcommand{sin(4.3)\$Float} $$ -{0.9161659367 4945498404} $$ \returnType{Type: Float} \spadcommand{sin(34.6)\$Float} $$ -{0.0424680347 1695010154 3} $$ \returnType{Type: Float} Even worse, say we accidentally used the same name as a library function in the function. \spadcommand{sin x == sin x} \begin{verbatim} Compiled code for sin has been cleared. 1 old definition(s) deleted for function or rule sin \end{verbatim} \returnType{Type: Void} Then Axiom definitely does not understand us. \spadcommand{sin 4.3} \begin{verbatim} AXIOM cannot determine the type of sin because it cannot analyze the non-recursive part, if that exists. This may be remedied by declaring the function. \end{verbatim} Again, we could package-call the inside function. \spadcommand{sin x == sin(x)\$Float} \begin{verbatim} 1 old definition(s) deleted for function or rule sin \end{verbatim} \returnType{Type: Void} \spadcommand{sin 4.3} \begin{verbatim} Compiling function sin with type Float -> Float +++ |*1;sin;1;G82322| redefined \end{verbatim} $$ -{0.9161659367 4945498404} $$ \returnType{Type: Float} Of course, you are unlikely to make such obvious errors. It is more probable that you would write a function and in the body use a function that you think is a library function. If you had also written a function by that same name, the library function would be invisible. How does Axiom determine what library function to call? It very much depends on the particular example, but the simple case of creating the polynomial $x + 2/3$ will give you an idea. \begin{enumerate} \item The $x$ is analyzed and its default type is {\tt Variable(x)}. \item The $2$ is analyzed and its default type is {\tt PositiveInteger}. \item The $3$ is analyzed and its default type is {\tt PositiveInteger}. \item Because the arguments to ``{\tt /}'' are integers, Axiom gives the expression $2/3$ a default target type of {\tt Fraction(Integer)}. \item Axiom looks in {\tt PositiveInteger} for ``{\tt /}''. It is not found. \item Axiom looks in {\tt Fraction(Integer)} for ``{\tt /}''. It is found for arguments of type {\tt Integer}. \item The $2$ and $3$ are converted to objects of type {\tt Integer} (this is trivial) and ``{\tt /}'' is applied, creating an object of type {\tt Fraction(Integer)}. \item No ``{\tt +}'' for arguments of types {\tt Variable(x)} and {\tt Fraction(Integer)} are found in either domain. \item Axiom resolves \index{resolve} (see \ref{ugTypesResolve} on page~\pageref{ugTypesResolve}) the types and gets {\tt Polynomial (Fraction (Integer))}. \item The $x$ and the $2/3$ are converted to objects of this type and {\tt +} is applied, yielding the answer, an object of type {\tt Polynomial (Fraction (Integer))}. \end{enumerate} \section{Compiling vs. Interpreting} \label{ugUserCompInt} When possible, Axiom completely determines the type of every object in a function, then translates the function definition to Common Lisp or to machine code (see the next section). This translation, \index{function!compiler} called compilation, happens the first time you call the function and results in a computational delay. Subsequent function calls with the same argument types use the compiled version of the code without delay. If Axiom cannot determine the type of everything, the function may still be executed \index{function!interpretation} but \index{interpret-code mode} in interpret-code mode: each statement in the function is analyzed and executed as the control flow indicates. This process is slower than executing a compiled function, but it allows the execution of code that may involve objects whose types change. \boxed{4.6in}{ \vskip 0.1cm If Axiom decides that it cannot compile the code, it issues a message stating the problem and then the following message: \begin{center} {\bf We will attempt to step through and interpret the code.} \end{center} This is not a time to panic. \index{panic!avoiding} Rather, it just means that what you gave to Axiom is somehow ambiguous: either it is not specific enough to be analyzed completely, or it is beyond Axiom's present interactive compilation abilities.\\ } This function runs in interpret-code mode, but it does not compile. \begin{verbatim} varPolys(vars) == for var in vars repeat output(1 :: UnivariatePolynomial(var,Integer)) \end{verbatim} \returnType{Type: Void} For $vars$ equal to $['x, 'y, 'z]$, this function displays $1$ three times. \spadcommand{varPolys ['x,'y,'z]} \begin{verbatim} Cannot compile conversion for types involving local variables. In particular, could not compile the expression involving :: UnivariatePolynomial(var,Integer) AXIOM will attempt to step through and interpret the code. 1 1 1 \end{verbatim} \returnType{Type: Void} The type of the argument to {\bf output} changes in each iteration, so Axiom cannot compile the function. In this case, even the inner loop by itself would have a problem: \begin{verbatim} for var in ['x,'y,'z] repeat output(1 :: UnivariatePolynomial(var,Integer)) \end{verbatim} \begin{verbatim} Cannot compile conversion for types involving local variables. In particular, could not compile the expression involving :: UnivariatePolynomial(var,Integer) AXIOM will attempt to step through and interpret the code. 1 1 1 \end{verbatim} \returnType{Type: Void} Sometimes you can help a function to compile by using an extra conversion or by using $pretend$. \index{pretend} See \ref{ugTypesSubdomains} on page~\pageref{ugTypesSubdomains} for details. When a function is compilable, you have the choice of whether it is compiled to Common Lisp and then interpreted by the Common Lisp interpreter or then further compiled from Common Lisp to machine code. \index{machine code} The option is controlled via {\tt )set functions compile}. \index{set function compile} Issue {\tt )set functions compile on} to compile all the way to machine code. With the default setting {\tt )set functions compile off}, Axiom has its Common Lisp code interpreted because the overhead of further compilation is larger than the run-time of most of the functions our users have defined. You may find that selectively turning this option on and off will \index{performance} give you the best performance in your particular application. For example, if you are writing functions for graphics applications where hundreds of points are being computed, it is almost certainly true that you will get the best performance by issuing {\tt )set functions compile on}. \section{Piece-Wise Function Definitions} \label{ugUserPiece} To move beyond functions defined in one line, we introduce in this section functions that are defined piece-by-piece. That is, we say ``use this definition when the argument is such-and-such and use this other definition when the argument is that-and-that.'' \subsection{A Basic Example} \label{ugUserPieceBasic} There are many other ways to define a factorial function for nonnegative integers. You might \index{function!piece-wise definition} say \index{piece-wise function definition} factorial of $0$ is $1$, otherwise factorial of $n$ is $n$ times factorial of $n-1$. Here is one way to do this in Axiom. Here is the value for $n = 0$. \spadcommand{fact(0) == 1} \returnType{Type: Void} Here is the value for $n > 0$. The vertical bar ``{\tt |}'' means ``such that''. \index{such that} \spadcommand{fact(n | n > 0) == n * fact(n - 1)} \returnType{Type: Void} What is the value for $n = 3$? \spadcommand{fact(3)} \begin{verbatim} Compiling function fact with type Integer -> Integer Compiling function fact as a recurrence relation. \end{verbatim} $$ 6 $$ \returnType{Type: PositiveInteger} What is the value for $n = -3$? \spadcommand{fact(-3)} \begin{verbatim} You did not define fact for argument -3 . \end{verbatim} Now for a second definition. Here is the value for $n = 0$. \spadcommand{facto(0) == 1} \returnType{Type: Void} Give an error message if $n < 0$. \spadcommand{facto(n | n < 0) == error "arguments to facto must be non-negative"} \returnType{Type: Void} Here is the value otherwise. \spadcommand{facto(n) == n * facto(n - 1)} \returnType{Type: Void} What is the value for $n = 7$? \spadcommand{facto(3)} \begin{verbatim} Compiling function facto with type Integer -> Integer \end{verbatim} $$ 6 $$ \returnType{Type: PositiveInteger} What is the value for $n = -7$? \spadcommand{facto(-7)} \begin{verbatim} Error signalled from user code in function facto: arguments to facto must be non-negative \end{verbatim} \returnType{Type: PositiveInteger} To see the current piece-wise definition of a function, use {\tt )display value}. \spadcommand{)display value facto} \begin{verbatim} Definition: facto 0 == 1 facto (n | n < 0) == error(arguments to facto must be non-negative) facto n == n facto(n - 1) \end{verbatim} In general a {\it piece-wise definition} of a function consists of two or more parts. Each part gives a ``piece'' of the entire definition. Axiom collects the pieces of a function as you enter them. When you ask for a value of the function, it then ``glues'' the pieces together to form a function. The two piece-wise definitions for the factorial function are examples of recursive functions, that is, functions that are defined in terms of themselves. Here is an interesting doubly-recursive function. This function returns the value $11$ for all positive integer arguments. Here is the first of two pieces. \spadcommand{eleven(n | n < 1) == n + 11} \returnType{Type: Void} And the general case. \spadcommand{eleven(m) == eleven(eleven(m - 12))} \returnType{Type: Void} Compute $elevens$, the infinite stream of values of $eleven$. \spadcommand{elevens := [eleven(i) for i in 0..]} $$ \left[ {11}, {11}, {11}, {11}, {11}, {11}, {11}, {11}, {11}, {11}, \ldots \right] $$ \returnType{Type: Stream Integer} What is the value at $n = 200$? \spadcommand{elevens 200} $$ 11 $$ \returnType{Type: PositiveInteger} What is the Axiom's definition of $eleven$? \spadcommand{)display value eleven} \begin{verbatim} Definition: eleven (m | m < 1) == m + 11 eleven m == eleven(eleven(m - 12)) \end{verbatim} \subsection{Picking Up the Pieces} \label{ugUserPiecePicking} Here are the details about how Axiom creates a function from its pieces. Axiom converts the $i$-th piece of a function definition into a conditional expression of the form: {\tt if} $\hbox{\it pred}_{i}$ {\tt then} $\hbox{\it expression}_{i}$. If any new piece has a $\hbox{\it pred}_{i}$ that is identical (after all variables are uniformly named) to an earlier $\hbox{\it pred}_{j}$, the earlier piece is removed. Otherwise, the new piece is always added at the end. \boxed{4.6in}{ \vskip 0.1cm If there are $n$ pieces to a function definition for $f$, the function defined $f$ is: \newline \hspace*{3pc} {\tt if} $\hbox{\it pred}_{1}$ {\tt then} $\hbox{\it expression}_{1}$ {\tt else}\newline \hspace*{6pc}. . . \newline \hspace*{3pc} {\tt if} $\hbox{\it pred}_{n}$ {\tt then} $\hbox{\it expression}_{n}$ {\tt else}\newline \hspace*{3pc} {\tt error "You did not define f for argument ."}\\ } You can give definitions of any number of mutually recursive function definitions, piece-wise or otherwise. No computation is done until you ask for a value. When you do ask for a value, all the relevant definitions are gathered, analyzed, and translated into separate functions and compiled. Let's recall the definition of {\bf eleven} from the previous section. \spadcommand{eleven(n | n < 1) == n + 11} \returnType{Type: Void} \spadcommand{eleven(m) == eleven(eleven(m - 12))} \returnType{Type: Void} A similar doubly-recursive function below produces $-11$ for all negative positive integers. If you haven't worked out why or how {\bf eleven} works, the structure of this definition gives a clue. This definition we write as a block. \begin{verbatim} minusEleven(n) == n >= 0 => n - 11 minusEleven (5 + minusEleven(n + 7)) \end{verbatim} \returnType{Type: Void} Define $s(n)$ to be the sum of plus and minus ``eleven'' functions divided by $n$. Since $11 - 11 = 0$, we define $s(0)$ to be $1$. \spadcommand{s(0) == 1} \returnType{Type: Void} And the general term. \spadcommand{s(n) == (eleven(n) + minusEleven(n))/n} \returnType{Type: Void} What are the first ten values of $s$? \spadcommand{[s(n) for n in 0..]} $$ \left[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ldots \right] $$ \returnType{Type: Stream Fraction Integer} %% interpreter puts the rule at the end - should fix % Oops! Evidently $s(0)$ should be $1$. % Let's check the current definition of {\bf s} using {\tt )display}. % \spadcommand{)display value s} % Change the value at $n = 0$. % \spadcommand{s(0) == 1} % Now, what is the definition of {\bf s}? % Note: {\it you can only replace a given piece if you give exactly the same % predicate!} % \spadcommand{)display value s} Axiom can create infinite streams in the positive direction (for example, for index values $0,1, \ldots$) or negative direction (for example, for $0,-1,-2, \ldots$). Here we would like a stream of values of $s(n)$ that is infinite in both directions. The function $t(n)$ below returns the $n$-th term of the infinite stream $$[s(0), s(1), s(-1), s(2), s(-2), \ldots]$$ Its definition has three pieces. Define the initial term. \spadcommand{t(1) == s(0)} \returnType{Type: Void} The even numbered terms are the $s(i)$ for positive $i$. We use ``{\tt quo}'' rather than ``{\tt /}'' since we want the result to be an integer. \spadcommand{t(n | even?(n)) == s(n quo 2)} \returnType{Type: Void} Finally, the odd numbered terms are the $s(i)$ for negative $i$. In piece-wise definitions, you can use different variables to define different pieces. Axiom will not get confused. \spadcommand{t(p) == s(- p quo 2)} \returnType{Type: Void} Look at the definition of $t$. In the first piece, the variable $n$ was used; in the second piece, $p$. Axiom always uses your last variable to display your definitions back to you. \spadcommand{)display value t} \begin{verbatim} Definition: t 1 == s(0) t (p | even?(p)) == s(p quo 2) t p == s(- p quo 2) \end{verbatim} Create a series of values of $s$ applied to alternating positive and negative arguments. \spadcommand{[t(i) for i in 1..]} \begin{verbatim} Compiling function s with type Integer -> Fraction Integer Compiling function t with type PositiveInteger -> Fraction Integer \end{verbatim} $$ \left[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ldots \right] $$ \returnType{Type: Stream Fraction Integer} Evidently $t(n) = 1$ for all $i$. Check it at $n= 100$. \spadcommand{t(100)} $$ 1 $$ \returnType{Type: Fraction Integer} \subsection{Predicates} \label{ugUserPiecePred} We have already seen some examples of \index{function!predicate} predicates \index{predicate!in function definition} (\ref{ugUserPieceBasic} on page~\pageref{ugUserPieceBasic}). Predicates are {\tt Boolean}-valued expressions and Axiom uses them for filtering collections (see \ref{ugLangIts} on page~\pageref{ugLangIts}) and for placing constraints on function arguments. In this section we discuss their latter usage. The simplest use of a predicate is one you don't see at all. \spadcommand{opposite 'right == 'left} \returnType{Type: Void} Here is a longer way to give the ``opposite definition.'' \spadcommand{opposite (x | x = 'left) == 'right} \returnType{Type: Void} Try it out. \spadcommand{for x in ['right,'left,'inbetween] repeat output opposite x} \begin{verbatim} Compiling function opposite with type OrderedVariableList [right, left,inbetween] -> Symbol left right The function opposite is not defined for the given argument(s). \end{verbatim} Explicit predicates tell Axiom that the given function definition piece is to be applied if the predicate evaluates to {\tt true} for the arguments to the function. You can use such ``constant'' arguments for integers, \index{function!constant argument} strings, and quoted symbols. \index{constant function argument} The {\tt Boolean} values {\tt true} and {\tt false} can also be used if qualified with ``$@$'' or ``$\$$'' and {\tt Boolean}. The following are all valid function definition fragments using constant arguments. \begin{verbatim} a(1) == ... b("unramified") == ... c('untested) == ... d(true@Boolean) == ... \end{verbatim} If a function has more than one argument, each argument can have its own predicate. However, if a predicate involves two or more arguments, it must be given {\it after} all the arguments mentioned in the predicate have been given. You are always safe to give a single predicate at the end of the argument list. A function involving predicates on two arguments. \spadcommand{inFirstHalfQuadrant(x | x > 0,y | y < x) == true} \returnType{Type: Void} This is incorrect as it gives a predicate on $y$ before the argument $y$ is given. \spadcommand{inFirstHalfQuadrant(x | x > 0 and y < x,y) == true} \begin{verbatim} 1 old definition(s) deleted for function or rule inFirstHalfQuadrant \end{verbatim} \returnType{Type: Void} It is always correct to write the predicate at the end. \spadcommand{inFirstHalfQuadrant(x,y | x > 0 and y < x) == true} \begin{verbatim} 1 old definition(s) deleted for function or rule inFirstHalfQuadrant \end{verbatim} \returnType{Type: Void} Here is the rest of the definition. \spadcommand{inFirstHalfQuadrant(x,y) == false} \returnType{Type: Void} Try it out. \spadcommand{[inFirstHalfQuadrant(i,3) for i in 1..5]} \begin{verbatim} Compiling function inFirstHalfQuadrant with type (PositiveInteger, PositiveInteger) -> Boolean \end{verbatim} $$ \left[ {\tt false}, {\tt false}, {\tt false}, {\tt true}, {\tt true} \right] $$ \returnType{Type: List Boolean} \section{Caching Previously Computed Results} \label{ugUserCache} By default, Axiom does not save the values of any function. \index{function!caching values} You can cause it to save values and not to recompute unnecessarily \index{remembering function values} by using {\tt )set functions cache}. \index{set functions cache} This should be used before the functions are defined or, at least, before they are executed. The word following ``cache'' should be $0$ to turn off caching, a positive integer $n$ to save the last $n$ computed values or ``all'' to save all computed values. If you then give a list of names of functions, the caching only affects those functions. Use no list of names or ``all'' when you want to define the default behavior for functions not specifically mentioned in other {\tt )set functions cache} statements. If you give no list of names, all functions will have the caching behavior. If you explicitly turn on caching for one or more names, you must explicitly turn off caching for those names when you want to stop saving their values. This causes the functions {\bf f} and {\bf g} to have the last three computed values saved. \spadcommand{)set functions cache 3 f g} \begin{verbatim} function f will cache the last 3 values. function g will cache the last 3 values. \end{verbatim} This is a sample definition for {\bf f}. \spadcommand{f x == factorial(2**x)} \returnType{Type: Void} A message is displayed stating what {\bf f} will cache. \spadcommand{f(4)} \begin{verbatim} Compiling function f with type PositiveInteger -> Integer f will cache 3 most recently computed value(s). +++ |*1;f;1;G82322| redefined \end{verbatim} $$ 20922789888000 $$ \returnType{Type: PositiveInteger} This causes all other functions to have all computed values saved by default. \spadcommand{)set functions cache all} \begin{verbatim} In general, interpreter functions will cache all values. \end{verbatim} This causes all functions that have not been specifically cached in some way to have no computed values saved. \spadcommand{)set functions cache 0} \begin{verbatim} In general, functions will cache no returned values. \end{verbatim} We also make {\bf f} and {\bf g} uncached. \spadcommand{)set functions cache 0 f g} \begin{verbatim} Caching for function f is turned off Caching for function g is turned off \end{verbatim} \boxed{4.6in}{ \vskip 0.1cm Be careful about caching functions that have side effects. Such a function might destructively modify the elements of an array or issue a {\bf draw} command, for example. A function that you expect to execute every time it is called should not be cached. Also, it is highly unlikely that a function with no arguments should be cached.\\ } You should also be careful about caching functions that depend on free variables. See \ref{ugUserFreeLocal} on page~\pageref{ugUserFreeLocal} for an example. \section{Recurrence Relations} \label{ugUserRecur} One of the most useful classes of function are those defined via a ``recurrence relation.'' A {\it recurrence relation} makes each successive \index{recurrence relation} value depend on some or all of the previous values. A simple example is the ordinary ``factorial'' function: \begin{verbatim} fact(0) == 1 fact(n | n > 0) == n * fact(n-1) \end{verbatim} The value of $fact(10)$ depends on the value of $fact(9)$, $fact(9)$ on $fact(8)$, and so on. Because it depends on only one previous value, it is usually called a {\it first order recurrence relation.} You can easily imagine a function based on two, three or more previous values. The Fibonacci numbers are probably the most famous function defined by a \index{Fibonacci numbers} second order recurrence relation. The library function {\bf fibonacci} computes Fibonacci numbers. It is obviously optimized for speed. \spadcommand{[fibonacci(i) for i in 0..]} $$ \left[ 0, 1, 1, 2, 3, 5, 8, {13}, {21}, {34}, \ldots \right] $$ \returnType{Type: Stream Integer} Define the Fibonacci numbers ourselves using a piece-wise definition. \spadcommand{fib(1) == 1} \returnType{Type: Void} \spadcommand{fib(2) == 1} \returnType{Type: Void} \spadcommand{fib(n) == fib(n-1) + fib(n-2)} \returnType{Type: Void} As defined, this recurrence relation is obviously doubly-recursive. To compute $fib(10)$, we need to compute $fib(9)$ and $fib(8)$. And to $fib(9)$, we need to compute $fib(8)$ and $fib(7)$. And so on. It seems that to compute $fib(10)$ we need to compute $fib(9)$ once, $fib(8)$ twice, $fib(7)$ three times. Look familiar? The number of function calls needed to compute {\it any} second order recurrence relation in the obvious way is exactly $fib(n)$. These numbers grow! For example, if Axiom actually did this, then $fib(500)$ requires more than $10^{104}$ function calls. And, given all this, our definition of {\bf fib} obviously could not be used to calculate the five-hundredth Fibonacci number. Let's try it anyway. \spadcommand{fib(500)} \begin{verbatim} Compiling function fib with type Integer -> PositiveInteger Compiling function fib as a recurrence relation. 13942322456169788013972438287040728395007025658769730726410_ 8962948325571622863290691557658876222521294125 \end{verbatim} \returnType{Type: PositiveInteger} Since this takes a short time to compute, it obviously didn't do as many as $10^{104}$ operations! By default, Axiom transforms any recurrence relation it recognizes into an iteration. Iterations are efficient. To compute the value of the $n$-th term of a recurrence relation using an iteration requires only $n$ function calls. Note that if you compare the speed of our {\bf fib} function to the library function, our version is still slower. This is because the library \spadfunFrom{fibonacci}{IntegerNumberTheoryFunctions} uses a ``powering algorithm'' with a computing time proportional to $\log^3(n)$ to compute {\tt fibonacci(n)}. To turn off this special recurrence relation compilation, issue \index{set function recurrence} \begin{verbatim} )set functions recurrence off \end{verbatim} To turn it back on, substitute ``{\tt on}'' for ``{\tt off}''. The transformations that Axiom uses for {\bf fib} caches the last two values. For a more general $k$-th order recurrence relation, Axiom caches the last $k$ values. If, after computing a value for {\bf fib}, you ask for some larger value, Axiom picks up the cached values and continues computing from there. See \ref{ugUserFreeLocal} on page~\pageref{ugUserFreeLocal} for an example of a function definition that has this same behavior. Also see \ref{ugUserCache} on page~\pageref{ugUserCache} for a more general discussion of how you can cache function values. Recurrence relations can be used for defining recurrence relations involving polynomials, rational functions, or anything you like. Here we compute the infinite stream of Legendre polynomials. The Legendre polynomial of degree $0.$ \spadcommand{p(0) == 1} \returnType{Type: Void} The Legendre polynomial of degree $1.$ \spadcommand{p(1) == x} \returnType{Type: Void} The Legendre polynomial of degree $n$. \spadcommand{p(n) == ((2*n-1)*x*p(n-1) - (n-1)*p(n-2))/n} \returnType{Type: Void} Compute the Legendre polynomial of degree $6.$ \spadcommand{p(6)} \begin{verbatim} Compiling function p with type Integer -> Polynomial Fraction Integer Compiling function p as a recurrence relation. \end{verbatim} $$ {{{231} \over {16}} \ {x \sp 6}} -{{{315} \over {16}} \ {x \sp 4}}+{{{105} \over {16}} \ {x \sp 2}} -{5 \over {16}} $$ \returnType{Type: Polynomial Fraction Integer} \section{Making Functions from Objects} \label{ugUserMake} There are many times when you compute a complicated expression and then wish to use that expression as the body of a function. Axiom provides an operation called {\bf function} to do \index{function!from an object} this. \index{function!made by function @{made by {\bf function}}} It creates a function object and places it into the workspace. There are several versions, depending on how many arguments the function has. The first argument to {\bf function} is always the expression to be converted into the function body, and the second is always the name to be used for the function. For more information, see section \ref{MakeFunctionXmpPage} on page~\pageref{MakeFunctionXmpPage}. Start with a simple example of a polynomial in three variables. \spadcommand{p := -x + y**2 - z**3} $$ -{z \sp 3}+{y \sp 2} -x $$ \returnType{Type: Polynomial Integer} To make this into a function of no arguments that simply returns the polynomial, use the two argument form of {\bf function}. \spadcommand{function(p,'f0)} $$ f0 $$ \returnType{Type: Symbol} To avoid possible conflicts (see below), it is a good idea to quote always this second argument. \spadcommand{f0} $$ f0 \ {\left( \right)} \ == \ {-{z \sp 3}+{y \sp 2} -x} $$ \returnType{Type: FunctionCalled f0} This is what you get when you evaluate the function. \spadcommand{f0()} $$ -{z \sp 3}+{y \sp 2} -x $$ \returnType{Type: Polynomial Integer} To make a function in $x$, use a version of {\bf function} that takes three arguments. The last argument is the name of the variable to use as the parameter. Typically, this variable occurs in the expression and, like the function name, you should quote it to avoid possible confusion. \spadcommand{function(p,'f1,'x)} $$ f1 $$ \returnType{Type: Symbol} This is what the new function looks like. \spadcommand{f1} $$ f1 \ x \ == \ {-{z \sp 3}+{y \sp 2} -x} $$ \returnType{Type: FunctionCalled f1} This is the value of {\bf f1} at $x = 3$. Notice that the return type of the function is {\tt Polynomial (Integer)}, the same as $p$. \spadcommand{f1(3)} \begin{verbatim} Compiling function f1 with type PositiveInteger -> Polynomial Integer \end{verbatim} $$ -{z \sp 3}+{y \sp 2} -3 $$ \returnType{Type: Polynomial Integer} To use $x$ and $y$ as parameters, use the four argument form of {\bf function}. \spadcommand{function(p,'f2,'x,'y)} $$ f2 $$ \returnType{Type: Symbol} \spadcommand{f2} $$ f2 \ {\left( x, y \right)} \ == \ {-{z \sp 3}+{y \sp 2} -x} $$ \returnType{Type: FunctionCalled f2} Evaluate $f2$ at $x = 3$ and $y = 0$. The return type of {\bf f2} is still {\tt Polynomial(Integer)} because the variable $z$ is still present and not one of the parameters. \spadcommand{f2(3,0)} $$ -{z \sp 3} -3 $$ \returnType{Type: Polynomial Integer} Finally, use all three variables as parameters. There is no five argument form of {\bf function}, so use the one with three arguments, the third argument being a list of the parameters. \spadcommand{function(p,'f3,['x,'y,'z])} $$ f3 $$ \returnType{Type: Symbol} Evaluate this using the same values for $x$ and $y$ as above, but let $z$ be $-6$. The result type of {\bf f3} is {\tt Integer}. \spadcommand{f3} $$ f3 \ {\left( x, y, z \right)} \ == \ {-{z \sp 3}+{y \sp 2} -x} $$ \returnType{Type: FunctionCalled f3} \spadcommand{f3(3,0,-6)} \begin{verbatim} Compiling function f3 with type (PositiveInteger,NonNegativeInteger, Integer) -> Integer \end{verbatim} $$ 213 $$ \returnType{Type: PositiveInteger} The four functions we have defined via $p$ have been undeclared. To declare a function whose body is to be generated by \index{function!declaring} {\bf function}, issue the declaration {\it before} the function is created. \spadcommand{g: (Integer, Integer) -> Float} \returnType{Type: Void} \spadcommand{D(sin(x-y)/cos(x+y),x)} $$ {-{{\sin \left( {{y -x}} \right)} \ {\sin \left( {{y+x}} \right)}}+{{\cos \left( {{y -x}} \right)} \ {\cos \left( {{y+x}} \right)}}} \over {{\cos \left( {{y+x}} \right)} \sp 2} $$ \returnType{Type: Expression Integer} \spadcommand{function(\%,'g,'x,'y)} $$ g $$ \returnType{Type: Symbol} \spadcommand{g} $$ g \ {\left( x, y \right)} \ == \ {{-{{\sin \left( {{y -x}} \right)} \ {\sin \left( {{y+x}} \right)}}+{{\cos \left( {{y -x}} \right)} \ {\cos \left( {{y+x}} \right)}}} \over {{\cos \left( {{y+x}} \right)} \sp 2}} $$ \returnType{Type: FunctionCalled g} It is an error to use $g$ without the quote in the penultimate expression since $g$ had been declared but did not have a value. Similarly, since it is common to overuse variable names like $x$, $y$, and so on, you avoid problems if you always quote the variable names for {\bf function}. In general, if $x$ has a value and you use $x$ without a quote in a call to {\bf function}, then Axiom does not know what you are trying to do. What kind of object is allowable as the first argument to {\bf function}? Let's use the Browse facility of HyperDoc to find out. \index{Browse@Browse} At the main Browse menu, enter the string {\tt function} and then click on {\bf Operations.} The exposed operations called {\bf function} all take an object whose type belongs to category {\tt ConvertibleTo InputForm}. What domains are those? Go back to the main Browse menu, erase {\tt function}, enter {\tt ConvertibleTo} in the input area, and click on {\bf categories} on the {\tt Constructors} line. At the bottom of the page, enter {\tt InputForm} in the input area following {\bf S =}. Click on {\tt Cross Reference} and then on {\tt Domains}. The list you see contains over forty domains that belong to the category {\tt ConvertibleTo InputForm}. Thus you can use {\bf function} for {\tt Integer}, {\tt Float}, {\tt String}, {\tt Complex}, {\tt Expression}, and so on. \section{Functions Defined with Blocks} \label{ugUserBlocks} You need not restrict yourself to functions that only fit on one line or are written in a piece-wise manner. The body of the function can be a block, as discussed in \ref{ugLangBlocks} on page~\pageref{ugLangBlocks}. Here is a short function that swaps two elements of a list, array or vector. \begin{verbatim} swap(m,i,j) == temp := m.i m.i := m.j m.j := temp \end{verbatim} \returnType{Type: Void} The significance of {\bf swap} is that it has a destructive effect on its first argument. \spadcommand{k := [1,2,3,4,5]} $$ \left[ 1, 2, 3, 4, 5 \right] $$ \returnType{Type: List PositiveInteger} \spadcommand{swap(k,2,4)} \begin{verbatim} Compiling function swap with type (List PositiveInteger, PositiveInteger,PositiveInteger) -> PositiveInteger \end{verbatim} $$ 2 $$ \returnType{Type: PositiveInteger} You see that the second and fourth elements are interchanged. \spadcommand{k} $$ \left[ 1, 4, 3, 2, 5 \right] $$ \returnType{Type: List PositiveInteger} Using this, we write a couple of different sort functions. First, a simple bubble sort. \index{sort!bubble} The operation \spadopFrom{\#}{List} returns the number of elements in an aggregate. \begin{verbatim} bubbleSort(m) == n := #m for i in 1..(n-1) repeat for j in n..(i+1) by -1 repeat if m.j < m.(j-1) then swap(m,j,j-1) m \end{verbatim} \returnType{Type: Void} Let this be the list we want to sort. \spadcommand{m := [8,4,-3,9]} $$ \left[ 8, 4, -3, 9 \right] $$ \returnType{Type: List Integer} This is the result of sorting. \spadcommand{bubbleSort(m)} \begin{verbatim} Compiling function swap with type (List Integer,Integer,Integer) -> Integer +++ |*3;swap;1;G82322| redefined Compiling function bubbleSort with type List Integer -> List Integer \end{verbatim} $$ \left[ -3, 4, 8, 9 \right] $$ \returnType{Type: List Integer} Moreover, $m$ is destructively changed to be the sorted version. \spadcommand{m} $$ \left[ -3, 4, 8, 9 \right] $$ \returnType{Type: List Integer} This function implements an insertion sort. \index{sort!insertion} The basic idea is to traverse the list and insert the $i$-th element in its correct position among the $i-1$ previous elements. Since we start at the beginning of the list, the list elements before the $i$-th element have already been placed in ascending order. \begin{verbatim} insertionSort(m) == for i in 2..#m repeat j := i while j > 1 and m.j < m.(j-1) repeat swap(m,j,j-1) j := j - 1 m \end{verbatim} \returnType{Type: Void} As with our bubble sort, this is a destructive function. \spadcommand{m := [8,4,-3,9]} $$ \left[ 8, 4, -3, 9 \right] $$ \returnType{Type: List Integer} \spadcommand{insertionSort(m)} \begin{verbatim} Compiling function insertionSort with type List Integer -> List Integer \end{verbatim} $$ \left[ -3, 4, 8, 9 \right] $$ \returnType{Type: List Integer} \spadcommand{m} $$ \left[ -3, 4, 8, 9 \right] $$ \returnType{Type: List Integer} Neither of the above functions is efficient for sorting large lists since they reference elements by asking for the $j$-th element of the structure $m$. Here is a more efficient bubble sort for lists. \begin{verbatim} bubbleSort2(m: List Integer): List Integer == null m => m l := m while not null (r := l.rest) repeat r := bubbleSort2 r x := l.first if x < r.first then l.first := r.first r.first := x l.rest := r l := l.rest m Function declaration bubbleSort2 : List Integer -> List Integer has been added to workspace. \end{verbatim} \returnType{Type: Void} Try it out. \spadcommand{bubbleSort2 [3,7,2]} $$ \left[ 7, 3, 2 \right] $$ \returnType{Type: List Integer} This definition is both recursive and iterative, and is tricky! Unless you are {\it really} curious about this definition, we suggest you skip immediately to the next section. Here are the key points in the definition. First notice that if you are sorting a list with less than two elements, there is nothing to do: just return the list. This definition returns immediately if there are zero elements, and skips the entire {\tt while} loop if there is just one element. The second point to realize is that on each outer iteration, the bubble sort ensures that the minimum element is propagated leftmost. Each iteration of the {\tt while} loop calls {\bf bubbleSort2} recursively to sort all but the first element. When finished, the minimum element is either in the first or second position. The conditional expression ensures that it comes first. If it is in the second, then a swap occurs. In any case, the {\bf rest} of the original list must be updated to hold the result of the recursive call. \section{Free and Local Variables} \label{ugUserFreeLocal} When you want to refer to a variable that is not local to your function, use a ``{\tt free}'' declaration. \index{free} Variables declared to be {\tt free} \index{free variable} are assumed to be defined globally \index{variable!free} in the \index{variable!global} workspace. \index{global variable} This is a global workspace variable. \spadcommand{counter := 0} $$ 0 $$ \returnType{Type: NonNegativeInteger} This function refers to the global $counter$. \begin{verbatim} f() == free counter counter := counter + 1 \end{verbatim} \returnType{Type: Void} The global $counter$ is incremented by $1$. \spadcommand{f()} \begin{verbatim} Compiling function f with type () -> NonNegativeInteger +++ |*0;f;1;G82322| redefined \end{verbatim} $$ 1 $$ \returnType{Type: PositiveInteger} \spadcommand{counter} $$ 1 $$ \returnType{Type: NonNegativeInteger} Usually Axiom can tell that you mean to refer to a global variable and so {\tt free} isn't always necessary. However, for clarity and the sake of self-documentation, we encourage you to use it. Declare a variable to be ``{\tt local}'' when you do not want to refer to \index{variable!local} a global variable by the same name. \index{local variable} This function uses $counter$ as a local variable. \begin{verbatim} g() == local counter counter := 7 \end{verbatim} \returnType{Type: Void} Apply the function. \spadcommand{g()} $$ 7 $$ \returnType{Type: PositiveInteger} Check that the global value of $counter$ is unchanged. \spadcommand{counter} $$ 1 $$ \returnType{Type: NonNegativeInteger} Parameters to a function are local variables in the function. Even if you issue a {\tt free} declaration for a parameter, it is still local. What happens if you do not declare that a variable $x$ in the body of your function is {\tt local} or {\tt free}? Well, Axiom decides on this basis: \begin{enumerate} \item Axiom scans your function line-by-line, from top-to-bottom. The right-hand side of an assignment is looked at before the left-hand side. \item If $x$ is referenced before it is assigned a value, it is a {\tt free} (global) variable. \item If $x$ is assigned a value before it is referenced, it is a {\tt local} variable. \end{enumerate} Set two global variables to 1. \spadcommand{a := b := 1} $$ 1 $$ \returnType{Type: PositiveInteger} Refer to $a$ before it is assigned a value, but assign a value to $b$ before it is referenced. \begin{verbatim} h() == b := a + 1 a := b + a \end{verbatim} \returnType{Type: Void} Can you predict this result? \spadcommand{h()} \begin{verbatim} Compiling function h with type () -> PositiveInteger +++ |*0;h;1;G82322| redefined \end{verbatim} $$ 3 $$ \returnType{Type: PositiveInteger} How about this one? \spadcommand{[a, b]} $$ \left[ 3, 1 \right] $$ \returnType{Type: List PositiveInteger} What happened? In the first line of the function body for $h$, $a$ is referenced on the right-hand side of the assignment. Thus $a$ is a free variable. The variable $b$ is not referenced in that line, but it is assigned a value. Thus $b$ is a local variable and is given the value $a + 1 = 2$. In the second line, the free variable $a$ is assigned the value $b + a$ which equals $2 + 1 = 3.$ This is the value returned by the function. Since $a$ was free in {\bf h}, the global variable $a$ has value $3.$ Since $b$ was local in {\bf h}, the global variable $b$ is unchanged---it still has the value $1$. It is good programming practice always to declare global variables. However, by far the most common situation is to have local variables in your functions. No declaration is needed for this situation, but be sure to initialize their values. Be careful if you use free variables and you cache the value of your function (see \ref{ugUserCache} on page~\pageref{ugUserCache}). Caching {\it only} checks if the values of the function arguments are the same as in a function call previously seen. It does not check if any of the free variables on which the function depends have changed between function calls. Turn on caching for {\bf p}. \spadcommand{)set fun cache all p} \begin{verbatim} function p will cache all values. \end{verbatim} Define {\bf p} to depend on the free variable $N$. \spadcommand{p(i,x) == ( free N; reduce( + , [ (x-i)**n for n in 1..N ] ) )} \returnType{Type: Void} Set the value of $N$. \spadcommand{N := 1} $$ 1 $$ \returnType{Type: PositiveInteger} Evaluate {\bf p} the first time. \spadcommand{p(0, x)} $$ x $$ \returnType{Type: Polynomial Integer} Change the value of $N$. \spadcommand{N := 2} $$ 2 $$ \returnType{Type: PositiveInteger} Evaluate {\bf p} the second time. \spadcommand{p(0, x)} $$ x $$ \returnType{Type: Polynomial Integer} If caching had been turned off, the second evaluation would have reflected the changed value of $N$. Turn off caching for {\bf p}. \spadcommand{)set fun cache 0 p} \begin{verbatim} Caching for function p is turned off \end{verbatim} Axiom does not allow {\it fluid variables}, that is, variables \index{variable!fluid} bound by a function $f$ that can be referenced by functions called by $f$. \index{fluid variable} Values are passed to functions by {\it reference}: a pointer to the value is passed rather than a copy of the value or a pointer to a copy. This is a global variable that is bound to a record object. \spadcommand{r : Record(i : Integer) := [1]} $$ \left[ {i=1} \right] $$ \returnType{Type: Record(i: Integer)} This function first modifies the one component of its record argument and then rebinds the parameter to another record. \begin{verbatim} resetRecord rr == rr.i := 2 rr := [10] \end{verbatim} \returnType{Type: Void} Pass $r$ as an argument to {\bf resetRecord}. \spadcommand{resetRecord r} $$ \left[ {i={10}} \right] $$ \returnType{Type: Record(i: Integer)} The value of $r$ was changed by the expression $rr.i := 2$ but not by $rr := [10]$. \spadcommand{r} $$ \left[ {i=2} \right] $$ \returnType{Type: Record(i: Integer)} To conclude this section, we give an iterative definition of \index{Fibonacci numbers} a function that computes Fibonacci numbers. This definition approximates the definition into which Axiom transforms the recurrence relation definition of {\bf fib} in \ref{ugUserRecur} on page~\pageref{ugUserRecur}. Global variables {\tt past} and {\tt present} are used to hold the last computed Fibonacci numbers. \spadcommand{past := present := 1} $$ 1 $$ \returnType{Type: PositiveInteger} Global variable $index$ gives the current index of $present$. \spadcommand{index := 2} $$ 2 $$ \returnType{Type: PositiveInteger} Here is a recurrence relation defined in terms of these three global variables. \begin{verbatim} fib(n) == free past, present, index n < 3 => 1 n = index - 1 => past if n < index-1 then (past,present) := (1,1) index := 2 while (index < n) repeat (past,present) := (present, past+present) index := index + 1 present \end{verbatim} \returnType{Type: Void} Compute the infinite stream of Fibonacci numbers. \spadcommand{fibs := [fib(n) for n in 1..]} $$ \left[ 1, 1, 2, 3, 5, 8, {13}, {21}, {34}, {55}, \ldots \right] $$ \returnType{Type: Stream PositiveInteger} What is the 1000th Fibonacci number? \spadcommand{fibs 1000} \begin{verbatim} 434665576869374564356885276750406258025646605173717804024_ 8172908953655541794905189040387984007925516929592259308_ 0322634775209689623239873322471161642996440906533187938_ 298969649928516003704476137795166849228875 \end{verbatim} \returnType{Type: PositiveInteger} As an exercise, we suggest you write a function in an iterative style that computes the value of the recurrence relation $p(n) = p(n-1) - 2 \, p(n-2) + 4 \, p(n-3)$ having the initial values $p(1) = 1,\, p(2) = 3 \hbox{ and } p(3) = 9.$ How would you write the function using an element {\tt OneDimensionalArray} or {\tt Vector} to hold the previously computed values? \section{Anonymous Functions} \label{ugUserAnon} \boxed{4.6in}{ \vskip 0.1cm An {\it anonymous function} is a function that is \index{function!anonymous} defined \index{anonymous function} by giving a list of parameters, the ``maps-to'' compound \index{+-> @{\tt +->}} symbol ``{\tt +->}'' (from the mathematical symbol $\mapsto$), and by an expression involving the parameters, the evaluation of which determines the return value of the function. \begin{center} {\tt ( $\hbox{\it parm}_{1}$, $\hbox{\it parm}_{2}$, \ldots, $\hbox{\it parm}_{N}$ ) {\tt +->} {\it expression}} \end{center} {\ }%force a blank line } You can apply an anonymous function in several ways. \begin{enumerate} \item Place the anonymous function definition in parentheses directly followed by a list of arguments. \item Assign the anonymous function to a variable and then use the variable name when you would normally use a function name. \item Use ``{\tt ==}'' to use the anonymous function definition as the arguments and body of a regular function definition. \item Have a named function contain a declared anonymous function and use the result returned by the named function. \end{enumerate} \subsection{Some Examples} \label{ugUserAnonExamp} Anonymous functions are particularly useful for defining functions ``on the fly.'' That is, they are handy for simple functions that are used only in one place. In the following examples, we show how to write some simple anonymous functions. This is a simple absolute value function. \spadcommand{x +-> if x < 0 then -x else x} $$ x \mapsto {if \ {x<0} \ {\begin{array}{l} {then \ -x} \\ {else \ x} \end{array} }} $$ \returnType{Type: AnonymousFunction} \spadcommand{abs1 := \%} $$ x \mapsto {if \ {x<0} \ {\begin{array}{l} {then \ -x} \\ {else \ x} \end{array} }} $$ \returnType{Type: AnonymousFunction} This function returns {\tt true} if the absolute value of the first argument is greater than the absolute value of the second, {\tt false} otherwise. \spadcommand{(x,y) +-> abs1(x) > abs1(y)} $$ {\left( x, y \right)} \mapsto {{abs1 \left( {y} \right)}<{abs1 \left( {x} \right)}} $$ \returnType{Type: AnonymousFunction} We use the above function to ``sort'' a list of integers. \spadcommand{sort(\%,[3,9,-4,10,-3,-1,-9,5])} $$ \left[ {10}, -9, 9, 5, -4, -3, 3, -1 \right] $$ \returnType{Type: List Integer} This function returns $1$ if $i + j$ is even, $-1$ otherwise. \spadcommand{ev := ( (i,j) +-> if even?(i+j) then 1 else -1)} $$ {\left( i, j \right)} \mapsto {if \ {even? \left( {{i+j}} \right)} \ {\begin{array}{l} {then \ 1} \\ {else \ -1} \end{array} }} $$ \returnType{Type: AnonymousFunction} We create a four-by-four matrix containing $1$ or $-1$ depending on whether the row plus the column index is even or not. \spadcommand{matrix([ [ev(row,col) for row in 1..4] for col in 1..4])} $$ \left[ \begin{array}{cccc} 1 & -1 & 1 & -1 \\ -1 & 1 & -1 & 1 \\ 1 & -1 & 1 & -1 \\ -1 & 1 & -1 & 1 \end{array} \right] $$ \returnType{Type: Matrix Integer} This function returns {\tt true} if a polynomial in $x$ has multiple roots, {\tt false} otherwise. It is defined and applied in the same expression. \spadcommand{( p +-> not one?(gcd(p,D(p,x))) )(x**2+4*x+4)} $$ {\tt true} $$ \returnType{Type: Boolean} This and the next expression are equivalent. \spadcommand{g(x,y,z) == cos(x + sin(y + tan(z)))} \returnType{Type: Void} The one you use is a matter of taste. \spadcommand{g == (x,y,z) +-> cos(x + sin(y + tan(z)))} \begin{verbatim} 1 old definition(s) deleted for function or rule g \end{verbatim} \returnType{Type: Void} \subsection{Declaring Anonymous Functions} \label{ugUserAnonDeclare} If you declare any of the arguments you must declare all of them. Thus, \begin{verbatim} (x: INT,y): FRAC INT +-> (x + 2*y)/(y - 1) \end{verbatim} is not legal. This is an example of a fully declared anonymous function. \index{function!declaring} \index{function!anonymous!declaring} The output shown just indicates that the object you created is a particular kind of map, that is, function. \spadcommand{(x: INT,y: INT): FRAC INT +-> (x + 2*y)/(y - 1)} $$ \mbox{theMap(...)} $$ \returnType{Type: ((Integer,Integer) {\tt ->} Fraction Integer)} Axiom allows you to declare the arguments and not declare the return type. \spadcommand{(x: INT,y: INT) +-> (x + 2*y)/(y - 1)} $$ \mbox{theMap(...)} $$ \returnType{Type: ((Integer,Integer) {\tt ->} Fraction Integer)} The return type is computed from the types of the arguments and the body of the function. You cannot declare the return type if you do not declare the arguments. Therefore, \begin{verbatim} (x,y): FRAC INT +-> (x + 2*y)/(y - 1) \end{verbatim} is not legal. This and the next expression are equivalent. \spadcommand{h(x: INT,y: INT): FRAC INT == (x + 2*y)/(y - 1)} \begin{verbatim} Function declaration h : (Integer,Integer) -> Fraction Integer has been added to workspace. \end{verbatim} \returnType{Type: Void} The one you use is a matter of taste. \spadcommand{h == (x: INT,y: INT): FRAC INT +-> (x + 2*y)/(y - 1)} \begin{verbatim} Function declaration h : (Integer,Integer) -> Fraction Integer has been added to workspace. 1 old definition(s) deleted for function or rule h \end{verbatim} \returnType{Type: Void} When should you declare an anonymous function? \begin{enumerate} \item If you use an anonymous function and Axiom can't figure out what you are trying to do, declare the function. \item If the function has nontrivial argument types or a nontrivial return type that Axiom may be able to determine eventually, but you are not willing to wait that long, declare the function. \item If the function will only be used for arguments of specific types and it is not too much trouble to declare the function, do so. \item If you are using the anonymous function as an argument to another function (such as {\bf map} or {\bf sort}), consider declaring the function. \item If you define an anonymous function inside a named function, you {\it must} declare the anonymous function. \end{enumerate} This is an example of a named function for integers that returns a function. \spadcommand{addx x == ((y: Integer): Integer +-> x + y)} \returnType{Type: Void} We define {\bf g} to be a function that adds $10$ to its argument. \spadcommand{g := addx 10} \begin{verbatim} Compiling function addx with type PositiveInteger -> (Integer -> Integer) \end{verbatim} $$ \mbox{theMap(...)} $$ \returnType{Type: (Integer {\tt ->} Integer)} Try it out. \spadcommand{g 3} $$ 13 $$ \returnType{Type: PositiveInteger} \spadcommand{g(-4)} $$ 6 $$ \returnType{Type: PositiveInteger} \index{function!anonymous!restrictions} An anonymous function cannot be recursive: since it does not have a name, you cannot even call it within itself! If you place an anonymous function inside a named function, the anonymous function must be declared. \section{Example: A Database} \label{ugUserDatabase} This example shows how you can use Axiom to organize a database of lineage data and then query the database for relationships. The database is entered as ``assertions'' that are really pieces of a function definition. \spadcommand{children("albert") == ["albertJr","richard","diane"]} \returnType{Type: Void} Each piece $children(x) == y$ means ``the children of $x$ are $y$''. \spadcommand{children("richard") == ["douglas","daniel","susan"]} \returnType{Type: Void} This family tree thus spans four generations. \spadcommand{children("douglas") == ["dougie","valerie"]} \returnType{Type: Void} Say ``no one else has children.'' \spadcommand{children(x) == []} \returnType{Type: Void} We need some functions for computing lineage. Start with {\tt childOf}. \spadcommand{childOf(x,y) == member?(x,children(y))} \returnType{Type: Void} To find the {\tt parentOf} someone, you have to scan the database of people applying {\tt children}. \begin{verbatim} parentOf(x) == for y in people repeat (if childOf(x,y) then return y) "unknown" \end{verbatim} \returnType{Type: Void} And a grandparent of $x$ is just a parent of a parent of $x$. \spadcommand{grandParentOf(x) == parentOf parentOf x} \returnType{Type: Void} The grandchildren of $x$ are the people $y$ such that $x$ is a grandparent of $y$. \spadcommand{grandchildren(x) == [y for y in people | grandParentOf(y) = x]} \returnType{Type: Void} Suppose you want to make a list of all great-grandparents. Well, a great-grandparent is a grandparent of a person who has children. \begin{verbatim} greatGrandParents == [x for x in people | reduce(\_or, [not empty? children(y) for y in grandchildren(x)],false)] \end{verbatim} \returnType{Type: Void} Define {\tt descendants} to include the parent as well. \begin{verbatim} descendants(x) == kids := children(x) null kids => [x] concat(x,reduce(concat,[descendants(y) for y in kids],[])) \end{verbatim} \returnType{Type: Void} Finally, we need a list of people. Since all people are descendants of ``albert'', let's say so. \spadcommand{people == descendants "albert"} \returnType{Type: Void} We have used ``{\tt ==}'' to define the database and some functions to query the database. But no computation is done until we ask for some information. Then, once and for all, the functions are analyzed and compiled to machine code for run-time efficiency. Notice that no types are given anywhere in this example. They are not needed. Who are the grandchildren of ``richard''? \spadcommand{grandchildren "richard"} \begin{verbatim} Compiling function children with type String -> List String Compiling function descendants with type String -> List String Compiling body of rule people to compute value of type List String Compiling function childOf with type (String,String) -> Boolean Compiling function parentOf with type String -> String Compiling function grandParentOf with type String -> String Compiling function grandchildren with type String -> List String \end{verbatim} $$ \left[ \mbox{\tt "dougie"} , \mbox{\tt "valerie"} \right] $$ \returnType{Type: List String} Who are the great-grandparents? \spadcommand{greatGrandParents} \begin{verbatim} Compiling body of rule greatGrandParents to compute value of type List String \end{verbatim} $$ \left[ \mbox{\tt "albert"} \right] $$ \returnType{Type: List String} \section{Example: A Famous Triangle} \label{ugUserTriangle} In this example we write some functions that display Pascal's triangle. \index{Pascal's triangle} It demonstrates the use of piece-wise definitions and some output operations you probably haven't seen before. To make these output operations available, we have to {\it expose} the domain {\tt OutputForm}. \index{OutputForm} See \ref{ugTypesExpose} on page~\pageref{ugTypesExpose} for more information about exposing domains and packages. \spadcommand{)set expose add constructor OutputForm} \begin{verbatim} OutputForm is now explicitly exposed in frame G82322 \end{verbatim} Define the values along the first row and any column $i$. \spadcommand{pascal(1,i) == 1} \returnType{Type: Void} Define the values for when the row and column index $i$ are equal. Repeating the argument name indicates that the two index values are equal. \spadcommand{pascal(n,n) == 1} \returnType{Type: Void} \begin{verbatim} pascal(i,j | 1 < i and i < j) == pascal(i-1,j-1)+pascal(i,j-1) \end{verbatim} \returnType{Type: Void} Now that we have defined the coefficients in Pascal's triangle, let's write a couple of one-liners to display it. First, define a function that gives the $n$-th row. \spadcommand{pascalRow(n) == [pascal(i,n) for i in 1..n]} \returnType{Type: Void} Next, we write the function {\bf displayRow} to display the row, separating entries by blanks and centering. \spadcommand{displayRow(n) == output center blankSeparate pascalRow(n)} \returnType{Type: Void} Here we have used three output operations. Operation \spadfunFrom{output}{OutputForm} displays the printable form of objects on the screen, \spadfunFrom{center}{OutputForm} centers a printable form in the width of the screen, and \spadfunFrom{blankSeparate}{OutputForm} takes a list of nprintable forms and inserts a blank between successive elements. Look at the result. \spadcommand{for i in 1..7 repeat displayRow i} \begin{verbatim} Compiling function pascal with type (Integer,Integer) -> PositiveInteger Compiling function pascalRow with type PositiveInteger -> List PositiveInteger Compiling function displayRow with type PositiveInteger -> Void 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 \end{verbatim} \returnType{Type: Void} Being purists, we find this less than satisfactory. Traditionally, elements of Pascal's triangle are centered between the left and right elements on the line above. To fix this misalignment, we go back and redefine {\bf pascalRow} to right adjust the entries within the triangle within a width of four characters. \spadcommand{pascalRow(n) == [right(pascal(i,n),4) for i in 1..n]} \begin{verbatim} Compiled code for pascalRow has been cleared. Compiled code for displayRow has been cleared. 1 old definition(s) deleted for function or rule pascalRow \end{verbatim} \returnType{Type: Void} Finally let's look at our purely reformatted triangle. \spadcommand{for i in 1..7 repeat displayRow i} \begin{verbatim} Compiling function pascalRow with type PositiveInteger -> List OutputForm +++ |*1;pascalRow;1;G82322| redefined Compiling function displayRow with type PositiveInteger -> Void +++ |*1;displayRow;1;G82322| redefined 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 \end{verbatim} \returnType{Type: Void} Unexpose {\tt OutputForm} so we don't get unexpected results later. \spadcommand{)set expose drop constructor OutputForm} \begin{verbatim} OutputForm is now explicitly hidden in frame G82322 \end{verbatim} \section{Example: Testing for Palindromes} \label{ugUserPal} In this section we define a function {\bf pal?} that tests whether its \index{palindrome} argument is a {\it palindrome}, that is, something that reads the same backwards and forwards. For example, the string ``Madam I'm Adam'' is a palindrome (excluding blanks and punctuation) and so is the number $123454321$. The definition works for any datatype that has $n$ components that are accessed by the indices $1\ldots n$. Here is the definition for {\bf pal?}. It is simply a call to an auxiliary function called {\bf palAux?}. We are following the convention of ending a function's name with {\tt ?} if the function returns a {\tt Boolean} value. \spadcommand{pal? s == palAux?(s,1,\#s)} \returnType{Type: Void} Here is {\bf palAux?}. It works by comparing elements that are equidistant from the start and end of the object. \begin{verbatim} palAux?(s,i,j) == j > i => (s.i = s.j) and palAux?(s,i+1,i-1) true \end{verbatim} \returnType{Type: Void} Try {\bf pal?} on some examples. First, a string. \spadcommand{pal? "Oxford"} \begin{verbatim} Compiling function palAux? with type (String,Integer,Integer) -> Boolean Compiling function pal? with type String -> Boolean \end{verbatim} $$ {\tt false} $$ \returnType{Type: Boolean} A list of polynomials. \spadcommand{pal? [4,a,x-1,0,x-1,a,4]} \begin{verbatim} Compiling function palAux? with type (List Polynomial Integer, Integer,Integer) -> Boolean Compiling function pal? with type List Polynomial Integer -> Boolean \end{verbatim} $$ {\tt true} $$ \returnType{Type: Boolean} A list of integers from the example in the last section. \spadcommand{pal? [1,6,15,20,15,6,1]} \begin{verbatim} Compiling function palAux? with type (List PositiveInteger,Integer, Integer) -> Boolean Compiling function pal? with type List PositiveInteger -> Boolean \end{verbatim} $$ {\tt true} $$ \returnType{Type: Boolean} To use {\bf pal?} on an integer, first convert it to a string. \spadcommand{pal?(1441::String)} $$ {\tt true} $$ \returnType{Type: Boolean} Compute an infinite stream of decimal numbers, each of which is an obvious palindrome. \spadcommand{ones := [reduce(+,[10**j for j in 0..i]) for i in 1..]} $$ \begin{array}{@{}l} \left[ {11}, {111}, {1111}, {11111}, {111111}, {1111111}, \right. \\ \\ \displaystyle \left. {11111111}, {111111111}, {1111111111}, {11111111111}, \ldots \right] \end{array} $$ \returnType{Type: Stream PositiveInteger} \spadcommand{)set streams calculate 9} How about their squares? \spadcommand{squares := [x**2 for x in ones]} $$ \begin{array}{@{}l} \left[ {121}, {12321}, {1234321}, {123454321}, {12345654321}, {1234567654321}, \right. \\ \\ \displaystyle {123456787654321}, {12345678987654321}, {1234567900987654321}, \\ \\ \displaystyle \left. {123456790120987654321}, \ldots \right] \end{array} $$ \returnType{Type: Stream PositiveInteger} Well, let's test them all. \spadcommand{[pal?(x::String) for x in squares]} $$ \left[ {\tt true}, {\tt true}, {\tt true}, {\tt true}, {\tt true}, {\tt true}, {\tt true}, {\tt true}, {\tt true}, {\tt true}, \ldots \right] $$ \returnType{Type: Stream Boolean} \spadcommand{)set streams calculate 7} \section{Rules and Pattern Matching} \label{ugUserRules} A common mathematical formula is $$ \log(x) + \log(y) = \log(x y) \quad\forall \, x \hbox{\ and\ } y$$ The presence of ``$\forall$'' indicates that $x$ and $y$ can stand for arbitrary mathematical expressions in the above formula. You can use such mathematical formulas in Axiom to specify ``rewrite rules''. Rewrite rules are objects in Axiom that can be assigned to variables for later use, often for the purpose of simplification. Rewrite rules look like ordinary function definitions except that they are preceded by the reserved word $rule$. \index{rule} For example, a rewrite rule for the above formula is: \begin{verbatim} rule log(x) + log(y) == log(x * y) \end{verbatim} Like function definitions, no action is taken when a rewrite rule is issued. Think of rewrite rules as functions that take one argument. When a rewrite rule $A = B$ is applied to an argument $f$, its meaning is: ``rewrite every subexpression of $f$ that {\it matches} $A$ by $B.$'' The left-hand side of a rewrite rule is called a {\it pattern}; its right-side side is called its {\it substitution}. Create a rewrite rule named {\bf logrule}. The generated symbol beginning with a ``{\tt \%}'' is a place-holder for any other terms that might occur in the sum. \spadcommand{logrule := rule log(x) + log(y) == log(x * y)} $$ {{\log \left( {y} \right)}+{\log \left( {x} \right)}+ \%C} \mbox{\rm == } {{\log \left( {{x \ y}} \right)}+ \%C} $$ \returnType{Type: RewriteRule(Integer,Integer,Expression Integer)} Create an expression with logarithms. \spadcommand{f := log sin x + log x} $$ {\log \left( {{\sin \left( {x} \right)}} \right)}+{\log \left( {x} \right)} $$ \returnType{Type: Expression Integer} Apply {\bf logrule} to $f$. \spadcommand{logrule f} $$ \log \left( {{x \ {\sin \left( {x} \right)}}} \right) $$ \returnType{Type: Expression Integer} The meaning of our example rewrite rule is: ``for all expressions $x$ and $y$, rewrite $log(x) + log(y)$ by $log(x * y)$.'' Patterns generally have both operation names (here, {\bf log} and ``{\tt +}'') and variables (here, $x$ and $y$). By default, every operation name stands for itself. Thus {\bf log} matches only ``$log$'' and not any other operation such as {\bf sin}. On the other hand, variables do not stand for themselves. Rather, a variable denotes a {\it pattern variable} that is free to match any expression whatsoever. \index{pattern!variables} When a rewrite rule is applied, a process called {\it pattern matching} goes to work by systematically scanning \index{pattern!matching} the subexpressions of the argument. When a subexpression is found that ``matches'' the pattern, the subexpression is replaced by the right-hand side of the rule. The details of what happens will be covered later. The customary Axiom notation for patterns is actually a shorthand for a longer, more general notation. Pattern variables can be made explicit by using a percent ``{\tt \%}'' as the first character of the variable name. To say that a name stands for itself, you can prefix that name with a quote operator ``{\tt '}''. Although the current Axiom parser does not let you quote an operation name, this more general notation gives you an alternate way of giving the same rewrite rule: \begin{verbatim} rule log(%x) + log(%y) == log(x * y) \end{verbatim} This longer notation gives you patterns that the standard notation won't handle. For example, the rule \begin{verbatim} rule %f(c * 'x) == c*%f(x) \end{verbatim} means ``for all $f$ and $c$, replace $f(y)$ by $c * f(x)$ when $y$ is the product of $c$ and the explicit variable $x$.'' Thus the pattern can have several adornments on the names that appear there. Normally, all these adornments are dropped in the substitution on the right-hand side. To summarize: \boxed{4.6in}{ \vskip 0.1cm To enter a single rule in Axiom, use the following syntax: \index{rule} \begin{center} {\tt rule {\it leftHandSide} == {\it rightHandSide}} \end{center} The {\it leftHandSide} is a pattern to be matched and the {\it rightHandSide} is its substitution. The rule is an object of type {\tt RewriteRule} that can be assigned to a variable and applied to expressions to transform them.\\ } Rewrite rules can be collected into rulesets so that a set of rules can be applied at once. Here is another simplification rule for logarithms. $$y \log(x) = \log(x^y) \quad\forall \, x \hbox{\ and\ } y$$ If instead of giving a single rule following the reserved word $rule$ you give a ``pile'' of rules, you create what is called a {\it ruleset.} \index{ruleset} Like rules, rulesets are objects in Axiom and can be assigned to variables. You will find it useful to group commonly used rules into input files, and read them in as needed. Create a ruleset named $logrules$. \begin{verbatim} logrules := rule log(x) + log(y) == log(x * y) y * log x == log(x ** y) \end{verbatim} $$ \left\{ {{{\log \left( {y} \right)}+{\log \left( {x} \right)}+ \%B} \mbox{\rm == } {{\log \left( {{x \ y}} \right)}+ \%B}}, {{y \ {\log \left( {x} \right)}} \mbox{\rm == } {\log \left( {{x \sp y}} \right)}} \right\} $$ \returnType{Type: Ruleset(Integer,Integer,Expression Integer)} Again, create an expression $f$ containing logarithms. \spadcommand{f := a * log(sin x) - 2 * log x} $$ {a \ {\log \left( {{\sin \left( {x} \right)}} \right)}} -{2 \ {\log \left( {x} \right)}} $$ \returnType{Type: Expression Integer} Apply the ruleset {\bf logrules} to $f$. \spadcommand{logrules f} $$ \log \left( {{{{\sin \left( {x} \right)} \sp a} \over {x \sp 2}}} \right) $$ \returnType{Type: Expression Integer} We have allowed pattern variables to match arbitrary expressions in the above examples. Often you want a variable only to match expressions satisfying some predicate. For example, we may want to apply the transformation $$y \log(x) = \log(x^y)$$ only when $y$ is an integer. The way to restrict a pattern variable $y$ by a predicate $f(y)$ \index{pattern!variable!predicate} is by using a vertical bar ``{\tt |}'', which means ``such that,'' in \index{such that} much the same way it is used in function definitions. \index{predicate!on a pattern variable} You do this only once, but at the earliest (meaning deepest and leftmost) part of the pattern. This restricts the logarithmic rule to create integer exponents only. \begin{verbatim} logrules2 := rule log(x) + log(y) == log(x * y) (y | integer? y) * log x == log(x ** y) \end{verbatim} $$ \left\{ {{{\log \left( {y} \right)}+{\log \left( {x} \right)}+ \%D} \mbox{\rm == } {{\log \left( {{x \ y}} \right)}+ \%D}}, {{y \ {\log \left( {x} \right)}} \mbox{\rm == } {\log \left( {{x \sp y}} \right)}} \right\} $$ \returnType{Type: Ruleset(Integer,Integer,Expression Integer)} Compare this with the result of applying the previous set of rules. \spadcommand{f} $$ {a \ {\log \left( {{\sin \left( {x} \right)}} \right)}} -{2 \ {\log \left( {x} \right)}} $$ \returnType{Type: Expression Integer} \spadcommand{logrules2 f} $$ {a \ {\log \left( {{\sin \left( {x} \right)}} \right)}}+{\log \left( {{1 \over {x \sp 2}}} \right)} $$ \returnType{Type: Expression Integer} You should be aware that you might need to apply a function like {\tt integer} within your predicate expression to actually apply the test function. Here we use {\tt integer} because $n$ has type {\tt Expression Integer} but {\bf even?} is an operation defined on integers. \spadcommand{evenRule := rule cos(x)**(n | integer? n and even? integer n)==(1-sin(x)**2)**(n/2)} $$ {{\cos \left( {x} \right)} \sp n} \mbox{\rm == } {{\left( -{{\sin \left( {x} \right)} \sp 2}+1 \right)} \sp {n \over 2}} $$ \returnType{Type: RewriteRule(Integer,Integer,Expression Integer)} Here is the application of the rule. \spadcommand{evenRule( cos(x)**2 )} $$ -{{\sin \left( {x} \right)} \sp 2}+1 $$ \returnType{Type: Expression Integer} This is an example of some of the usual identities involving products of sines and cosines. \begin{verbatim} sinCosProducts == rule sin(x) * sin(y) == (cos(x-y) - cos(x + y))/2 cos(x) * cos(y) == (cos(x-y) + cos(x+y))/2 sin(x) * cos(y) == (sin(x-y) + sin(x + y))/2 \end{verbatim} \returnType{Type: Void} \spadcommand{g := sin(a)*sin(b) + cos(b)*cos(a) + sin(2*a)*cos(2*a)} $$ {{\sin \left( {a} \right)} \ {\sin \left( {b} \right)}}+{{\cos \left( {{2 \ a}} \right)} \ {\sin \left( {{2 \ a}} \right)}}+{{\cos \left( {a} \right)} \ {\cos \left( {b} \right)}} $$ \returnType{Type: Expression Integer} \spadcommand{sinCosProducts g} \begin{verbatim} Compiling body of rule sinCosProducts to compute value of type Ruleset(Integer,Integer,Expression Integer) \end{verbatim} $$ {{\sin \left( {{4 \ a}} \right)}+{2 \ {\cos \left( {{b -a}} \right)}}} \over 2 $$ \returnType{Type: Expression Integer} Another qualification you will often want to use is to allow a pattern to match an identity element. Using the pattern $x + y$, for example, neither $x$ nor $y$ matches the expression $0$. Similarly, if a pattern contains a product $x*y$ or an exponentiation $x**y$, then neither $x$ or $y$ matches $1$. If identical elements were matched, pattern matching would generally loop. Here is an expansion rule for exponentials. \spadcommand{exprule := rule exp(a + b) == exp(a) * exp(b)} $$ {e \sp {\left( b+a \right)}} \mbox{\rm == } {{e \sp a} \ {e \sp b}} $$ \returnType{Type: RewriteRule(Integer,Integer,Expression Integer)} This rule would cause infinite rewriting on this if either $a$ or $b$ were allowed to match $0$. \spadcommand{exprule exp x} $$ e \sp x $$ \returnType{Type: Expression Integer} There are occasions when you do want a pattern variable in a sum or product to match $0$ or $1$. If so, prefix its name with a ``{\tt ?}'' whenever it appears in a left-hand side of a rule. For example, consider the following rule for the exponential integral: $$\int \left(\frac{y+e^x}{x}\right) dx = \int \frac{y}{x} dx + \hbox{\rm Ei}(x) \quad\forall \, x \hbox{\ and\ } y$$ This rule is valid for $y = 0$. One solution is to create a {\tt Ruleset} with two rules, one with and one without $y$. A better solution is to use an ``optional'' pattern variable. Define rule {\tt eirule} with a pattern variable $?y$ to indicate that an expression may or may not occur. \spadcommand{eirule := rule integral((?y + exp x)/x,x) == integral(y/x,x) + Ei x} $$ {\int \sp{\displaystyle x} {{{{e \sp \%M}+y} \over \%M} \ {d \%M}}} \mbox{\rm == } {{{{\tt '}integral} \left( {{y \over x}, x} \right)}+{{{\tt '}Ei} \left( {x} \right)}} $$ \returnType{Type: RewriteRule(Integer,Integer,Expression Integer)} Apply rule {\tt eirule} to an integral without this term. \spadcommand{eirule integral(exp u/u, u)} $$ Ei \left( {u} \right) $$ \returnType{Type: Expression Integer} Apply rule {\tt eirule} to an integral with this term. \spadcommand{eirule integral(sin u + exp u/u, u)} $$ {\int \sp{\displaystyle u} {{\sin \left( { \%M} \right)} \ {d \%M}}}+{Ei \left( {u} \right)} $$ \returnType{Type: Expression Integer} Here is one final adornment you will find useful. When matching a pattern of the form $x + y$ to an expression containing a long sum of the form $a +\ldots+ b$, there is no way to predict in advance which subset of the sum matches $x$ and which matches $y$. Aside from efficiency, this is generally unimportant since the rule holds for any possible combination of matches for $x$ and $y$. In some situations, however, you may want to say which pattern variable is a sum (or product) of several terms, and which should match only a single term. To do this, put a prefix colon ``{\tt :}'' before the pattern variable that you want to match multiple terms. \index{pattern!variable!matching several terms} The remaining rules involve operators $u$ and $v$. \index{operator} \spadcommand{u := operator 'u} $$ u $$ \returnType{Type: BasicOperator} These definitions tell Axiom that $u$ and $v$ are formal operators to be used in expressions. \spadcommand{v := operator 'v} $$ v $$ \returnType{Type: BasicOperator} First define {\tt myRule} with no restrictions on the pattern variables $x$ and $y$. \spadcommand{myRule := rule u(x + y) == u x + v y} $$ {u \left( {{y+x}} \right)} \mbox{\rm == } {{{{\tt '}v} \left( {y} \right)}+{{{\tt '}u} \left( {x} \right)}} $$ \returnType{Type: RewriteRule(Integer,Integer,Expression Integer)} Apply {\tt myRule} to an expression. \spadcommand{myRule u(a + b + c + d)} $$ {v \left( {{d+c+b}} \right)}+{u \left( {a} \right)} $$ \returnType{Type: Expression Integer} Define {\tt myOtherRule} to match several terms so that the rule gets applied recursively. \spadcommand{myOtherRule := rule u(:x + y) == u x + v y} $$ {u \left( {{y+x}} \right)} \mbox{\rm == } {{{{\tt '}v} \left( {y} \right)}+{{{\tt '}u} \left( {x} \right)}} $$ \returnType{Type: RewriteRule(Integer,Integer,Expression Integer)} Apply {\tt myOtherRule} to the same expression. \spadcommand{myOtherRule u(a + b + c + d)} $$ {v \left( {c} \right)}+{v \left( {b} \right)}+{v \left( {a} \right)}+{u \left( {d} \right)} $$ \returnType{Type: Expression Integer} \boxed{4.6in}{ \vskip 0.1cm Summary of pattern variable adornments: \vskip .5\baselineskip \begin{tabular}{@{}ll} {\tt (x | predicate?(x))} & means that the substutution $s$ for $x$\\ & must satisfy {\tt predicate(s) = true.} \\ {\tt ?x} & means that $x$ can match an identity \\ & element (0 or 1). \\ {\tt :x} & means that $x$ can match several terms \\ & in a sum. \end{tabular}\\ } Here are some final remarks on pattern matching. Pattern matching provides a very useful paradigm for solving certain classes of problems, namely, those that involve transformations of one form to another and back. However, it is important to recognize its limitations. \index{pattern!matching!caveats} First, pattern matching slows down as the number of rules you have to apply increases. Thus it is good practice to organize the sets of rules you use optimally so that irrelevant rules are never included. Second, careless use of pattern matching can lead to wrong answers. You should avoid using pattern matching to handle hidden algebraic relationships that can go undetected by other programs. As a simple example, a symbol such as ``J'' can easily be used to represent the square root of $-1$ or some other important algebraic quantity. Many algorithms branch on whether an expression is zero or not, then divide by that expression if it is not. If you fail to simplify an expression involving powers of $J$ to $-1,$ algorithms may incorrectly assume an expression is non-zero, take a wrong branch, and produce a meaningless result. Pattern matching should also not be used as a substitute for a domain. In Axiom, objects of one domain are transformed to objects of other domains using well-defined {\bf coerce} operations. Pattern matching should be used on objects that are all the same type. Thus if your application can be handled by type {\tt Expression} in Axiom and you think you need pattern matching, consider this choice carefully. \index{Expression} You may well be better served by extending an existing domain or by building a new domain of objects for your application. \setcounter{chapter}{3} \chapter{Graphics} \label{ugGraph} \begin{figure}[htbp] \includegraphics{ps/torusKnot.ps} \caption{Torus knot of type (15,17).} \end{figure} This chapter shows how to use the Axiom graphics facilities \index{graphics} under the X Window System. Axiom has two-di\-men\-sion\-al and three-di\-men\-sion\-al drawing and rendering packages that allow the drawing, coloring, transforming, mapping, clipping, and combining of graphic output from Axiom computations. This facility is particularly useful for investigating problems in areas such as topology. The graphics package is capable of plotting functions of one or more variables or plotting parametric surfaces and curves. Various coordinate systems are also available, such as polar and spherical. A graph is displayed in a viewport window and it has a \index{viewport} control-panel that uses interactive mouse commands. PostScript and other output forms are available so that Axiom \index{PostScript} images can be printed or used by other programs. \section{Two-Dimensional Graphics} \label{ugGraphTwoD} The Axiom two-di\-men\-sion\-al graphics package provides the ability to \index{graphics!two-dimensional} display \begin{itemize} \item curves defined by functions of a single real variable \item curves defined by parametric equations \item implicit non-singular curves defined by polynomial equations \item planar graphs generated from lists of point components. \end{itemize} These graphs can be modified by specifying various options, such as calculating points in the polar coordinate system or changing the size of the graph viewport window. \subsection{Plotting Two-Dimensional Functions of One Variable} \label{ugGraphTwoDPlot} \index{curve!one variable function} The first kind of two-di\-men\-sion\-al graph is that of a curve defined by a function $y = f(x)$ over a finite interval of the $x$ axis. \boxed{4.6in}{ \vskip 0.1cm The general format for drawing a function defined by a formula $f(x)$ is: \begin{center} {\tt draw(f(x), x = a..b, {\it options})} \end{center} where $a..b$ defines the range of $x$, and where {\it options} prescribes zero or more options as described in \ref{ugGraphTwoDOptions} on page~\pageref{ugGraphTwoDOptions}. An example of an option is $curveColor == bright red().$ An alternative format involving functions $f$ and $g$ is also available.\\ } A simple way to plot a function is to use a formula. The first argument is the formula. For the second argument, write the name of the independent variable (here, $x$), followed by an ``{\tt =}'', and the range of values. Display this formula over the range $0 \leq x \leq 6$. Axiom converts your formula to a compiled function so that the results can be computed quickly and efficiently. \spadgraph{draw(sin(tan(x)) - tan(sin(x)),x = 0..6)} %\begin{figure}[htbp] %{\rm draw(sin(tan(x)) - tan(sin(x)),x = 0..6)\\} %\vskip 0.2cm %\includegraphics{ps/2D1VarA.ps} %\caption{$sin(tan(x)) - tan(sin(x))\ \ \ x = 0 \ldots6$} %\end{figure} %{\rm %\par %Notice that Axiom compiled the function before the graph was put %on the screen. % %Here is the same graph on a different interval.\\ % %draw(sin(tan(x)) - tan(sin(x)),x = 10..16)\\ %} %\vskip 0.2cm %\spadgraph{draw(sin(tan(x)) - tan(sin(x)),x = 10..16)} %\begin{figure}[htbp] %\includegraphics{ps/2D1VarB.ps} %\caption{$sin(tan(x)) - tan(sin(x))\ \ \ x = 10 \ldots16$} %\end{figure} Once again the formula is converted to a compiled function before any points were computed. If you want to graph the same function on several intervals, it is a good idea to define the function first so that the function has to be compiled only once. This time we first define the function. \spadcommand{f(x) == (x-1)*(x-2)*(x-3) } %\begin{figure} %\tpd{0 0 300 300 ps/2D1VarD.ps} %\end{figure} \returnType{Type: Void} %\epsffile[14 14 188 199]{ps/2D1VarD.ps} %\hspace*{\baseLeftSkip}\special{psfile=ps/2Dctrl.ps} To draw the function, the first argument is its name and the second is just the range with no independent variable. \spadgraph{draw(f, 0..4) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2D1VarD.ps} \subsection{Plotting Two-Dimensional Parametric Plane Curves} \label{ugGraphTwoDPar} The second kind of two-di\-men\-sion\-al graph is that of \index{parametric plane curve} curves produced by parametric equations. \index{curve!parametric plane} Let $x = f(t)$ and $y = g(t)$ be formulas or two functions $f$ and $g$ as the parameter $t$ ranges over an interval $[a,b]$. The function {\bf curve} takes the two functions $f$ and $g$ as its parameters. \boxed{4.6in}{ \vskip 0.1cm The general format for drawing a two-di\-men\-sion\-al plane curve defined by parametric formulas $x = f(t)$ and $y = g(t)$ is: \begin{center} {\tt draw(curve(f(t), g(t)), t = a..b, {\it options})} \end{center} where $a..b$ defines the range of the independent variable $t$, and where {\it options} prescribes zero or more options as described in \ref{ugGraphThreeDOptions} on page~\pageref{ugGraphThreeDOptions}. An example of an option is $curveColor == bright red().$\\ } Here's an example: Define a parametric curve using a range involving $\%pi$, Axiom's way of saying $\pi$. For parametric curves, Axiom compiles two functions, one for each of the functions $f$ and $g$. \spadgraph{draw(curve(sin(t)*sin(2*t)*sin(3*t), sin(4*t)*sin(5*t)*sin(6*t)), t = 0..2*\%pi)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DppcA.ps} The title may be an arbitrary string and is an optional argument to the {\bf draw} command. \spadgraph{draw(curve(cos(t), sin(t)), t = 0..2*\%pi)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DppcB.ps} If you plan on plotting $x = f(t)$, $y = g(t)$ as $t$ ranges over several intervals, you may want to define functions $f$ and $g$ first, so that they need not be recompiled every time you create a new graph. Here's an example: As before, you can first define the functions you wish to draw. \spadcommand{f(t:DFLOAT):DFLOAT == sin(3*t/4) } \begin{verbatim} Function declaration f : DoubleFloat -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Axiom compiles them to map {\tt DoubleFloat} values to {\tt DoubleFloat} values. \spadcommand{g(t:DFLOAT):DFLOAT == sin(t) } \begin{verbatim} Function declaration f : DoubleFloat -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Give to {\tt curve} the names of the functions, then write the range without the name of the independent variable. \spadgraph{draw(curve(f,g),0..\%pi) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DppcC.ps} Here is another look at the same curve but over a different range. Notice that $f$ and $g$ are not recompiled. Also note that Axiom provides a default title based on the first function specified in {\bf curve}. \spadgraph{draw(curve(f,g),-4*\%pi..4*\%pi) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DppcE.ps} \subsection{Plotting Plane Algebraic Curves} \label{ugGraphTwoDPlane} A third kind of two-di\-men\-sion\-al graph is a non-singular ``solution curve'' \index{curve!plane algebraic} in a rectangular region of the plane. A solution curve is a curve defined by a polynomial equation $p(x,y) = 0$. \index{plane algebraic curve} Non-singular means that the curve is ``smooth'' in that it does not cross itself or come to a point (cusp). Algebraically, this means that for any point $(x,y)$ on the curve, that is, a point such that $p(x,y) = 0$, the partial derivatives ${{\partial p}\over{\partial x}}(x,y)$ and ${{\partial p}\over{\partial y}}(x,y)$ are not both zero. \index{curve!smooth} \index{curve!non-singular} \index{smooth curve} \index{non-singular curve} \boxed{4.6in}{ \vskip 0.1cm The general format for drawing a non-singular solution curve given by a polynomial of the form $p(x,y) = 0$ is: \begin{center} {\tt draw(p(x,y) = 0, x, y, range == [a..b, c..d], {\it options})} \end{center} where the second and third arguments name the first and second independent variables of $p$. A {\tt range} option is always given to designate a bounding rectangular region of the plane $a \leq x \leq b, c \leq y \leq d$. Zero or more additional options as described in \ref{ugGraphTwoDOptions} on page~\pageref{ugGraphTwoDOptions} may be given.\\ } We require that the polynomial has rational or integral coefficients. Here is an algebraic curve example (``Cartesian ovals''): \index{Cartesian!ovals} \spadcommand{p := ((x**2 + y**2 + 1) - 8*x)**2 - (8*(x**2 + y**2 + 1)-4*x-1) } \begin{verbatim} $$ {y \sp 4}+{{\left( {2 \ {x \sp 2}} -{{16} \ x} -6 \right)} \ {y \sp 2}}+{x \sp 4} -{{16} \ {x \sp 3}}+{{58} \ {x \sp 2}} -{{12} \ x} -6 $$ \end{verbatim} \returnType{Type: Polynomial Integer} The first argument is always expressed as an equation of the form $p = 0$ where $p$ is a polynomial. \spadgraph{draw(p = 0, x, y, range == [-1..11, -7..7]) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DpacA.ps} \subsection{Two-Dimensional Options} \label{ugGraphTwoDOptions} The {\bf draw} commands take an optional list of options, such as {\tt title} shown above. Each option is given by the syntax: {\it name} {\tt ==} {\it value}. Here is a list of the available options in the order that they are described below. \begin{tabular}{llll} adaptive&clip&unit\\ clip&curveColor&range\\ toScale&pointColor&coordinates\\ \end{tabular} The $adaptive$ option turns adaptive plotting on or off. \index{adaptive plotting} Adaptive plotting uses an algorithm that traverses a graph and computes more points for those parts of the graph with high curvature. The higher the curvature of a region is, the more points the algorithm computes. \index{graphics!2D options!adaptive} The {\tt adaptive} option is normally on. Here we turn it off. \spadgraph{draw(sin(1/x),x=-2*\%pi..2*\%pi, adaptive == false)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptAd.ps} The {\tt clip} option turns clipping on or off. \index{graphics!2D options!clipping} If on, large values are cut off according to \spadfunFrom{clipPointsDefault}{GraphicsDefaults}. \spadgraph{draw(tan(x),x=-2*\%pi..2*\%pi, clip == true)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptCp.ps} Option {\tt toScale} does plotting to scale if {\tt true} or uses the entire viewport if {\tt false}. The default can be determined using \spadfunFrom{drawToScale}{GraphicsDefaults}. \index{graphics!2D options!to scale} \spadgraph{draw(sin(x),x=-\%pi..\%pi, toScale == true, unit == [1.0,1.0])} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptSc.ps} Option {\tt clip} with a range sets point clipping of a graph within the \index{graphics!2D options!clip in a range} ranges specified in the list $[x range,y range]$. \index{clipping} If only one range is specified, clipping applies to the y-axis. \spadgraph{draw(sec(x),x=-2*\%pi..2*\%pi, clip == [-2*\%pi..2*\%pi,-\%pi..\%pi], unit == [1.0,1.0])} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptCpR.ps} Option {\tt curveColor} sets the color of the graph curves or lines to be the \index{graphics!2D options!curve color} indicated palette color \index{curve!color} (see \ref{ugGraphColor} on page~\pageref{ugGraphColor} and \ref{ugGraphColorPalette} on page~\pageref{ugGraphColorPalette}). \index{color!curve} \spadgraph{draw(sin(x),x=-\%pi..\%pi, curveColor == bright red())} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptCvC.ps} Option {\tt pointColor} sets the color of the graph points to the indicated \index{graphics!2D options!point color} palette color (see \ref{ugGraphColor} on page~\pageref{ugGraphColor} and \ref{ugGraphColorPalette} on page~\pageref{ugGraphColorPalette}). \index{color!point} \spadgraph{draw(sin(x),x=-\%pi..\%pi, pointColor == pastel yellow())} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptPtC.ps} Option {\tt unit} sets the intervals at which the axis units are plotted \index{graphics!2D options!set units} according to the indicated steps [$x$ interval, $y$ interval]. \spadgraph{draw(curve(9*sin(3*t/4),8*sin(t)), t = -4*\%pi..4*\%pi, unit == [2.0,1.0])} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptUt.ps} Option {\tt range} sets the range of variables in a graph to be within the ranges \index{graphics!2D options!range} for solving plane algebraic curve plots. \spadgraph{draw(y**2 + y - (x**3 - x) = 0, x, y, range == [-2..2,-2..1], unit==[1.0,1.0])} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptRgA.ps} A second example of a solution plot. \spadgraph{draw(x**2 + y**2 = 1, x, y, range == [-3/2..3/2,-3/2..3/2], unit==[0.5,0.5])} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptRgB.ps} Option $coordinates$ indicates the coordinate system in which the graph \index{graphics!2D options!coordinates} is plotted. The default is to use the Cartesian coordinate system. \index{Cartesian!coordinate system} For more details, see \ref{ugGraphCoord} on page~\pageref{ugGraphCoord} {or {\tt CoordinateSystems}.} \index{coordinate system!Cartesian} \spadgraph{draw(curve(sin(5*t),t),t=0..2*\%pi, coordinates == polar)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/2DOptPlr.ps} \subsection{Color} \label{ugGraphColor} The domain {\tt Color} \index{Color} provides operations for manipulating \index{graphics!color} colors in two-di\-men\-sion\-al graphs. \index{color} Colors are objects of {\tt Color}. Each color has a {\it hue} and a {\it weight}. \index{hue} Hues are represented by integers that range from $1$ to the \spadfunFrom{numberOfHues()}{Color}, normally \index{graphics!color!number of hues} $27$. \index{weight} Weights are floats and have the value $1.0$ by default. \begin{description} \item[{\bf color}]\funArgs{integer} creates a color of hue {\it integer} and weight $1.0$. \item[{\bf hue}]\funArgs{color} returns the hue of {\it color} as an integer. \index{graphics!color!hue function} \item[{\bf red}]\funArgs{} \funSyntax{blue}{}, \funSyntax{green}{}, and \funSyntax{yellow}{} \index{graphics!color!primary color functions} create colors of that hue with weight $1.0$. \item[$\hbox{\it color}_{1}$ {\tt +} $\hbox{\it color}_{2}$] returns the color that results from additively combining the indicated $\hbox{\it color}_{1}$ and $\hbox{\it color}_{2}$. Color addition is not commutative: changing the order of the arguments produces different results. \item[{\it integer} {\tt *} {\it color}] changes the weight of {\it color} by {\it integer} without affecting its hue. \index{graphics!color!multiply function} For example, $red() + 3*yellow()$ produces a color closer to yellow than to red. Color multiplication is not associative: changing the order of grouping \index{color!multiplication} produces different results. \end{description} These functions can be used to change the point and curve colors for two- and three-di\-men\-sion\-al graphs. Use the {\tt pointColor} option for points. \spadgraph{draw(x**2,x=-1..1,pointColor == green())} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/23DColA.ps} Use the {\tt curveColor} option for curves. \spadgraph{draw(x**2,x=-1..1,curveColor == color(13) + 2*blue())} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/23DColB.ps} \subsection{Palette} \label{ugGraphColorPalette} \index{graphics!palette} Domain {\tt Palette} is the domain of shades of colors: {\bf dark}, {\bf dim}, {\bf bright}, {\bf pastel}, and {\bf light}, designated by the integers $1$ through $5$, respectively. \index{Palette} Colors are normally ``bright.'' \spadcommand{shade red()} $$ 3 $$ \returnType{Type: PositiveInteger} To change the shade of a color, apply the name of a shade to it. \index{color!shade} \index{shade} \spadcommand{myFavoriteColor := dark blue() } $$ [{ \mbox{\rm Hue: } {22} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dark \mbox{\rm palette} $$ \returnType{Type: Palette} The expression $shade(color)$ returns the value of a shade of $color$. \spadcommand{shade myFavoriteColor } $$ 1 $$ \returnType{Type: PositiveInteger} The expression $hue(color)$ returns its hue. \spadcommand{hue myFavoriteColor } $$ \mbox{\rm Hue: } {22} \mbox{\rm Weight: } {1.0} $$ \returnType{Type: Color} Palettes can be used in specifying colors in two-di\-men\-sion\-al graphs. \spadgraph{draw(x**2,x=-1..1,curveColor == dark blue())} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/23DPal.ps} \subsection{Two-Dimensional Control-Panel} \label{ugGraphTwoDControl} \index{graphics!2D control-panel} Once you have created a viewport, move your mouse to the viewport and click with your left mouse button to display a control-panel. The panel is displayed on the side of the viewport closest to where you clicked. Each of the buttons which toggle on and off show the current state of the graph. %\begin{texonly} %\typeout{2D control-panel.} \begin{figure}[htbp] %{\epsfverbosetrue\epsfxsize=2in% %\def\epsfsize#1#2{\epsfxsize}\hspace*{\baseLeftSkip}% %%\epsffile[0 0 144 289]{ps/2Dctrl.ps}} %\begin{picture}(147,252)%(-143,0) %\hspace*{\baseLeftSkip}\special{psfile=ps/2Dctrl.ps} %\end{picture} \caption{Two-dimensional control-panel.} \end{figure} %\end{texonly} \subsubsection{Transformations} \index{graphics!2D control-panel!transformations} Object transformations are executed from the control-panel by mouse-activated potentiometer windows. % \begin{description} % \item[Scale:] To scale a graph, click on a mouse button \index{graphics!2D control-panel!scale} within the {\bf Scale} window in the upper left corner of the control-panel. The axes along which the scaling is to occur are indicated by setting the toggles above the arrow. With {\tt X On} and {\tt Y On} appearing, both axes are selected and scaling is uniform. If either is not selected, for example, if {\tt X Off} appears, scaling is non-uniform. % \item[Translate:] To translate a graph, click the mouse in the \index{graphics!2D control-panel!translate} {\bf Translate} window in the direction you wish the graph to move. This window is located in the upper right corner of the control-panel. Along the top of the {\bf Translate} window are two buttons for selecting the direction of translation. Translation along both coordinate axes results when {\tt X On} and {\tt Y On} appear or along one axis when one is on, for example, {\tt X On} and {\tt Y Off} appear. \end{description} \subsubsection{Messages} \index{graphics!2D control-panel!messages} The window directly below the transformation potentiometer windows is used to display system messages relating to the viewport and the control-panel. The following format is displayed: \newline % \begin{center} [scaleX, scaleY] $>$graph$<$ [translateX, translateY] \newline \end{center} The two values to the left show the scale factor along the {\tt X} and {\tt Y} coordinate axes. The two values to the right show the distance of translation from the center in the {\tt X} and {\tt Y} directions. The number in the center shows which graph in the viewport this data pertains to. When multiple graphs exist in the same viewport, the graph must be selected (see ``Multiple Graphs,'' below) in order for its transformation data to be shown, otherwise the number is 1. \subsubsection{Multiple Graphs} \index{graphics!2D control-panel!multiple graphs} The {\bf Graphs} window contains buttons that allow the placement of two-di\-men\-sion\-al graphs into one of nine available slots in any other two-di\-men\-sion\-al viewport. In the center of the window are numeral buttons from one to nine that show whether a graph is displayed in the viewport. Below each number button is a button showing whether a graph that is present is selected for application of some transformation. When the caret symbol is displayed, then the graph in that slot will be manipulated. Initially, the graph for which the viewport is created occupies the first slot, is displayed, and is selected. % % \begin{description} % \item[Clear:] The {\bf Clear} button deselects every viewport graph slot. \index{graphics!2D control-panel!clear} A graph slot is reselected by selecting the button below its number. % \item[Query:] The {\bf Query} button is used to display the scale and \index{graphics!2D control-panel!query} translate data for the indicated graph. When this button is selected the message ``Click on the graph to query'' appears. Select a slot number button from the {\bf Graphs} window. The scaling factor and translation offset of the graph are then displayed in the message window. % \item[Pick:] The {\bf Pick} button is used to select a graph \index{graphics!2D control-panel!pick} to be placed or dropped into the indicated viewport. When this button is selected, the message ``Click on the graph to pick'' appears. Click on the slot with the graph number of the desired graph. The graph information is held waiting for you to execute a {\bf Drop} in some other graph. % \item[Drop:] Once a graph has been picked up using the {\bf Pick} button, \index{graphics!2D control-panel!drop} the {\bf Drop} button places it into a new viewport slot. The message ``Click on the graph to drop'' appears in the message window when the {\bf Drop} button is selected. By selecting one of the slot number buttons in the {\bf Graphs} window, the graph currently being held is dropped into this slot and displayed. \end{description} \subsubsection{Buttons} \index{graphics!2D control-panel!buttons} % \begin{description} % \item[Axes] turns the coordinate axes on or off. \index{graphics!2D control-panel!axes} % \item[Units] turns the units along the {\tt x} and {\tt y} axis on or off. \index{graphics!2D control-panel!units} % \item[Box] encloses the area of the viewport graph in a bounding box, or removes the box if already enclosed. \index{graphics!2D control-panel!box} % \item[Pts] turns on or off the display of points. \index{graphics!2D control-panel!points} % \item[Lines] turns on or off the display of lines connecting points. \index{graphics!2D control-panel!lines} % \item[PS] writes the current viewport contents to \index{graphics!2D control-panel!ps} a file {\bf axiom2D.ps} or to a name specified in the user's {\bf \index{graphics!.Xdefaults!PostScript file name} .Xdefaults} file. \index{file!.Xdefaults @{\bf .Xdefaults}} The file is placed in the directory from which Axiom or the {\bf viewAlone} program was invoked. \index{PostScript} % \item[Reset] resets the object transformation characteristics and attributes back to their initial states. \index{graphics!2D control-panel!reset} % \item[Hide] makes the control-panel disappear. \index{graphics!2D control-panel!hide} % \item[Quit] queries whether the current viewport \index{graphics!2D control-panel!quit} session should be terminated. \end{description} \subsection{Operations for Two-Dimensional Graphics} \label{ugGraphTwoDops} Here is a summary of useful Axiom operations for two-di\-men\-sion\-al graphics. Each operation name is followed by a list of arguments. Each argument is written as a variable informally named according to the type of the argument (for example, {\it integer}). If appropriate, a default value for an argument is given in parentheses immediately following the name. % \begin{description} % \item[{\bf adaptive}]\funArgs{\optArg{boolean\argDef{true}}} \index{adaptive plotting} sets or indicates whether graphs are plotted \index{graphics!set 2D defaults!adaptive} according to the adaptive refinement algorithm. % \item[{\bf axesColorDefault}]\funArgs{\optArg{color\argDef{dark blue()}}} sets or indicates the default color of the \index{graphics!set 2D defaults!axes color} axes in a two-di\-men\-sion\-al graph viewport. % \item[{\bf clipPointsDefault}]\funArgs{\optArg{boolean\argDef{false}}} sets or indicates whether point clipping is \index{graphics!set 2D defaults!clip points} to be applied as the default for graph plots. % \item[{\bf drawToScale}]\funArgs{\optArg{boolean\argDef{false}}} sets or indicates whether the plot of a graph \index{graphics!set 2D defaults!to scale} is ``to scale'' or uses the entire viewport space as the default. % \item[{\bf lineColorDefault}]\funArgs{\optArg{color\argDef{pastel yellow()}}} sets or indicates the default color of the \index{graphics!set 2D defaults!line color} lines or curves in a two-di\-men\-sion\-al graph viewport. % \item[{\bf maxPoints}]\funArgs{\optArg{integer\argDef{500}}} sets or indicates the default maximum number of \index{graphics!set 2D defaults!max points} possible points to be used when constructing a two-di\-men\-sion\-al graph. % \item[{\bf minPoints}]\funArgs{\optArg{integer\argDef{21}}} sets or indicates the default minimum number of \index{graphics!set 2D defaults!min points} possible points to be used when constructing a two-di\-men\-sion\-al graph. % \item[{\bf pointColorDefault}]\funArgs{\optArg{color\argDef{bright red()}}} sets or indicates the default color of the \index{graphics!set 2D defaults!point color} points in a two-di\-men\-sion\-al graph viewport. % \item[{\bf pointSizeDefault}]\funArgs{\optArg{integer\argDef{5}}} sets or indicates the default size of the \index{graphics!set 2D defaults!point size} dot used to plot points in a two-di\-men\-sion\-al graph. % \item[{\bf screenResolution}]\funArgs{\optArg{integer\argDef{600}}} sets or indicates the default screen \index{graphics!set 2D defaults!screen resolution} resolution constant used in setting the computation limit of adaptively \index{adaptive plotting} generated curve plots. % \item[{\bf unitsColorDefault}]\funArgs{\optArg{color\argDef{dim green()}}} sets or indicates the default color of the \index{graphics!set 2D defaults!units color} unit labels in a two-di\-men\-sion\-al graph viewport. % \item[{\bf viewDefaults}]\funArgs{} resets the default settings for the following \index{graphics!set 2D defaults!reset viewport} attributes: point color, line color, axes color, units color, point size, viewport upper left-hand corner position, and the viewport size. % \item[{\bf viewPosDefault}]\funArgs{\optArg{list\argDef{[100,100]}}} sets or indicates the default position of the \index{graphics!set 2D defaults!viewport position} upper left-hand corner of a two-di\-men\-sion\-al viewport, relative to the display root window. The upper left-hand corner of the display is considered to be at the (0, 0) position. % \item[{\bf viewSizeDefault}]\funArgs{\optArg{list\argDef{[200,200]}}} sets or indicates the default size in which two \index{graphics!set 2D defaults!viewport size} dimensional viewport windows are shown. It is defined by a width and then a height. % \item[{\bf viewWriteAvailable}] \funArgs{\optArg{list\argDef{["pixmap","bitmap", "postscript", "image"]}}} indicates the possible file types \index{graphics!2D defaults!available viewport writes} that can be created with the \spadfunFrom{write}{TwoDimensionalViewport} function. % \item[{\bf viewWriteDefault}]\funArgs{\optArg{list\argDef{[]}}} sets or indicates the default types of files, in \index{graphics!set 2D defaults!write viewport} addition to the {\bf data} file, that are created when a {\bf write} function is executed on a viewport. % \item[{\bf units}]\funArgs{viewport, integer\argDef{1}, string\argDef{"off"}} turns the units on or off for the graph with index {\it integer}. % \item[{\bf axes}]\funArgs{viewport, integer\argDef{1}, string\argDef{"on"}} turns the axes on \index{graphics!2D commands!axes} or off for the graph with index {\it integer}. % \item[{\bf close}]\funArgs{viewport} closes {\it viewport}. \index{graphics!2D commands!close} % \item[{\bf connect}]\funArgs{viewport, integer\argDef{1}, string\argDef{"on"}} declares whether lines \index{graphics!2D commands!connect} connecting the points are displayed or not. % \item[{\bf controlPanel}]\funArgs{viewport, string\argDef{"off"}} declares whether the two-di\-men\-sion\-al control-panel is automatically displayed or not. % \item[{\bf graphs}]\funArgs{viewport} returns a list \index{graphics!2D commands!graphs} describing the state of each graph. If the graph state is not being used this is shown by {\tt "undefined"}, otherwise a description of the graph's contents is shown. % \item[{\bf graphStates}]\funArgs{viewport} displays \index{graphics!2D commands!state of graphs} a list of all the graph states available for {\it viewport}, giving the values for every property. % \item[{\bf key}]\funArgs{viewport} returns the process \index{graphics!2D commands!key} ID number for {\it viewport}. % \item[{\bf move}]\funArgs{viewport, $integer_{x}$(viewPosDefault), $integer_{y}$(viewPosDefault)} moves {\it viewport} on the screen so that the \index{graphics!2D commands!move} upper left-hand corner of {\it viewport} is at the position {\it (x,y)}. % \item[{\bf options}]\funArgs{\it viewport} returns a list \index{graphics!2D commands!options} of all the {\tt DrawOption}s used by {\it viewport}. % \item[{\bf points}]\funArgs{viewport, integer\argDef{1}, string\argDef{"on"}} specifies whether the graph points for graph {\it integer} are \index{graphics!2D commands!points} to be displayed or not. % \item[{\bf region}]\funArgs{viewport, integer\argDef{1}, string\argDef{"off"}} declares whether graph {\it integer} is or is not to be displayed with a bounding rectangle. % \item[{\bf reset}]\funArgs{viewport} resets all the properties of {\it viewport}. % \item[{\bf resize}]\funArgs{viewport, $integer_{width}$,$integer_{height}$} \index{graphics!2D commands!resize} resizes {\it viewport} with a new {\it width} and {\it height}. % \item[{\bf scale}]\funArgs{viewport, $integer_{n}$\argDef{1}, $integer_{x}$\argDef{0.9}, $integer_{y}$\argDef{0.9}} scales values for the \index{graphics!2D commands!scale} {\it x} and {\it y} coordinates of graph {\it n}. % \item[{\bf show}]\funArgs{viewport, $integer_{n}$\argDef{1}, string\argDef{"on"}} indicates if graph {\it n} is shown or not. % \item[{\bf title}]\funArgs{viewport, string\argDef{"Axiom 2D"}} designates the title for {\it viewport}. % \item[{\bf translate}]\funArgs{viewport, $integer_{n}$\argDef{1}, $float_{x}$\argDef{0.0}, $float_{y}$\argDef{0.0}} \index{graphics!2D commands!translate} causes graph {\it n} to be moved {\it x} and {\it y} units in the respective directions. % \item[{\bf write}]\funArgs{viewport, $string_{directory}$, \optArg{strings}} if no third argument is given, writes the {\bf data} file onto the directory with extension {\bf data}. The third argument can be a single string or a list of strings with some or all the entries {\tt "pixmap"}, {\tt "bitmap"}, {\tt "postscript"}, and {\tt "image"}. \end{description} \subsection{Addendum: Building Two-Dimensional Graphs} \label{ugGraphTwoDbuild} In this section we demonstrate how to create two-di\-men\-sion\-al graphs from lists of points and give an example showing how to read the lists of points from a file. \subsubsection{Creating a Two-Dimensional Viewport from a List of Points} Axiom creates lists of points in a two-di\-men\-sion\-al viewport by utilizing the {\tt GraphImage} and {\tt TwoDimensionalViewport} domains. In this example, the \spadfunFrom{makeGraphImage}{GraphImage} function takes a list of lists of points parameter, a list of colors for each point in the graph, a list of colors for each line in the graph, and a list of sizes for each point in the graph. % The following expressions create a list of lists of points which will be read by Axiom and made into a two-di\-men\-sion\-al viewport. \spadcommand{p1 := point [1,1]\$(Point DFLOAT) } $$ \left[ {1.0}, {1.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p2 := point [0,1]\$(Point DFLOAT) } $$ \left[ {0.0}, {1.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p3 := point [0,0]\$(Point DFLOAT) } $$ \left[ {0.0}, {0.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p4 := point [1,0]\$(Point DFLOAT) } $$ \left[ {1.0}, {0.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p5 := point [1,.5]\$(Point DFLOAT) } $$ \left[ {1.0}, {0.5} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p6 := point [.5,0]\$(Point DFLOAT) } $$ \left[ {0.5}, {0.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p7 := point [0,0.5]\$(Point DFLOAT) } $$ \left[ {0.0}, {0.5} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p8 := point [.5,1]\$(Point DFLOAT) } $$ \left[ {0.5}, {1.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p9 := point [.25,.25]\$(Point DFLOAT) } $$ \left[ {0.25}, {0.25} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p10 := point [.25,.75]\$(Point DFLOAT) } $$ \left[ {0.25}, {0.75} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p11 := point [.75,.75]\$(Point DFLOAT) } $$ \left[ {0.75}, {0.75} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p12 := point [.75,.25]\$(Point DFLOAT) } $$ \left[ {0.75}, {0.25} \right] $$ \returnType{Type: Point DoubleFloat} Finally, here is the list. \spadcommand{llp := [ [p1,p2], [p2,p3], [p3,p4], [p4,p1], [p5,p6], [p6,p7], [p7,p8], [p8,p5], [p9,p10], [p10,p11], [p11,p12], [p12,p9] ] } $$ \left[ {\left[ {\left[ {1.0}, {1.0} \right]}, {\left[ {0.0}, {1.0} \right]} \right]}, {\left[ {\left[ {0.0}, {1.0} \right]}, {\left[ {0.0}, {0.0} \right]} \right]}, {\left[ {\left[ {0.0}, {0.0} \right]}, {\left[ {1.0}, {0.0} \right]} \right]}, {\left[ {\left[ {1.0}, {0.0} \right]}, {\left[ {1.0}, {1.0} \right]} \right]}, {\left[ {\left[ {1.0}, {0.5} \right]}, {\left[ {0.5}, {0.0} \right]} \right]}, {\left[ {\left[ {0.5}, {0.0} \right]}, {\left[ {0.0}, {0.5} \right]} \right]}, {\left[ {\left[ {0.0}, {0.5} \right]}, {\left[ {0.5}, {1.0} \right]} \right]}, {\left[ {\left[ {0.5}, {1.0} \right]}, {\left[ {1.0}, {0.5} \right]} \right]}, {\left[ {\left[ {0.25}, {0.25} \right]}, {\left[ {0.25}, {0.75} \right]} \right]}, {\left[ {\left[ {0.25}, {0.75} \right]}, {\left[ {0.75}, {0.75} \right]} \right]}, {\left[ {\left[ {0.75}, {0.75} \right]}, {\left[ {0.75}, {0.25} \right]} \right]}, {\left[ {\left[ {0.75}, {0.25} \right]}, {\left[ {0.25}, {0.25} \right]} \right]} \right] $$ \returnType{Type: List List Point DoubleFloat} Now we set the point sizes for all components of the graph. \spadcommand{size1 := 6::PositiveInteger } $$ 6 $$ \returnType{Type: PositiveInteger} \spadcommand{size2 := 8::PositiveInteger } $$ 8 $$ \returnType{Type: PositiveInteger} \spadcommand{size3 := 10::PositiveInteger } \spadcommand{lsize := [size1, size1, size1, size1, size2, size2, size2, size2, size3, size3, size3, size3] } $$ \left[ 6, 6, 6, 6, 8, 8, 8, 8, size3, size3, size3, size3 \right] $$ \returnType{Type: List Polynomial Integer} Here are the colors for the points. \spadcommand{pc1 := pastel red() } $$ [{ \mbox{\rm Hue: } 1 \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} $$ \returnType{Type: Palette} \spadcommand{pc2 := dim green() } $$ [{ \mbox{\rm Hue: } {14} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dim \mbox{\rm palette} $$ \returnType{Type: Palette} \spadcommand{pc3 := pastel yellow() } $$ [{ \mbox{\rm Hue: } {11} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} $$ \returnType{Type: Palette} \spadcommand{lpc := [pc1, pc1, pc1, pc1, pc2, pc2, pc2, pc2, pc3, pc3, pc3, pc3] } $$ \left[ {[{ \mbox{\rm Hue: } 1 \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } 1 \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } 1 \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } 1 \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {14} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dim \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {14} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dim \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {14} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dim \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {14} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dim \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {11} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {11} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {11} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {11} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} } \right] $$ \returnType{Type: List Palette} Here are the colors for the lines. \spadcommand{lc := [pastel blue(), light yellow(), dim green(), bright red(), light green(), dim yellow(), bright blue(), dark red(), pastel red(), light blue(), dim green(), light yellow()] } $$ \left[ {[{ \mbox{\rm Hue: } {22} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {11} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Light \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {14} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dim \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } 1 \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Bright \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {14} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Light \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {11} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dim \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {22} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Bright \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } 1 \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dark \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } 1 \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Pastel \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {22} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Light \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {14} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Dim \mbox{\rm palette} }, {[{ \mbox{\rm Hue: } {11} \mbox{\rm Weight: } {1.0}} \mbox{\rm ] from the } Light \mbox{\rm palette} } \right] $$ \returnType{Type: List Palette} Now the {\tt GraphImage} is created according to the component specifications indicated above. \spadcommand{g := makeGraphImage(llp,lpc,lc,lsize)\$GRIMAGE } The \spadfunFrom{makeViewport2D}{TwoDimensionalViewport} function now creates a {\tt TwoDimensionalViewport} for this graph according to the list of options specified within the brackets. \spadgraph{makeViewport2D(g,[title("Lines")])\$VIEW2D } %See Figure #.#. This example demonstrates the use of the {\tt GraphImage} functions \spadfunFrom{component}{GraphImage} and \spadfunFrom{appendPoint}{GraphImage} in adding points to an empty {\tt GraphImage}. \spadcommand{)clear all } \spadcommand{g := graphImage()\$GRIMAGE } $$ \mbox{\rm Graph with } 0 \mbox{\rm point lists} $$ \returnType{Type: GraphImage} \spadcommand{p1 := point [0,0]\$(Point DFLOAT) } $$ \left[ {0.0}, {0.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p2 := point [.25,.25]\$(Point DFLOAT) } $$ \left[ {0.25}, {0.25} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p3 := point [.5,.5]\$(Point DFLOAT) } $$ \left[ {0.5}, {0.5} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p4 := point [.75,.75]\$(Point DFLOAT) } $$ \left[ {0.75}, {0.75} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{p5 := point [1,1]\$(Point DFLOAT) } $$ \left[ {1.0}, {1.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{component(g,p1)\$GRIMAGE} \returnType{Type: Void} \spadcommand{component(g,p2)\$GRIMAGE} \returnType{Type: Void} \spadcommand{appendPoint(g,p3)\$GRIMAGE} \returnType{Type: Void} \spadcommand{appendPoint(g,p4)\$GRIMAGE} \returnType{Type: Void} \spadcommand{appendPoint(g,p5)\$GRIMAGE} \returnType{Type: Void} \spadcommand{g1 := makeGraphImage(g)\$GRIMAGE } Here is the graph. \spadgraph{makeViewport2D(g1,[title("Graph Points")])\$VIEW2D } % %See Figure #.#. % A list of points can also be made into a {\tt GraphImage} by using the operation \spadfunFrom{coerce}{GraphImage}. It is equivalent to adding each point to $g2$ using \spadfunFrom{component}{GraphImage}. \spadcommand{g2 := coerce([ [p1],[p2],[p3],[p4],[p5] ])\$GRIMAGE } Now, create an empty {\tt TwoDimensionalViewport}. \spadcommand{v := viewport2D()\$VIEW2D } \spadcommand{options(v,[title("Just Points")])\$VIEW2D } Place the graph into the viewport. \spadcommand{putGraph(v,g2,1)\$VIEW2D } Take a look. \spadgraph{makeViewport2D(v)\$VIEW2D } %See Figure #.#. \subsubsection{Creating a Two-Dimensional Viewport of a List of Points from a File} The following three functions read a list of points from a file and then draw the points and the connecting lines. The points are stored in the file in readable form as floating point numbers (specifically, {\tt DoubleFloat} values) as an alternating stream of $x$- and $y$-values. For example, \begin{verbatim} 0.0 0.0 1.0 1.0 2.0 4.0 3.0 9.0 4.0 16.0 5.0 25.0 \end{verbatim} \begin{verbatim} drawPoints(lp:List Point DoubleFloat):VIEW2D == g := graphImage()$GRIMAGE for p in lp repeat component(g,p,pointColorDefault(),lineColorDefault(), pointSizeDefault()) gi := makeGraphImage(g)$GRIMAGE makeViewport2D(gi,[title("Points")])$VIEW2D drawLines(lp:List Point DoubleFloat):VIEW2D == g := graphImage()$GRIMAGE component(g, lp, pointColorDefault(), lineColorDefault(), pointSizeDefault())$GRIMAGE gi := makeGraphImage(g)$GRIMAGE makeViewport2D(gi,[title("Points")])$VIEW2D plotData2D(name, title) == f:File(DFLOAT) := open(name,"input") lp:LIST(Point DFLOAT) := empty() while ((x := readIfCan!(f)) case DFLOAT) repeat y : DFLOAT := read!(f) lp := cons(point [x,y]$(Point DFLOAT), lp) lp close!(f) drawPoints(lp) drawLines(lp) \end{verbatim} % This command will actually create the viewport and the graph if the point data is in the file $"file.data"$. \begin{verbatim} plotData2D("file.data", "2D Data Plot") \end{verbatim} \subsection{Addendum: Appending a Graph to a Viewport Window Containing a Graph} \label{ugGraphTwoDappend} This section demonstrates how to append a two-di\-men\-sion\-al graph to a viewport already containing other graphs. The default {\bf draw} command places a graph into the first {\tt GraphImage} slot position of the {\tt TwoDimensionalViewport}. This graph is in the first slot in its viewport. \spadcommand{v1 := draw(sin(x),x=0..2*\%pi) } So is this graph. \spadcommand{v2 := draw(cos(x),x=0..2*\%pi, curveColor==light red()) } The operation \spadfunFrom{getGraph}{TwoDimensionalViewport} retrieves the {\tt GraphImage} $g1$ from the first slot position in the viewport $v1$. \spadcommand{g1 := getGraph(v1,1) } Now \spadfunFrom{putGraph}{TwoDimensionalViewport} places $g1$ into the the second slot position of $v2$. \spadcommand{putGraph(v2,g1,2) } Display the new {\tt TwoDimensionalViewport} containing both graphs. \spadgraph{makeViewport2D(v2) } % %See Figure #.#. % \section{Three-Dimensional Graphics} \label{ugGraphThreeD} % The Axiom three-di\-men\-sion\-al graphics package provides the ability to \index{graphics!three-dimensional} % \begin{itemize} % \item generate surfaces defined by a function of two real variables % \item generate space curves and tubes defined by parametric equations % \item generate surfaces defined by parametric equations \end{itemize} These graphs can be modified by using various options, such as calculating points in the spherical coordinate system or changing the polygon grid size of a surface. \subsection{Plotting Three-Dimensional Functions of Two Variables} \label{ugGraphThreeDPlot} \index{surface!two variable function} The simplest three-di\-men\-sion\-al graph is that of a surface defined by a function of two variables, $z = f(x,y)$. \boxed{4.6in}{ \vskip 0.1cm The general format for drawing a surface defined by a formula $f(x,y)$ of two variables $x$ and $y$ is: % \begin{center} {\tt draw(f(x,y), x = a..b, y = c..d, {\it options})} \end{center} where $a..b$ and $c..d$ define the range of $x$ and $y$, and where {\it options} prescribes zero or more options as described in \ref{ugGraphThreeDOptions} on page~\pageref{ugGraphThreeDOptions}. An example of an option is $title == "Title of Graph".$ An alternative format involving a function $f$ is also available.\\ } The simplest way to plot a function of two variables is to use a formula. With formulas you always precede the range specifications with the variable name and an {\tt =} sign. \spadgraph{draw(cos(x*y),x=-3..3,y=-3..3)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3D2VarA.ps} If you intend to use a function more than once, or it is long and complex, then first give its definition to Axiom. \spadcommand{f(x,y) == sin(x)*cos(y) } \returnType{Type: Void} To draw the function, just give its name and drop the variables from the range specifications. Axiom compiles your function for efficient computation of data for the graph. Notice that Axiom uses the text of your function as a default title. \spadgraph{draw(f,-\%pi..\%pi,-\%pi..\%pi) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3D2VarB.ps} \subsection{Plotting Three-Dimensional Parametric Space Curves} \label{ugGraphThreeDParm} A second kind of three-di\-men\-sion\-al graph is a three-di\-men\-sion\-al space curve \index{curve!parametric space} defined by the parametric equations for $x(t)$, $y(t)$, \index{parametric space curve} and $z(t)$ as a function of an independent variable $t$. \boxed{4.6in}{ \vskip 0.1cm The general format for drawing a three-di\-men\-sion\-al space curve defined by parametric formulas $x = f(t)$, $y = g(t)$, and $z = h(t)$ is: % \begin{center} {\tt draw(curve(f(t),g(t),h(t)), t = a..b, {\it options})} \end{center} where $a..b$ defines the range of the independent variable $t$, and where {\it options} prescribes zero or more options as described in \ref{ugGraphThreeDOptions} on page~\pageref{ugGraphThreeDOptions}. An example of an option is $title == "Title of Graph".$ An alternative format involving functions $f$, $g$ and $h$ is also available.\\ } If you use explicit formulas to draw a space curve, always precede the range specification with the variable name and an {\tt =} sign. \spadgraph{draw(curve(5*cos(t), 5*sin(t),t), t=-12..12)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DpscA.ps} Alternatively, you can draw space curves by referring to functions. \spadcommand{i1(t:DFLOAT):DFLOAT == sin(t)*cos(3*t/5) } \begin{verbatim} Function declaration i1 : DoubleFloat -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} This is useful if the functions are to be used more than once \ldots \spadcommand{i2(t:DFLOAT):DFLOAT == cos(t)*cos(3*t/5) } \begin{verbatim} Function declaration i2 : DoubleFloat -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} or if the functions are long and complex. \spadcommand{i3(t:DFLOAT):DFLOAT == cos(t)*sin(3*t/5) } \begin{verbatim} Function declaration i3 : DoubleFloat -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Give the names of the functions and drop the variable name specification in the second argument. Again, Axiom supplies a default title. \spadgraph{draw(curve(i1,i2,i3),0..15*\%pi) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DpscB.ps} \subsection{Plotting Three-Dimensional Parametric Surfaces} \label{ugGraphThreeDPar} \index{surface!parametric} A third kind of three-di\-men\-sion\-al graph is a surface defined by \index{parametric surface} parametric equations for $x(u,v)$, $y(u,v)$, and $z(u,v)$ of two independent variables $u$ and $v$. \boxed{4.6in}{ \vskip 0.1cm The general format for drawing a three-di\-men\-sion\-al graph defined by parametric formulas $x = f(u,v)$, $y = g(u,v)$, and $z = h(u,v)$ is: % \begin{center} {\tt draw(surface(f(u,v),g(u,v),h(u,v)), u = a..b, v = c..d, {\it options})} \end{center} where $a..b$ and $c..d$ define the range of the independent variables $u$ and $v$, and where {\it options} prescribes zero or more options as described in \ref{ugGraphThreeDOptions} on page~\pageref{ugGraphThreeDOptions}. An example of an option is $title == "Title of Graph".$ An alternative format involving functions $f$, $g$ and $h$ is also available.\\ } This example draws a graph of a surface plotted using the parabolic cylindrical coordinate system option. \index{coordinate system!parabolic cylindrical} The values of the functions supplied to {\bf surface} are \index{parabolic cylindrical coordinate system} interpreted in coordinates as given by a {\tt coordinates} option, here as parabolic cylindrical coordinates (see \ref{ugGraphCoord} on page~\pageref{ugGraphCoord}). \spadgraph{draw(surface(u*cos(v), u*sin(v), v*cos(u)), u=-4..4, v=0..\%pi, coordinates== parabolicCylindrical)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DpsA.ps} Again, you can graph these parametric surfaces using functions, if the functions are long and complex. Here we declare the types of arguments and values to be of type {\tt DoubleFloat}. \spadcommand{n1(u:DFLOAT,v:DFLOAT):DFLOAT == u*cos(v) } \begin{verbatim} Function declaration n1 : DoubleFloat -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} As shown by previous examples, these declarations are necessary. \spadcommand{n2(u:DFLOAT,v:DFLOAT):DFLOAT == u*sin(v) } \begin{verbatim} Function declaration n2 : DoubleFloat -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} In either case, Axiom compiles the functions when needed to graph a result. \spadcommand{n3(u:DFLOAT,v:DFLOAT):DFLOAT == u } \begin{verbatim} Function declaration n3 : DoubleFloat -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Without these declarations, you have to suffix floats with $@DFLOAT$ to get a {\tt DoubleFloat} result. However, a call here with an unadorned float produces a {\tt DoubleFloat}. \spadcommand{n3(0.5,1.0)} \begin{verbatim} Compiling function n3 with type (DoubleFloat,DoubleFloat) -> DoubleFloat \end{verbatim} \returnType{Type: DoubleFloat} Draw the surface by referencing the function names, this time choosing the toroidal coordinate system. \index{coordinate system!toroidal} \index{toroidal coordinate system} \spadgraph{draw(surface(n1,n2,n3), 1..4, 1..2*\%pi, coordinates == toroidal(1\$DFLOAT)) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DpsB.ps} \subsection{Three-Dimensional Options} \label{ugGraphThreeDOptions} \index{graphics!3D options} The {\bf draw} commands optionally take an optional list of options such as {\tt coordinates} as shown in the last example. Each option is given by the syntax: $name$ {\tt ==} $value$. Here is a list of the available options in the order that they are described below: \begin{tabular}{llll} title&coordinates&var1Steps\\ style&tubeRadius&var2Steps\\ colorFunction&tubePoints&space\\ \end{tabular} The option $title$ gives your graph a title. \index{graphics!3D options!title} \spadgraph{draw(cos(x*y),x=0..2*\%pi,y=0..\%pi,title == "Title of Graph") } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptTtl.ps} The $style$ determines which of four rendering algorithms is used for \index{rendering} the graph. The choices are {\tt "wireMesh"}, {\tt "solid"}, {\tt "shade"}, and {\tt "smooth"}. \spadgraph{draw(cos(x*y),x=-3..3,y=-3..3, style=="smooth", title=="Smooth Option")} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptSty.ps} In all but the wire-mesh style, polygons in a surface or tube plot are normally colored in a graph according to their $z$-coordinate value. Space curves are colored according to their parametric variable value. \index{graphics!3D options!color function} To change this, you can give a coloring function. \index{function!coloring} The coloring function is sampled across the range of its arguments, then normalized onto the standard Axiom colormap. A function of one variable makes the color depend on the value of the parametric variable specified for a tube plot. \spadcommand{color1(t) == t } \returnType{Type: Void} \spadgraph{draw(curve(sin(t), cos(t),0), t=0..2*\%pi, tubeRadius == .3, colorFunction == color1) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptCf1.ps} A function of two variables makes the color depend on the values of the independent variables. \spadcommand{color2(u,v) == u**2 - v**2 } \returnType{Type: Void} Use the option {\tt colorFunction} for special coloring. \spadgraph{draw(cos(u*v), u=-3..3, v=-3..3, colorFunction == color2) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptCf2.ps} With a three variable function, the color also depends on the value of the function. \spadcommand{color3(x,y,fxy) == sin(x*fxy) + cos(y*fxy) } \returnType{Type: Void} \spadgraph{draw(cos(x*y), x=-3..3, y=-3..3, colorFunction == color3) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptCf3.ps} Normally the Cartesian coordinate system is used. \index{Cartesian!coordinate system} To change this, use the {\tt coordinates} option. \index{coordinate system!Cartesian} For details, see \ref{ugGraphCoord} on page~\pageref{ugGraphCoord}. \spadcommand{m(u:DFLOAT,v:DFLOAT):DFLOAT == 1 } \begin{verbatim} Function declaration m : (DoubleFloat,DoubleFloat) -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Use the spherical \index{spherical coordinate system} coordinate system. \index{coordinate system!spherical} \spadgraph{draw(m, 0..2*\%pi,0..\%pi, coordinates == spherical, style=="shade") } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptCrd.ps} Space curves may be displayed as tubes with polygonal cross sections. \index{tube} Two options, {\tt tubeRadius} and {\tt tubePoints}, control the size and shape of this cross section. % The {\tt tubeRadius} option specifies the radius of the tube that \index{tube!radius} encircles the specified space curve. \spadgraph{draw(curve(sin(t),cos(t),0),t=0..2*\%pi, style=="shade", tubeRadius == .3)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptRad.ps} The {\tt tubePoints} option specifies the number of vertices \index{tube!points in polygon} defining the polygon that is used to create a tube around the specified space curve. The larger this number is, the more cylindrical the tube becomes. \spadgraph{draw(curve(sin(t), cos(t), 0), t=0..2*\%pi, style=="shade", tubeRadius == .25, tubePoints == 3)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptPts.ps} \index{graphics!3D options!variable steps} % Options \spadfunFrom{var1Steps}{DrawOption} and \spadfunFrom{var2Steps}{DrawOption} specify the number of intervals into which the grid defining a surface plot is subdivided with respect to the first and second parameters of the surface function(s). \spadgraph{draw(cos(x*y),x=-3..3,y=-3..3, style=="shade", var1Steps == 30, var2Steps == 30)} % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DOptvB.ps} The {\tt space} option of a {\bf draw} command lets you build multiple graphs in three space. To use this option, first create an empty three-space object, then use the {\tt space} option thereafter. There is no restriction as to the number or kinds of graphs that can be combined this way. Create an empty three-space object. \spadcommand{s := create3Space()\$(ThreeSpace DFLOAT) } $$ {3-Space with }0 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{m(u:DFLOAT,v:DFLOAT):DFLOAT == 1 } \begin{verbatim} Function declaration m : (DoubleFloat,DoubleFloat) -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Add a graph to this three-space object. The new graph destructively inserts the graph into $s$. \spadgraph{draw(m,0..\%pi,0..2*\%pi, coordinates == spherical, space == s) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3Dmult1A.ps} Add a second graph to $s$. \spadgraph{v := draw(curve(1.5*sin(t), 1.5*cos(t),0), t=0..2*\%pi, tubeRadius == .25, space == s) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3Dmult1B.ps} A three-space object can also be obtained from an existing three-di\-men\-sion\-al viewport using the \spadfunFrom{subspace}{ThreeSpace} command. You can then use {\bf makeViewport3D} to create a viewport window. Assign to $subsp$ the three-space object in viewport $v$. \spadcommand{subsp := subspace v } Reset the space component of $v$ to the value of $subsp$. \spadcommand{subspace(v, subsp) } Create a viewport window from a three-space object. \spadgraph{makeViewport3D(subsp,"Graphs") } \subsection{The makeObject Command} \label{ugGraphMakeObject} An alternate way to create multiple graphs is to use {\bf makeObject}. The {\bf makeObject} command is similar to the {\bf draw} command, except that it returns a three-space object rather than a {\tt ThreeDimensionalViewport}. In fact, {\bf makeObject} is called by the {\bf draw} command to create the {\tt ThreeSpace} then \spadfunFrom{makeViewport3D}{ThreeDimensionalViewport} to create a viewport window. \spadcommand{m(u:DFLOAT,v:DFLOAT):DFLOAT == 1 } \begin{verbatim} Function declaration m : (DoubleFloat,DoubleFloat) -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Do the last example a new way. First use {\bf makeObject} to create a three-space object $sph$. \spadcommand{sph := makeObject(m, 0..\%pi, 0..2*\%pi, coordinates==spherical)} \begin{verbatim} Compiling function m with type (DoubleFloat,DoubleFloat) -> DoubleFloat \end{verbatim} $$ {3-Space with }1 \mbox{\rm component} $$ \returnType{Type: ThreeSpace DoubleFloat} Add a second object to $sph$. \spadcommand{makeObject(curve(1.5*sin(t), 1.5*cos(t), 0), t=0..2*\%pi, space == sph, tubeRadius == .25) } \begin{verbatim} Compiling function %D with type DoubleFloat -> DoubleFloat Compiling function %F with type DoubleFloat -> DoubleFloat Compiling function %H with type DoubleFloat -> DoubleFloat \end{verbatim} $$ {3-Space with }2 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} Create and display a viewport containing $sph$. \spadgraph{makeViewport3D(sph,"Multiple Objects") } Note that an undefined {\tt ThreeSpace} parameter declared in a {\bf makeObject} or {\bf draw} command results in an error. Use the \spadfunFrom{create3Space}{ThreeSpace} function to define a {\tt ThreeSpace}, or obtain a {\tt ThreeSpace} that has been previously generated before including it in a command line. \subsection{Building Three-Dimensional Objects From Primitives} \label{ugGraphThreeDBuild} Rather than using the {\bf draw} and {\bf makeObject} commands, \index{graphics!advanced!build 3D objects} you can create three-di\-men\-sion\-al graphs from primitives. Operation \spadfunFrom{create3Space}{ThreeSpace} creates a three-space object to which points, curves and polygons can be added using the operations from the {\tt ThreeSpace} domain. The resulting object can then be displayed in a viewport using \spadfunFrom{makeViewport3D}{ThreeDimensionalViewport}. Create the empty three-space object $space$. \spadcommand{space := create3Space()\$(ThreeSpace DFLOAT) } $$ {3-Space with }0 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} Objects can be sent to this $space$ using the operations exported by the {\tt ThreeSpace} domain. \index{ThreeSpace} The following examples place curves into $space$. Add these eight curves to the space. \spadcommand{closedCurve(space,[ [0,30,20], [0,30,30], [0,40,30], [0,40,100], [0,30,100],[0,30,110], [0,60,110], [0,60,100], [0,50,100], [0,50,30], [0,60,30], [0,60,20] ]) } $$ {3-Space with }1 \mbox{\rm component} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{closedCurve(space,[ [80,0,30], [80,0,100], [70,0,110], [40,0,110], [30,0,100], [30,0,90], [40,0,90], [40,0,95], [45,0,100], [65,0,100], [70,0,95], [70,0,35] ]) } $$ {3-Space with }2 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{closedCurve(space,[ [70,0,35], [65,0,30], [45,0,30], [40,0,35], [40,0,60], [50,0,60], [50,0,70], [30,0,70], [30,0,30], [40,0,20], [70,0,20], [80,0,30] ]) } $$ {3-Space with }3 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{closedCurve(space,[ [0,70,20], [0,70,110], [0,110,110], [0,120,100], [0,120,70], [0,115,65], [0,120,60], [0,120,30], [0,110,20], [0,80,20], [0,80,30], [0,80,20] ]) } $$ {3-Space with }4 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{closedCurve(space,[ [0,105,30], [0,110,35], [0,110,55], [0,105,60], [0,80,60], [0,80,70], [0,105,70], [0,110,75], [0,110,95], [0,105,100], [0,80,100], [0,80,20], [0,80,30] ]) } $$ {3-Space with }5 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{closedCurve(space,[ [140,0,20], [140,0,110], [130,0,110], [90,0,20], [101,0,20],[114,0,50], [130,0,50], [130,0,60], [119,0,60], [130,0,85], [130,0,20] ]) } $$ {3-Space with }6 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{closedCurve(space,[ [0,140,20], [0,140,110], [0,150,110], [0,170,50], [0,190,110], [0,200,110], [0,200,20], [0,190,20], [0,190,75], [0,175,35], [0,165,35],[0,150,75], [0,150,20] ]) } $$ {3-Space with }7 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{closedCurve(space,[ [200,0,20], [200,0,110], [189,0,110], [160,0,45], [160,0,110], [150,0,110], [150,0,20], [161,0,20], [190,0,85], [190,0,20] ]) } $$ {3-Space with }8 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} Create and display the viewport using {\bf makeViewport3D}. Options may also be given but here are displayed as a list with values enclosed in parentheses. \spadgraph{makeViewport3D(space, title == "Letters") } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DBuildA.ps} \subsubsection{Cube Example} As a second example of the use of primitives, we generate a cube using a polygon mesh. It is important to use a consistent orientation of the polygons for correct generation of three-di\-men\-sion\-al objects. Again start with an empty three-space object. \spadcommand{spaceC := create3Space()\$(ThreeSpace DFLOAT) } $$ {3-Space with }0 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} For convenience, give {\tt DoubleFloat} values $+1$ and $-1$ names. \spadcommand{x: DFLOAT := 1 } $$ 1.0 $$ \returnType{Type: DoubleFloat} \spadcommand{y: DFLOAT := -1 } $$ -{1.0} $$ \returnType{Type: DoubleFloat} Define the vertices of the cube. \spadcommand{a := point [x,x,y,1::DFLOAT]\$(Point DFLOAT) } $$ \left[ {1.0}, {1.0}, -{1.0}, {1.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{b := point [y,x,y,4::DFLOAT]\$(Point DFLOAT) } $$ \left[ -{1.0}, {1.0}, -{1.0}, {4.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{c := point [y,x,x,8::DFLOAT]\$(Point DFLOAT) } $$ \left[ -{1.0}, {1.0}, {1.0}, {8.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{d := point [x,x,x,12::DFLOAT]\$(Point DFLOAT) } $$ \left[ {1.0}, {1.0}, {1.0}, {12.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{e := point [x,y,y,16::DFLOAT]\$(Point DFLOAT) } $$ \left[ {1.0}, -{1.0}, -{1.0}, {16.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{f := point [y,y,y,20::DFLOAT]\$(Point DFLOAT) } $$ \left[ -{1.0}, -{1.0}, -{1.0}, {20.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{g := point [y,y,x,24::DFLOAT]\$(Point DFLOAT) } $$ \left[ -{1.0}, -{1.0}, {1.0}, {24.0} \right] $$ \returnType{Type: Point DoubleFloat} \spadcommand{h := point [x,y,x,27::DFLOAT]\$(Point DFLOAT) } $$ \left[ {1.0}, -{1.0}, {1.0}, {27.0} \right] $$ \returnType{Type: Point DoubleFloat} Add the faces of the cube as polygons to the space using a consistent orientation. \spadcommand{polygon(spaceC,[d,c,g,h]) } $$ {3-Space with }1 \mbox{\rm component} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{polygon(spaceC,[d,h,e,a]) } $$ {3-Space with }2 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{polygon(spaceC,[c,d,a,b]) } $$ {3-Space with }3 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{polygon(spaceC,[g,c,b,f]) } $$ {3-Space with }4 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{polygon(spaceC,[h,g,f,e]) } $$ {3-Space with }5 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} \spadcommand{polygon(spaceC,[e,f,b,a]) } $$ {3-Space with }6 \mbox{\rm components} $$ \returnType{Type: ThreeSpace DoubleFloat} Create and display the viewport. \spadgraph{makeViewport3D(spaceC, title == "Cube") } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/3DBuildB.ps} \subsection{Coordinate System Transformations} \label{ugGraphCoord} \index{graphics!advanced!coordinate systems} The {\tt CoordinateSystems} package provides coordinate transformation functions that map a given data point from the coordinate system specified into the Cartesian coordinate system. \index{CoordinateSystems} The default coordinate system, given a triplet $(f(u,v), u, v)$, assumes that $z = f(u, v)$, $x = u$ and $y = v$, that is, reads the coordinates in $(z, x, y)$ order. \spadcommand{m(u:DFLOAT,v:DFLOAT):DFLOAT == u**2 } \begin{verbatim} Function declaration m : (DoubleFloat,DoubleFloat) -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Graph plotted in default coordinate system. \spadgraph{draw(m,0..3,0..5) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/defcoord.ps} The $z$ coordinate comes first since the first argument of the {\bf draw} command gives its values. In general, the coordinate systems Axiom provides, or any that you make up, must provide a map to an $(x, y, z)$ triplet in order to be compatible with the \spadfunFrom{coordinates}{DrawOption} {\tt DrawOption}. \index{DrawOption} Here is an example. Define the identity function. \spadcommand{cartesian(point:Point DFLOAT):Point DFLOAT == point } \begin{verbatim} Function declaration cartesian : Point DoubleFloat -> Point DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Pass $cartesian$ as the \spadfunFrom{coordinates}{DrawOption} parameter to the {\bf draw} command. \spadgraph{draw(m,0..3,0..5,coordinates==cartesian) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/cartcoord.ps} What happened? The option {\tt coordinates == cartesian} directs Axiom to treat the dependent variable $m$ defined by $m=u^2$ as the $x$ coordinate. Thus the triplet of values $(m, u, v)$ is transformed to coordinates $(x, y, z)$ and so we get the graph of $x=y^2$. Here is another example. The \spadfunFrom{cylindrical}{CoordinateSystems} transform takes \index{coordinate system!cylindrical} input of the form $(w,u,v)$, interprets it in the order \index{cylindrical coordinate system} ($r$,$\theta$,$z$) and maps it to the Cartesian coordinates $x=r\cos(\theta)$, $y=r\sin(\theta)$, $z=z$ in which $r$ is the radius, $\theta$ is the angle and $z$ is the z-coordinate. An example using the \spadfunFrom{cylindrical}{CoordinateSystems} coordinates for the constant $r = 3$. \spadcommand{f(u:DFLOAT,v:DFLOAT):DFLOAT == 3 } \begin{verbatim} Function declaration f : (DoubleFloat,DoubleFloat) -> DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} Graph plotted in cylindrical coordinates. \spadgraph{draw(f,0..\%pi,0..6,coordinates==cylindrical) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/cylCoord.ps} Suppose you would like to specify $z$ as a function of $r$ and $\theta$ instead of just $r$? Well, you still can use the {\bf cylindrical} Axiom transformation but we have to reorder the triplet before passing it to the transformation. First, let's create a point to work with and call it $pt$ with some color $col$. \spadcommand{col := 5 } $$ 5 $$ \returnType{Type: PositiveInteger} \spadcommand{pt := point[1,2,3,col]\$(Point DFLOAT) } $$ \left[ {1.0}, {2.0}, {3.0}, {5.0} \right] $$ \returnType{Type: Point DoubleFloat} The reordering you want is $(z,r, \theta)$ to $(r, \theta,z)$ so that the first element is moved to the third element, while the second and third elements move forward and the color element does not change. Define a function {\bf reorder} to reorder the point elements. \spadcommand{reorder(p:Point DFLOAT):Point DFLOAT == point[p.2, p.3, p.1, p.4] } \begin{verbatim} Function declaration reorder : Point DoubleFloat -> Point DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} The function moves the second and third elements forward but the color does not change. \spadcommand{reorder pt } $$ \left[ {2.0}, {3.0}, {1.0}, {5.0} \right] $$ \returnType{Type: Point DoubleFloat} The function {\bf newmap} converts our reordered version of the cylindrical coordinate system to the standard $(x,y,z)$ Cartesian system. \spadcommand{newmap(pt:Point DFLOAT):Point DFLOAT == cylindrical(reorder pt) } \begin{verbatim} Function declaration newmap : Point DoubleFloat -> Point DoubleFloat has been added to workspace. \end{verbatim} \returnType{Type: Void} \spadcommand{newmap pt } $$ \left[ -{1.9799849932008908}, {0.28224001611973443}, {1.0}, {5.0} \right] $$ \returnType{Type: Point DoubleFloat} Graph the same function $f$ using the coordinate mapping of the function $newmap$, so it is now interpreted as $z=3$: \spadgraph{draw(f,0..3,0..2*\%pi,coordinates==newmap) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/newmap.ps} % I think this is good to say here: it shows a lot of depth. RSS {\sloppy The {\tt CoordinateSystems} package exports the following \index{coordinate system} operations: {\bf bipolar}, {\bf bipolarCylindrical}, {\bf cartesian}, {\bf conical}, {\bf cylindrical}, {\bf elliptic}, {\bf ellipticCylindrical}, {\bf oblateSpheroidal}, {\bf parabolic}, {\bf parabolicCylindrical}, {\bf paraboloidal}, {\bf polar}, {\bf prolateSpheroidal}, {\bf spherical}, and {\bf toroidal}. Use Browse or the {\tt )show} system command \index{show} to get more information. \subsection{Three-Dimensional Clipping} \label{ugGraphClip} A three-di\-men\-sion\-al graph can be explicitly clipped within the {\bf draw} \index{graphics!advanced!clip} command by indicating a minimum and maximum threshold for the \index{clipping} given function definition. These thresholds can be defined using the Axiom {\bf min} and {\bf max} functions. \begin{verbatim} gamma(x,y) == g := Gamma complex(x,y) point [x, y, max( min(real g, 4), -4), argument g] \end{verbatim} Here is an example that clips the gamma function in order to eliminate the extreme divergence it creates. \spadgraph{draw(gamma,-\%pi..\%pi,-\%pi..\%pi,var1Steps==50,var2Steps==50) } % window was 300 x 300 %\epsffile[0 0 295 295]{ps/clipGamma.ps} \subsection{Three-Dimensional Control-Panel} \label{ugGraphThreeDControl} \index{graphics!3D control-panel} Once you have created a viewport, move your mouse to the viewport and click with your left mouse button. This displays a control-panel on the side of the viewport that is closest to where you clicked. \begin{figure}[htbp] %{\epsfverbosetrue\epsfxsize=2in% %\def\epsfsize#1#2{\epsfxsize}\hspace*{\baseLeftSkip}% %%\epsffile[0 0 144 289]{ps/3Dctrl.ps}} \begin{picture}(183,252)%(-125,0) \hspace*{\baseLeftSkip}\special{psfile=ps/3Dctrl.ps} \end{picture} \caption{Three-dimensional control-panel.} \end{figure} \subsubsection{Transformations} We recommend you first select the {\bf Bounds} button while \index{graphics!3D control-panel!transformations} executing transformations since the bounding box displayed indicates the object's position as it changes. % \begin{description} % \item[Rotate:] A rotation transformation occurs by clicking the mouse \index{graphics!3D control-panel!rotate} within the {\bf Rotate} window in the upper left corner of the control-panel. The rotation is computed in spherical coordinates, using the horizontal mouse position to increment or decrement the value of the longitudinal angle $\theta$ within the range of 0 to 2$\pi$ and the vertical mouse position to increment or decrement the value of the latitudinal angle $\phi$ within the range of -$\pi$ to $\pi$. The active mode of rotation is displayed in green on a color monitor or in clear text on a black and white monitor, while the inactive mode is displayed in red for color display or a mottled pattern for black and white. % \begin{description} % \item[origin:] The {\bf origin} button indicates that the rotation is to occur with respect to the origin of the viewing space, that is indicated by the axes. % \item[object:] The {\bf object} button indicates that the rotation is to occur with respect to the center of volume of the object, independent of the axes' origin position. \end{description} % \item[Scale:] A scaling transformation occurs by clicking the mouse \index{graphics!3D control-panel!scale} within the {\bf Scale} window in the upper center of the control-panel, containing a zoom arrow. The axes along which the scaling is to occur are indicated by selecting the appropriate button above the zoom arrow window. The selected axes are displayed in green on a color monitor or in clear text on a black and white monitor, while the unselected axes are displayed in red for a color display or a mottled pattern for black and white. % \begin{description} % \item[uniform:] Uniform scaling along the {\tt x}, {\tt y} and {\tt z} axes occurs when all the axes buttons are selected. % \item[non-uniform:] If any of the axes buttons are not selected, non-uniform scaling occurs, that is, scaling occurs only in the direction of the axes that are selected. \end{description} % \item[Translate:] Translation occurs by indicating with the mouse in the \index{graphics!3D control-panel!translate} {\bf Translate} window the direction you want the graph to move. This window is located in the upper right corner of the control-panel and contains a potentiometer with crossed arrows pointing up, down, left and right. Along the top of the {\bf Translate} window are three buttons ({\bf XY}, {\bf XZ}, and {\bf YZ}) indicating the three orthographic projection planes. Each orientates the group as a view into that plane. Any translation of the graph occurs only along this plane. \end{description} \subsubsection{Messages} \index{graphics!3D control-panel!messages} The window directly below the potentiometer windows for transformations is used to display system messages relating to the viewport, the control-panel and the current graph displaying status. \subsubsection{Colormap} \index{graphics!3D control-panel!color map} Directly below the message window is the colormap range indicator window. \index{colormap} The Axiom Colormap shows a sampling of the spectrum from which hues can be drawn to represent the colors of a surface. The Colormap is composed of five shades for each of the hues along this spectrum. By moving the markers above and below the Colormap, the range of hues that are used to color the existing surface are set. The bottom marker shows the hue for the low end of the color range and the top marker shows the hue for the upper end of the range. Setting the bottom and top markers at the same hue results in monochromatic smooth shading of the graph when {\bf Smooth} mode is selected. At each end of the Colormap are {\bf +} and {\bf -} buttons. When clicked on, these increment or decrement the top or bottom marker. \subsubsection{Buttons} \index{graphics!3D control-panel!buttons} Below the Colormap window and to the left are located various buttons that determine the characteristics of a graph. The buttons along the bottom and right hand side all have special meanings; the remaining buttons in the first row indicate the mode or style used to display the graph. The second row are toggles that turn on or off a property of the graph. On a color monitor, the property is on if green (clear text, on a monochrome monitor) and off if red (mottled pattern, on a monochrome monitor). Here is a list of their functions. % \begin{description} % \item[Wire] displays surface and tube plots as a \index{graphics!3D control-panel!wire} wireframe image in a single color (blue) with no hidden surfaces removed, or displays space curve plots in colors based upon their parametric variables. This is the fastest mode for displaying a graph. This is very useful when you want to find a good orientation of your graph. % \item[Solid] displays the graph with hidden \index{graphics!3D control-panel!solid} surfaces removed, drawing each polygon beginning with the furthest from the viewer. The edges of the polygons are displayed in the hues specified by the range in the Colormap window. % \item[Shade] displays the graph with hidden \index{graphics!3D control-panel!shade} surfaces removed and with the polygons shaded, drawing each polygon beginning with the furthest from the viewer. Polygons are shaded in the hues specified by the range in the Colormap window using the Phong illumination model. \index{Phong!illumination model} % \item[Smooth] displays the graph using a \index{graphics!3D control-panel!smooth} renderer that computes the graph one line at a time. The location and color of the graph at each visible point on the screen are determined and displayed using the Phong illumination \index{Phong!illumination model} model. Smooth shading is done in one of two ways, depending on the range selected in the colormap window and the number of colors available from the hardware and/or window manager. When the top and bottom markers of the colormap range are set to different hues, the graph is rendered by dithering between the \index{dithering} transitions in color hue. When the top and bottom markers of the colormap range are set to the same hue, the graph is rendered using the Phong smooth shading model. \index{Phong!smooth shading model} However, if enough colors cannot be allocated for this purpose, the renderer reverts to the color dithering method until a sufficient color supply is available. For this reason, it may not be possible to render multiple Phong smooth shaded graphs at the same time on some systems. % \item[Bounds] encloses the entire volume of the viewgraph within a bounding box, or removes the box if previously selected. \index{graphics!3D control-panel!bounds} The region that encloses the entire volume of the viewport graph is displayed. % \item[Axes] displays Cartesian \index{graphics!3D control-panel!axes} coordinate axes of the space, or turns them off if previously selected. % \item[Outline] causes \index{graphics!3D control-panel!outline} quadrilateral polygons forming the graph surface to be outlined in black when the graph is displayed in {\bf Shade} mode. % \item[BW] converts a color viewport to black and white, or vice-versa. \index{graphics!3D control-panel!bw} When this button is selected the control-panel and viewport switch to an immutable colormap composed of a range of grey scale patterns or tiles that are used wherever shading is necessary. % \item[Light] takes you to a control-panel described below. % \item[ViewVolume] takes you to another control-panel as described below. \index{graphics!3D control-panel!save} % \item[Save] creates a menu of the possible file types that can be written using the control-panel. The {\bf Exit} button leaves the save menu. The {\bf Pixmap} button writes an Axiom pixmap of \index{graphics!3D control-panel!pixmap} the current viewport contents. The file is called {\bf axiom3D.pixmap} and is located in the directory from which Axiom or {\bf viewAlone} was started. The {\bf PS} button writes the current viewport contents to \index{graphics!3D control-panel!ps} PostScript output rather than to the viewport window. By default the file is called {\bf axiom3D.ps}; however, if a file \index{file!.Xdefaults @{\bf .Xdefaults}} name is specified in the user's {\bf .Xdefaults} file it is \index{graphics!.Xdefaults!PostScript file name} used. The file is placed in the directory from which the Axiom or {\bf viewAlone} session was begun. See also the \spadfunFrom{write}{ThreeDimensionalViewport} function. \index{PostScript} % \item[Reset] returns the object transformation \index{graphics!3D control-panel!reset} characteristics back to their initial states. % \item[Hide] causes the control-panel for the \index{graphics!3D control-panel!hide} corresponding viewport to disappear from the screen. % \item[Quit] queries whether the current viewport \index{graphics!3D control-panel!quit} session should be terminated. \end{description} \subsubsection{Light} \index{graphics!3D control-panel!light} %>>>\begin{figure}[htbp] %>>>\begin{picture}(183,252)(-125,0) %>>>\special{psfile=ps/3Dlight.ps} %>>>\end{picture} %>>>\caption{Three-Dimensional Lighting Panel.} %>>>\end{figure} The {\bf Light} button changes the control-panel into the {\bf Lighting Control-Panel}. At the top of this panel, the three axes are shown with the same orientation as the object. A light vector from the origin of the axes shows the current position of the light source relative to the object. At the bottom of the panel is an {\bf Abort} button that cancels any changes to the lighting that were made, and a {\bf Return} button that carries out the current set of lighting changes on the graph. % \begin{description} % \item[XY:] The {\bf XY} lighting axes window is below the \index{graphics!3D control-panel!move xy} {\bf Lighting Control-Panel} title and to the left. This changes the light vector within the {\bf XY} view plane. % \item[Z:] The {\bf Z} lighting axis window is below the \index{graphics!3D control-panel!move z} {\bf Lighting Control-Panel} title and in the center. This changes the {\bf Z} location of the light vector. % \item[Intensity:] Below the {\bf Lighting Control-Panel} title \index{graphics!3D control-panel!intensity} and to the right is the light intensity meter. Moving the intensity indicator down decreases the amount of light emitted from the light source. When the indicator is at the top of the meter the light source is emitting at 100\% intensity. At the bottom of the meter the light source is emitting at a level slightly above ambient lighting. \end{description} \subsubsection{View Volume} \index{graphics!3D control-panel!view volume} The {\bf View Volume} button changes the control-panel into the {\bf Viewing Volume Panel}. At the bottom of the viewing panel is an {\bf Abort} button that cancels any changes to the viewing volume that were made and a {\it Return} button that carries out the current set of viewing changes to the graph. % %>>>\begin{figure}[htbp] %>>>\begin{picture}(183,252)(-125,0) %>>>\special{psfile=ps/3Dvolume.ps} %>>>\end{picture} %>>>\caption{Three-Dimensional Volume Panel.} %>>>\end{figure} \begin{description} \item[Eye Reference:] At the top of this panel is the \index{graphics!3D control-panel!eye reference} {\bf Eye Reference} window. It shows a planar projection of the viewing pyramid from the eye of the viewer relative to the location of the object. This has a bounding region represented by the rectangle on the left. Below the object rectangle is the {\bf Hither} window. By moving the slider in this window the hither clipping plane sets \index{hither clipping plane} the front of the view volume. As a result of this depth clipping all points of the object closer to the eye than this hither plane are not shown. The {\bf Eye Distance} slider to the right of the {\bf Hither} slider is used to change the degree of perspective in the image. % \item[Clip Volume:] The {\bf Clip Volume} window is at the \index{graphics!3D control-panel!clip volume} bottom of the {\bf Viewing Volume Panel}. On the right is a {\bf Settings} menu. In this menu are buttons to select viewing attributes. Selecting the {\bf Perspective} button computes the image using perspective projection. \index{graphics!3D control-panel!perspective} The {\bf Show Region} button indicates whether the clipping region of the \index{graphics!3D control-panel!show clip region} volume is to be drawn in the viewport and the {\bf Clipping On} button shows whether the view volume clipping is to be in effect when the image \index{graphics!3D control-panel!clipping on} is drawn. The left side of the {\bf Clip Volume} window shows the clipping \index{graphics!3D control-panel!clip volume} boundary of the graph. Moving the knobs along the {\bf X}, {\bf Y}, and {\bf Z} sliders adjusts the volume of the clipping region accordingly. \end{description} \subsection{Operations for Three-Dimensional Graphics} \label{ugGraphThreeDops} Here is a summary of useful Axiom operations for three-di\-men\-sion\-al graphics. Each operation name is followed by a list of arguments. Each argument is written as a variable informally named according to the type of the argument (for example, {\it integer}). If appropriate, a default value for an argument is given in parentheses immediately following the name. % \bgroup\hbadness = 10001\sloppy \begin{description} % \item[{\bf adaptive3D?}]\funArgs{} tests whether space curves are to be plotted \index{graphics!plot3d defaults!adaptive} according to the \index{adaptive plotting} adaptive refinement algorithm. % \item[{\bf axes}]\funArgs{viewport, string\argDef{"on"}} turns the axes on and off. \index{graphics!3D commands!axes} % \item[{\bf close}]\funArgs{viewport} closes the viewport. \index{graphics!3D commands!close} % \item[{\bf colorDef}]\funArgs{viewport, $\hbox{\it color}_{1}$\argDef{1}, $\hbox{\it color}_{2}$\argDef{27}} sets the colormap \index{graphics!3D commands!define color} range to be from $\hbox{\it color}_{1}$ to $\hbox{\it color}_{2}$. % \item[{\bf controlPanel}]\funArgs{viewport, string\argDef{"off"}} declares whether the \index{graphics!3D commands!control-panel} control-panel for the viewport is to be displayed or not. % \item[{\bf diagonals}]\funArgs{viewport, string\argDef{"off"}} declares whether the \index{graphics!3D commands!diagonals} polygon outline includes the diagonals or not. % \item[{\bf drawStyle}]\funArgs{viewport, style} selects which of four drawing styles \index{graphics!3D commands!drawing style} are used: {\tt "wireMesh", "solid", "shade",} or {\tt "smooth".} % \item[{\bf eyeDistance}]\funArgs{viewport,float\argDef{500}} sets the distance of the eye from the origin of the object \index{graphics!3D commands!eye distance} for use in the \spadfunFrom{perspective}{ThreeDimensionalViewport}. % \item[{\bf key}]\funArgs{viewport} returns the operating \index{graphics!3D commands!key} system process ID number for the viewport. % \item[{\bf lighting}]\funArgs{viewport, $float_{x}$\argDef{-0.5}, $float_{y}$\argDef{0.5}, $float_{z}$\argDef{0.5}} sets the Cartesian \index{graphics!3D commands!lighting} coordinates of the light source. % \item[{\bf modifyPointData}]\funArgs{viewport,integer,point} replaces the coordinates of the point with \index{graphics!3D commands!modify point data} the index {\it integer} with {\it point}. % \item[{\bf move}]\funArgs{viewport, $integer_{x}$\argDef{viewPosDefault}, $integer_{y}$\argDef{viewPosDefault}} moves the upper \index{graphics!3D commands!move} left-hand corner of the viewport to screen position \allowbreak ({\small $integer_{x}$, $integer_{y}$}). % \item[{\bf options}]\funArgs{viewport} returns a list of all current draw options. % \item[{\bf outlineRender}]\funArgs{viewport, string\argDef{"off"}} turns polygon outlining \index{graphics!3D commands!outline} off or on when drawing in {\tt "shade"} mode. % \item[{\bf perspective}]\funArgs{viewport, string\argDef{"on"}} turns perspective \index{graphics!3D commands!perspective} viewing on and off. % \item[{\bf reset}]\funArgs{viewport} resets the attributes of a viewport to their \index{graphics!3D commands!reset} initial settings. % \item[{\bf resize}]\funArgs{viewport, $integer_{width}$ \argDef{viewSizeDefault}, $integer_{height}$ \argDef{viewSizeDefault}} resets the width and height \index{graphics!3D commands!resize} values for a viewport. % \item[{\bf rotate}]\funArgs{viewport, $number_{\theta}$\argDef{viewThetaDefapult}, $number_{\phi}$\argDef{viewPhiDefault}} rotates the viewport by rotation angles for longitude ({\it $\theta$}) and latitude ({\it $\phi$}). Angles designate radians if given as floats, or degrees if given \index{graphics!3D commands!rotate} as integers. % \item[{\bf setAdaptive3D}]\funArgs{boolean\argDef{true}} sets whether space curves are to be plotted \index{graphics!plot3d defaults!set adaptive} according to the adaptive \index{adaptive plotting} refinement algorithm. % \item[{\bf setMaxPoints3D}]\funArgs{integer\argDef{1000}} sets the default maximum number of possible \index{graphics!plot3d defaults!set max points} points to be used when constructing a three-di\-men\-sion\-al space curve. % \item[{\bf setMinPoints3D}]\funArgs{integer\argDef{49}} sets the default minimum number of possible \index{graphics!plot3d defaults!set min points} points to be used when constructing a three-di\-men\-sion\-al space curve. % \item[{\bf setScreenResolution3D}]\funArgs{integer\argDef{49}} sets the default screen resolution constant \index{graphics!plot3d defaults!set screen resolution} used in setting the computation limit of adaptively \index{adaptive plotting} generated three-di\-men\-sion\-al space curve plots. % \item[{\bf showRegion}]\funArgs{viewport, string\argDef{"off"}} declares whether the bounding \index{graphics!3D commands!showRegion} box of a graph is shown or not. % \item[{\bf subspace}]\funArgs{viewport} returns the space component. % \item[{\bf subspace}]\funArgs{viewport, subspace} resets the space component \index{graphics!3D commands!subspace} to {\it subspace}. % \item[{\bf title}]\funArgs{viewport, string} gives the viewport the \index{graphics!3D commands!title} title {\it string}. % \item[{\bf translate}]\funArgs{viewport, $float_{x}$\argDef{viewDeltaXDefault}, $float_{y}$\argDef{viewDeltaYDefault}} translates \index{graphics!3D commands!translate} the object horizontally and vertically relative to the center of the viewport. % \item[{\bf intensity}]\funArgs{viewport,float\argDef{1.0}} resets the intensity {\it I} of the light source, \index{graphics!3D commands!intensity} $0 \le I \le 1.$ % \item[{\bf tubePointsDefault}]\funArgs{\optArg{integer\argDef{6}}} sets or indicates the default number of \index{graphics!3D defaults!tube points} vertices defining the polygon that is used to create a tube around a space curve. % \item[{\bf tubeRadiusDefault}]\funArgs{\optArg{float\argDef{0.5}}} sets or indicates the default radius of \index{graphics!3D defaults!tube radius} the tube that encircles a space curve. % \item[{\bf var1StepsDefault}]\funArgs{\optArg{integer\argDef{27}}} sets or indicates the default number of \index{graphics!3D defaults!var1 steps} increments into which the grid defining a surface plot is subdivided with respect to the first parameter declared in the surface function. % \item[{\bf var2StepsDefault}]\funArgs{\optArg{integer\argDef{27}}} sets or indicates the default number of \index{graphics!3D defaults!var2 steps} increments into which the grid defining a surface plot is subdivided with respect to the second parameter declared in the surface function. % \item[{\bf viewDefaults}]\funArgs{{\tt [}$integer_{point}$, $integer_{line}$, $integer_{axes}$, $integer_{units}$, $float_{point}$, \allowbreak$list_{position}$, $list_{size}${\tt ]}} resets the default settings for the \index{graphics!3D defaults!reset viewport defaults} point color, line color, axes color, units color, point size, viewport upper left-hand corner position, and the viewport size. % \item[{\bf viewDeltaXDefault}]\funArgs{\optArg{float\argDef{0}}} resets the default horizontal offset \index{graphics!3D commands!deltaX default} from the center of the viewport, or returns the current default offset if no argument is given. % \item[{\bf viewDeltaYDefault}]\funArgs{\optArg{float\argDef{0}}} resets the default vertical offset \index{graphics!3D commands!deltaY default} from the center of the viewport, or returns the current default offset if no argument is given. % \item[{\bf viewPhiDefault}]\funArgs{\optArg{float\argDef{-$\pi$/4}}} resets the default latitudinal view angle, or returns the current default angle if no argument is given. \index{graphics!3D commands!phi default} $\phi$ is set to this value. % \item[{\bf viewpoint}]\funArgs{viewport, $float_{x}$, $float_{y}$, $float_{z}$} sets the viewing position in Cartesian coordinates. % \item[{\bf viewpoint}]\funArgs{viewport, $float_{\theta}$, $Float_{\phi}$} sets the viewing position in spherical coordinates. % \item[{\bf viewpoint}]\funArgs{viewport, $Float_{\theta}$, $Float_{\phi}$, $Float_{scaleFactor}$, $Float_{xOffset}$, $Float_{yOffset}$} sets the viewing position in spherical coordinates, the scale factor, and offsets. \index{graphics!3D commands!viewpoint} $\theta$ (longitude) and $\phi$ (latitude) are in radians. % \item[{\bf viewPosDefault}]\funArgs{\optArg{list\argDef{[0,0]}}} sets or indicates the position of the upper \index{graphics!3D defaults!viewport position} left-hand corner of a two-di\-men\-sion\-al viewport, relative to the display root window (the upper left-hand corner of the display is $[0, 0]$). % \item[{\bf viewSizeDefault}]\funArgs{\optArg{list\argDef{[400,400]}}} sets or indicates the width and height dimensions \index{graphics!3D defaults!viewport size} of a viewport. % \item[{\bf viewThetaDefault}]\funArgs{\optArg{float\argDef{$\pi$/4}}} resets the default longitudinal view angle, or returns the current default angle if no argument is given. \index{graphics!3D commands!theta default} When a parameter is specified, the default longitudinal view angle $\theta$ is set to this value. % \item[{\bf viewWriteAvailable}]\funArgs{\optArg{list\argDef{["pixmap", "bitmap", "postscript", "image"]}}} indicates the possible file types \index{graphics!3D defaults!available viewport writes} that can be created with the \spadfunFrom{write}{ThreeDimensionalViewport} function. % \item[{\bf viewWriteDefault}]\funArgs{\optArg{list\argDef{[]}}} sets or indicates the default types of files that are created in addition to the {\bf data} file when a \spadfunFrom{write}{ThreeDimensionalViewport} command \index{graphics!3D defaults!viewport writes} is executed on a viewport. % \item[{\bf viewScaleDefault}]\funArgs{\optArg{float}} sets the default scaling factor, or returns \index{graphics!3D commands!scale default} the current factor if no argument is given. % \item[{\bf write}]\funArgs{viewport, directory, \optArg{option}} writes the file {\bf data} for {\it viewport} in the directory {\it directory}. An optional third argument specifies a file type (one of {\tt pixmap}, {\tt bitmap}, {\tt postscript}, or {\tt image}), or a list of file types. An additional file is written for each file type listed. % \item[{\bf scale}]\funArgs{viewport, float\argDef{2.5}} specifies the scaling factor. \index{graphics!3D commands!scale} \index{scaling graphs} \end{description} \egroup \subsection{Customization using .Xdefaults} \label{ugXdefaults} \index{graphics!.Xdefaults} Both the two-di\-men\-sion\-al and three-di\-men\-sion\-al drawing facilities consult the {\bf .Xdefaults} file for various defaults. \index{file!.Xdefaults @{\bf .Xdefaults}} The list of defaults that are recognized by the graphing routines is discussed in this section. These defaults are preceded by {\tt Axiom.3D.} for three-di\-men\-sion\-al viewport defaults, {\tt Axiom.2D.} for two-di\-men\-sion\-al viewport defaults, or {\tt Axiom*} (no dot) for those defaults that are acceptable to either viewport type. % \begin{description} % \item[{\tt Axiom*buttonFont:\ \it font}] \ \newline This indicates which \index{graphics!.Xdefaults!button font} font type is used for the button text on the control-panel. {\bf Rom11} % \item[{\tt Axiom.2D.graphFont:\ \it font}] \quad (2D only) \newline This indicates \index{graphics!.Xdefaults!graph number font} which font type is used for displaying the graph numbers and slots in the {\bf Graphs} section of the two-di\-men\-sion\-al control-panel. {\bf Rom22} % \item[{\tt Axiom.3D.headerFont:\ \it font}] \ \newline This indicates which \index{graphics!.Xdefaults!graph label font} font type is used for the axes labels and potentiometer header names on three-di\-men\-sion\-al viewport windows. This is also used for two-di\-men\-sion\-al control-panels for indicating which font type is used for potentionmeter header names and multiple graph title headers. %for example, {\tt Axiom.2D.headerFont: 8x13}. {\bf Itl14} % \item[{\tt Axiom*inverse:\ \it switch}] \ \newline This indicates whether the \index{graphics!.Xdefaults!inverting background} background color is to be inverted from white to black. If {\tt on}, the graph viewports use black as the background color. If {\tt off} or no declaration is made, the graph viewports use a white background. {\bf off} % \item[{\tt Axiom.3D.lightingFont:\ \it font}] \quad (3D only) \newline This indicates which font type is used for the {\bf x}, \index{graphics!.Xdefaults!lighting font} {\bf y}, and {\bf z} labels of the two lighting axes potentiometers, and for the {\bf Intensity} title on the lighting control-panel. {\bf Rom10} % \item[{\tt Axiom.2D.messageFont, Axiom.3D.messageFont:\ \it font}] \ \newline These indicate the font type \index{graphics!.Xdefaults!message font} to be used for the text in the control-panel message window. {\bf Rom14} % \item[{\tt Axiom*monochrome:\ \it switch}] \ \newline This indicates whether the \index{graphics!.Xdefaults!monochrome} graph viewports are to be displayed as if the monitor is black and white, that is, a 1 bit plane. If {\tt on} is specified, the viewport display is black and white. If {\tt off} is specified, or no declaration for this default is given, the viewports are displayed in the normal fashion for the monitor in use. {\bf off} % \item[{\tt Axiom.2D.postScript:\ \it filename}] \ \newline This specifies \index{graphics!.Xdefaults!PostScript file name} the name of the file that is generated when a 2D PostScript graph \index{PostScript} is saved. {\bf axiom2D.ps} % \item[{\tt Axiom.3D.postScript:\ \it filename}] \ \newline This specifies \index{graphics!.Xdefaults!PostScript file name} the name of the file that is generated when a 3D PostScript graph \index{PostScript} is saved. {\bf axiom3D.ps} % \item[{\tt Axiom*titleFont \it font}] \ \newline This \index{graphics!.Xdefaults!title font} indicates which font type is used for the title text and, for three-di\-men\-sion\-al graphs, in the lighting and viewing-volume control-panel windows. \index{graphics!Xdefaults!2d} {\bf Rom14} % \item[{\tt Axiom.2D.unitFont:\ \it font}] \quad (2D only) \newline This indicates \index{graphics!.Xdefaults!unit label font} which font type is used for displaying the unit labels on two-di\-men\-sion\-al viewport graphs. {\bf 6x10} % \item[{\tt Axiom.3D.volumeFont:\ \it font}] \quad (3D only) \newline This indicates which font type is used for the {\bf x}, \index{graphics!.Xdefaults!volume label font} {\bf y}, and {\bf z} labels of the clipping region sliders; for the {\bf Perspective}, {\bf Show Region}, and {\bf Clipping On} buttons under {\bf Settings}, and above the windows for the {\bf Hither} and {\bf Eye Distance} sliders in the {\bf Viewing Volume Panel} of the three-di\-men\-sion\-al control-panel. {\bf Rom8} \end{description} \setcounter{chapter}{4} % Chapter 8 % viewSizeDefault [300,300] \chapter{Advanced Problem Solving} \label{ugProblem} In this chapter we describe techniques useful in solving advanced problems with Axiom. \section{Numeric Functions} \label{ugProblemNumeric} % Axiom provides two basic floating-point types: {\tt Float} and {\tt DoubleFloat}. This section describes how to use numerical \index{function!numeric} operations defined on these types and the related complex types. \index{numeric operations} % As we mentioned in Chapter \ref{ugIntro} on page~\pageref{ugIntro}, the {\tt Float} type is a software implementation of floating-point numbers in which the exponent and the \index{floating-point number} significand may have any number of digits. \index{number!floating-point} See \ref{FloatXmpPage} on page~\pageref{FloatXmpPage} for detailed information about this domain. The {\tt DoubleFloat} (see \ref{DoubleFloatXmpPage} on page~\pageref{DoubleFloatXmpPage}) is usually a hardware implementation of floating point numbers, corresponding to machine double precision. The types {\tt Complex Float} and {\tt Complex DoubleFloat} are \index{floating-point number!complex} the corresponding software implementations of complex floating-point numbers. \index{complex!floating-point number} In this section the term {\it floating-point type} means any of these \index{number!complex floating-point} four types. % The floating-point types implement the basic elementary functions. These include (where {\tt \$} means {\tt DoubleFloat}, {\tt Float}, {\tt Complex DoubleFloat}, or {\tt Complex Float}): \noindent {\bf exp}, {\bf log}: $\$ -> \$$ \newline {\bf sin}, {\bf cos}, {\bf tan}, {\bf cot}, {\bf sec}, {\bf csc}: $\$ -> \$$ \newline {\bf sin}, {\bf cos}, {\bf tan}, {\bf cot}, {\bf sec}, {\bf csc}: $\$ -> \$$ \newline {\bf asin}, {\bf acos}, {\bf atan}, {\bf acot}, {\bf asec}, {\bf acsc}: $\$ -> \$$ \newline {\bf sinh}, {\bf cosh}, {\bf tanh}, {\bf coth}, {\bf sech}, {\bf csch}: $\$ -> \$$ \newline {\bf asinh}, {\bf acosh}, {\bf atanh}, {\bf acoth}, {\bf asech}, {\bf acsch}: $\$ -> \$$ \newline {\bf pi}: $() -> \$$ \newline {\bf sqrt}: $\$ -> \$$ \newline {\bf nthRoot}: $(\$, Integer) -> \$$ \newline \spadfunFrom{**}{Float}: $(\$, Fraction Integer) -> \$$ \newline \spadfunFrom{**}{Float}: $(\$,\$) -> \$$ \newline The handling of roots depends on whether the floating-point type \index{root!numeric approximation} is real or complex: for the real floating-point types, {\tt DoubleFloat} and {\tt Float}, if a real root exists the one with the same sign as the radicand is returned; for the complex floating-point types, the principal value is returned. \index{principal value} Also, for real floating-point types the inverse functions produce errors if the results are not real. This includes cases such as $asin(1.2)$, $log(-3.2)$, $sqrt(-1.1)$. % The default floating-point type is {\tt Float} so to evaluate functions using {\tt Float} or {\tt Complex Float}, just use normal decimal notation. \spadcommand{exp(3.1)} $$ 22.1979512814 41633405 $$ \returnType{Type: Float} \spadcommand{exp(3.1 + 4.5 * \%i)} $$ -{4.6792348860 969899118} -{{21.6991659280 71731864} \ i} $$ \returnType{Type: Complex Float} To evaluate functions using {\tt DoubleFloat} or {\tt Complex DoubleFloat}, a declaration or conversion is required. \spadcommand{r: DFLOAT := 3.1; t: DFLOAT := 4.5; exp(r + t*\%i)} $$ -{4.6792348860969906} -{{21.699165928071732} \ i} $$ \returnType{Type: Complex DoubleFloat} \spadcommand{exp(3.1::DFLOAT + 4.5::DFLOAT * \%i)} $$ -{4.6792348860969906} -{{21.699165928071732} \ i} $$ \returnType{Type: Complex DoubleFloat} A number of special functions are provided by the package {\tt DoubleFloatSpecialFunctions} for the machine-precision \index{special functions} floating-point types. \index{DoubleFloatSpecialFunctions} The special functions provided are listed below, where $F$ stands for the types {\tt DoubleFloat} and {\tt Complex DoubleFloat}. The real versions of the functions yield an error if the result is not real. \index{function!special} \noindent {\bf Gamma}: $F -> F$\hfill\newline $Gamma(z)$ is the Euler gamma function, \index{function!Gamma} $\Gamma(z)$, defined by \index{Euler!gamma function} $$\Gamma(z) = \int_{0}^{\infty} t^{z-1} e^{-t} dt.$$ \noindent {\bf Beta}: $F -> F$\hfill\newline $Beta(u, v)$ is the Euler Beta function, \index{function!Euler Beta} $B(u,v)$, defined by \index{Euler!Beta function} $$B(u,v) = \int_{0}^{1} t^{u-1} (1-t)^{v-1} dt.$$ This is related to $\Gamma(z)$ by $$B(u,v) = \frac{\Gamma(u) \Gamma(v)}{\Gamma(u + v)}.$$ \noindent {\bf logGamma}: $F -> F$\hfill\newline $logGamma(z)$ is the natural logarithm of $\Gamma(z)$. This can often be computed even if $\Gamma(z)$ cannot. % \noindent {\bf digamma}: $F -> F$\hfill\newline $digamma(z)$, also called $psi(z)$, \index{psi @ $\psi$} is the function $\psi(z)$, \index{function!digamma} defined by $$\psi(z) = \Gamma'(z)/\Gamma(z).$$ \noindent {\bf polygamma}: $(NonNegativeInteger, F) -> F$\hfill\newline $polygamma(n, z)$ is the $n$-th derivative of \index{function!polygamma} $\psi(z)$, written $\psi^{(n)}(z)$. \noindent {\bf besselJ}: $(F,F) -> F$\hfill\newline $besselJ(v,z)$ is the Bessel function of the first kind, \index{function!Bessel} $J_\nu (z)$. This function satisfies the differential equation $$z^2 w''(z) + z w'(z) + (z^2-\nu^2)w(z) = 0.$$ \noindent {\bf besselY}: $(F,F) -> F$\hfill\newline $besselY(v,z)$ is the Bessel function of the second kind, \index{function!Bessel} $Y_\nu (z)$. This function satisfies the same differential equation as {\bf besselJ}. The implementation simply uses the relation $$Y_\nu (z) = \frac{J_\nu (z) \cos(\nu \pi) - J_{-\nu} (z)}{\sin(\nu \pi)}.$$ \noindent {\bf besselI}: $(F,F) -> F$\hfill\newline $besselI(v,z)$ is the modified Bessel function of the first kind, \index{function!Bessel} $I_\nu (z)$. This function satisfies the differential equation $$z^2 w''(z) + z w'(z) - (z^2+\nu^2)w(z) = 0.$$ \noindent {\bf besselK}: $(F,F) -> F$\hfill\newline $besselK(v,z)$ is the modified Bessel function of the second kind, \index{function!Bessel} $K_\nu (z)$. This function satisfies the same differential equation as {\bf besselI}. \index{Bessel function} The implementation simply uses the relation $$K_\nu (z) = \pi \frac{I_{-\nu} (z) - I_{\nu} (z)}{2 \sin(\nu \pi)}.$$ \noindent {\bf airyAi}: $F -> F$\hfill\newline $airyAi(z)$ is the Airy function $Ai(z)$. \index{function!Airy Ai} This function satisfies the differential equation $w''(z) - z w(z) = 0.$ The implementation simply uses the relation $$Ai(-z) = \frac{1}{3}\sqrt{z} ( J_{-1/3} (\frac{2}{3}z^{3/2}) + J_{1/3} (\frac{2}{3}z^{3/2}) ).$$ \noindent {\bf airyBi}: $F -> F$\hfill\newline $airyBi(z)$ is the Airy function $Bi(z)$. \index{function!Airy Bi} This function satisfies the same differential equation as {\bf airyAi}. \index{Airy function} The implementation simply uses the relation $$Bi(-z) = \frac{1}{3}\sqrt{3 z} ( J_{-1/3} (\frac{2}{3}z^{3/2}) - J_{1/3} (\frac{2}{3}z^{3/2}) ).$$ \noindent {\bf hypergeometric0F1}: $(F,F) -> F$\hfill\newline $hypergeometric0F1(c,z)$ is the hypergeometric function \index{function!hypergeometric} ${}_0 F_1 ( ; c; z)$. The above special functions are defined only for small floating-point types. If you give {\tt Float} arguments, they are converted to {\tt DoubleFloat} by Axiom. \spadcommand{Gamma(0.5)**2} $$ 3.14159265358979 $$ \returnType{Type: DoubleFloat} \spadcommand{a := 2.1; b := 1.1; besselI(a + \%i*b, b*a + 1)} $$ {2.489481690673867} -{{2.365846713181643} \ i} $$ \returnType{Type: Complex DoubleFloat} A number of additional operations may be used to compute numerical values. These are special polynomial functions that can be evaluated for values in any commutative ring $R$, and in particular for values in any floating-point type. The following operations are provided by the package {\tt OrthogonalPolynomialFunctions}: \index{OrthogonalPolynomialFunctions} \noindent {\bf chebyshevT}: $(NonNegativeInteger, R) -> R$\hbox{}\hfill\newline $chebyshevT(n,z)$ is the $n$-th Chebyshev polynomial of the first kind, $T_n (z)$. These are defined by $$\frac{1-t z}{1-2 t z+t^2} = \sum_{n=0}^{\infty} T_n (z) t^n.$$ \noindent {\bf chebyshevU}: $(NonNegativeInteger, R) -> R$\hbox{}\hfill\newline $chebyshevU(n,z)$ is the $n$-th Chebyshev polynomial of the second kind, $U_n (z)$. These are defined by $$\frac{1}{1-2 t z+t^2} = \sum_{n=0}^{\infty} U_n (z) t^n.$$ \noindent {\bf hermiteH}: $(NonNegativeInteger, R) -> R$\hbox{}\hfill\newline $hermiteH(n,z)$ is the $n$-th Hermite polynomial, $H_n (z)$. These are defined by $$e^{2 t z - t^2} = \sum_{n=0}^{\infty} H_n (z) \frac{t^n}{n!}.$$ \noindent {\bf laguerreL}: $(NonNegativeInteger, R) -> R$\hbox{}\hfill\newline $laguerreL(n,z)$ is the $n$-th Laguerre polynomial, $L_n (z)$. These are defined by $$\frac{e^{-\frac{t z}{1-t}}}{1-t} = \sum_{n=0}^{\infty} L_n (z) \frac{t^n}{n!}.$$ \noindent {\bf laguerreL}: $(NonNegativeInteger, NonNegativeInteger, R) -> R$\hbox{}\hfill\newline $laguerreL(m,n,z)$ is the associated Laguerre polynomial, $L^m_n (z)$. This is the $m$-th derivative of $L_n (z)$. \noindent {\bf legendreP}: $(NonNegativeInteger, R) -> R$\hbox{}\hfill\newline $legendreP(n,z)$ is the $n$-th Legendre polynomial, $P_n (z)$. These are defined by $$\frac{1}{\sqrt{1-2 t z+t^2}} = \sum_{n=0}^{\infty} P_n (z) t^n.$$ These operations require non-negative integers for the indices, but otherwise the argument can be given as desired. \spadcommand{[chebyshevT(i, z) for i in 0..5]} $$ \left[ 1, z, {{2 \ {z \sp 2}} -1}, {{4 \ {z \sp 3}} -{3 \ z}}, {{8 \ {z \sp 4}} -{8 \ {z \sp 2}}+1}, {{{16} \ {z \sp 5}} -{{20} \ {z \sp 3}}+{5 \ z}} \right] $$ \returnType{Type: List Polynomial Integer} The expression $chebyshevT(n,z)$ evaluates to the $n$-th Chebyshev \index{polynomial!Chebyshev!of the first kind} polynomial of the first kind. \spadcommand{chebyshevT(3, 5.0 + 6.0*\%i)} $$ -{1675.0}+{{918.0} \ i} $$ \returnType{Type: Complex Float} \spadcommand{chebyshevT(3, 5.0::DoubleFloat)} $$ 485.0 $$ \returnType{Type: DoubleFloat} The expression $chebyshevU(n,z)$ evaluates to the $n$-th Chebyshev \index{polynomial!Chebyshev!of the second kind} polynomial of the second kind. \spadcommand{[chebyshevU(i, z) for i in 0..5]} $$ \left[ 1, {2 \ z}, {{4 \ {z \sp 2}} -1}, {{8 \ {z \sp 3}} -{4 \ z}}, {{{16} \ {z \sp 4}} -{{12} \ {z \sp 2}}+1}, {{{32} \ {z \sp 5}} -{{32} \ {z \sp 3}}+{6 \ z}} \right] $$ \returnType{Type: List Polynomial Integer} \spadcommand{chebyshevU(3, 0.2)} $$ -{0.736} $$ \returnType{Type: Float} The expression $hermiteH(n,z)$ evaluates to the $n$-th Hermite \index{polynomial!Hermite} polynomial. \spadcommand{[hermiteH(i, z) for i in 0..5]} $$ \left[ 1, {2 \ z}, {{4 \ {z \sp 2}} -2}, {{8 \ {z \sp 3}} -{{12} \ z}}, {{{16} \ {z \sp 4}} -{{48} \ {z \sp 2}}+{12}}, {{{32} \ {z \sp 5}} -{{160} \ {z \sp 3}}+{{120} \ z}} \right] $$ \returnType{Type: List Polynomial Integer} \spadcommand{hermiteH(100, 1.0)} $$ -{0.1448706729 337934088 E 93} $$ \returnType{Type: Float} The expression $laguerreL(n,z)$ evaluates to the $n$-th Laguerre \index{polynomial!Laguerre} polynomial. \spadcommand{[laguerreL(i, z) for i in 0..4]} $$ \left[ 1, {-z+1}, {{z \sp 2} -{4 \ z}+2}, {-{z \sp 3}+{9 \ {z \sp 2}} -{{18} \ z}+6}, {{z \sp 4} -{{16} \ {z \sp 3}}+{{72} \ {z \sp 2}} -{{96} \ z}+{24}} \right] $$ \returnType{Type: List Polynomial Integer} \spadcommand{laguerreL(4, 1.2)} $$ -{13.0944} $$ \returnType{Type: Float} \spadcommand{[laguerreL(j, 3, z) for j in 0..4]} $$ \left[ {-{z \sp 3}+{9 \ {z \sp 2}} -{{18} \ z}+6}, {-{3 \ {z \sp 2}}+{{18} \ z} -{18}}, {-{6 \ z}+{18}}, -6, 0 \right] $$ \returnType{Type: List Polynomial Integer} \spadcommand{laguerreL(1, 3, 2.1)} $$ 6.57 $$ \returnType{Type: Float} The expression \index{polynomial!Legendre} $legendreP(n,z)$ evaluates to the $n$-th Legendre polynomial, \spadcommand{[legendreP(i,z) for i in 0..5]} $$ \left[ 1, z, {{{3 \over 2} \ {z \sp 2}} -{1 \over 2}}, {{{5 \over 2} \ {z \sp 3}} -{{3 \over 2} \ z}}, {{{{35} \over 8} \ {z \sp 4}} -{{{15} \over 4} \ {z \sp 2}}+{3 \over 8}}, {{{{63} \over 8} \ {z \sp 5}} -{{{35} \over 4} \ {z \sp 3}}+{{{15} \over 8} \ z}} \right] $$ \returnType{Type: List Polynomial Fraction Integer} \spadcommand{legendreP(3, 3.0*\%i)} $$ -{{72.0} \ i} $$ \returnType{Type: Complex Float} Finally, three number-theoretic polynomial operations may be evaluated. \index{number theory} The following operations are provided by the package {\tt NumberTheoreticPolynomialFunctions}. \index{NumberTheoreticPolynomialFunctions}. \noindent {\bf bernoulliB}: $(NonNegativeInteger, R) -> R$ \hbox{}\hfill\newline $bernoulliB(n,z)$ is the $n$-th Bernoulli polynomial, \index{polynomial!Bernoulli} $B_n (z)$. These are defined by $$\frac{t e^{z t}}{e^t - 1} = \sum_{n=0}^{\infty} B_n (z) \frac{t^n}{n!}.$$ \noindent {\bf eulerE}: $(NonNegativeInteger, R) -> R$ \hbox{}\hfill\newline $eulerE(n,z)$ is the $n$-th Euler polynomial, \index{Euler!polynomial} $E_n (z)$. These are defined by \index{polynomial!Euler} $$\frac{2 e^{z t}}{e^t + 1} = \sum_{n=0}^{\infty} E_n (z) \frac{t^n}{n!}.$$ \noindent {\bf cyclotomic}: $(NonNegativeInteger, R) -> R$\hbox{}\hfill\newline $cyclotomic(n,z)$ is the $n$-th cyclotomic polynomial $\Phi_n (z)$. This is the polynomial whose roots are precisely the primitive $n$-th roots of unity. \index{Euler!totient function} This polynomial has degree given by the Euler totient function \index{function!totient} $\phi(n)$. The expression $bernoulliB(n,z)$ evaluates to the $n$-th Bernoulli \index{polynomial!Bernouilli} polynomial. \spadcommand{bernoulliB(3, z)} $$ {z \sp 3} -{{3 \over 2} \ {z \sp 2}}+{{1 \over 2} \ z} $$ \returnType{Type: Polynomial Fraction Integer} \spadcommand{bernoulliB(3, 0.7 + 0.4 * \%i)} $$ -{0.138} -{{0.116} \ i} $$ \returnType{Type: Complex Float} The expression \index{polynomial!Euler} $eulerE(n,z)$ evaluates to the $n$-th Euler polynomial. \spadcommand{eulerE(3, z)} $$ {z \sp 3} -{{3 \over 2} \ {z \sp 2}}+{1 \over 4} $$ \returnType{Type: Polynomial Fraction Integer} \spadcommand{eulerE(3, 0.7 + 0.4 * \%i)} $$ -{0.238} -{{0.316} \ i} $$ \returnType{Type: Complex Float} The expression \index{polynomial!cyclotomic} $cyclotomic(n,z)$ evaluates to the $n$-th cyclotomic polynomial. \index{cyclotomic polynomial} \spadcommand{cyclotomic(3, z)} $$ {z \sp 2}+z+1 $$ \returnType{Type: Polynomial Integer} \spadcommand{cyclotomic(3, (-1.0 + 0.0 * \%i)**(2/3))} $$ 0.0 $$ \returnType{Type: Complex Float} Drawing complex functions in Axiom is presently somewhat awkward compared to drawing real functions. It is necessary to use the {\bf draw} operations that operate on functions rather than expressions. This is the complex exponential function (rotated interactively). \index{function!complex exponential} When this is displayed in color, the height is the value of the real part of the function and the color is the imaginary part. Red indicates large negative imaginary values, green indicates imaginary values near zero and blue/violet indicates large positive imaginary values. \spadgraph{draw((x,y)+-> real exp complex(x,y), -2..2, -2*\%pi..2*\%pi, colorFunction == (x, y) +-> imag exp complex(x,y), title=="exp(x+\%i*y)", style=="smooth")} %\epsffile[0 0 295 295]{ps/compexp.ps} This is the complex arctangent function. \index{function!complex arctangent} Again, the height is the real part of the function value but here the color indicates the function value's phase. The position of the branch cuts are clearly visible and one can see that the function is real only for a real argument. \spadgraph{vp := draw((x,y) +-> real atan complex(x,y), -\%pi..\%pi, -\%pi..\%pi, colorFunction==(x,y) +->argument atan complex(x,y), title=="atan(x+\%i*y)", style=="shade"); rotate(vp,-160,-45); vp} %\epsffile[0 0 295 295]{ps/compatan.ps} This is the complex Gamma function. \spadgraph{draw((x,y) +-> max(min(real Gamma complex(x,y),4),-4), -\%pi..\%pi, -\%pi..\%pi, style=="shade", colorFunction == (x,y) +-> argument Gamma complex(x,y), title == "Gamma(x+\%i*y)", var1Steps == 50, var2Steps== 50)} %\epsffile[0 0 295 295]{ps/compgamm.ps} This shows the real Beta function near the origin. \spadgraph{draw(Beta(x,y)/100, x=-1.6..1.7, y = -1.6..1.7, style=="shade", title=="Beta(x,y)", var1Steps==40, var2Steps==40)} %\epsffile[0 0 295 295]{ps/realbeta.ps} This is the Bessel function $J_\alpha (x)$ for index $\alpha$ in the range $-6..4$ and argument $x$ in the range $2..14$. \spadgraph{draw((alpha,x) +-> min(max(besselJ(alpha, x+8), -6), 6), -6..4, -6..6, title=="besselJ(alpha,x)", style=="shade", var1Steps==40, var2Steps==40)} %\epsffile[0 0 295 295]{ps/bessel.ps} This is the modified Bessel function $I_\alpha (x)$ evaluated for various real values of the index $\alpha$ and fixed argument $x = 5$. \spadgraph{draw(besselI(alpha, 5), alpha = -12..12, unit==[5,20])} %\epsffile[0 0 295 295]{ps/modbess.ps} This is similar to the last example except the index $\alpha$ takes on complex values in a $6 x 6$ rectangle centered on the origin. \spadgraph{draw((x,y) +-> real besselI(complex(x/20, y/20),5), -60..60, -60..60, colorFunction == (x,y)+-> argument besselI(complex(x/20,y/20),5), title=="besselI(x+i*y,5)", style=="shade")} %\epsffile[0 0 295 295]{ps/modbessc.ps} \section{Polynomial Factorization} \label{ugProblemFactor} % The Axiom polynomial factorization \index{polynomial!factorization} facilities are available for all polynomial types and a wide variety of coefficient domains. \index{factorization} Here are some examples. \subsection{Integer and Rational Number Coefficients} \label{ugProblemFactorIntRat} Polynomials with integer \index{polynomial!factorization!integer coefficients} coefficients can be be factored. \spadcommand{v := (4*x**3+2*y**2+1)*(12*x**5-x**3*y+12) } $$ -{2 \ {x \sp 3} \ {y \sp 3}}+{{\left( {{24} \ {x \sp 5}}+{24} \right)} \ {y \sp 2}}+{{\left( -{4 \ {x \sp 6}} -{x \sp 3} \right)} \ y}+{{48} \ {x \sp 8}}+{{12} \ {x \sp 5}}+{{48} \ {x \sp 3}}+{12} $$ \returnType{Type: Polynomial Integer} \spadcommand{factor v } $$ -{{\left( {{x \sp 3} \ y} -{{12} \ {x \sp 5}} -{12} \right)} \ {\left( {2 \ {y \sp 2}}+{4 \ {x \sp 3}}+1 \right)}} $$ \returnType{Type: Factored Polynomial Integer} Also, Axiom can factor polynomials with \index{polynomial!factorization!rational number coefficients} rational number coefficients. \spadcommand{w := (4*x**3+(2/3)*x**2+1)*(12*x**5-(1/2)*x**3+12) } $$ {{48} \ {x \sp 8}}+{8 \ {x \sp 7}} -{2 \ {x \sp 6}}+{{{35} \over 3} \ {x \sp 5}}+{{{95} \over 2} \ {x \sp 3}}+{8 \ {x \sp 2}}+{12} $$ \returnType{Type: Polynomial Fraction Integer} \spadcommand{factor w } $$ {48} \ {\left( {x \sp 3}+{{1 \over 6} \ {x \sp 2}}+{1 \over 4} \right)} \ {\left( {x \sp 5} -{{1 \over {24}} \ {x \sp 3}}+1 \right)} $$ \returnType{Type: Factored Polynomial Fraction Integer} \subsection{Finite Field Coefficients} \label{ugProblemFactorFF} Polynomials with coefficients in a finite field \index{polynomial!factorization!finite field coefficients} can be also be factored. \index{finite field!factoring polynomial with coefficients in} \spadcommand{u : POLY(PF(19)) :=3*x**4+2*x**2+15*x+18 } $$ {3 \ {x \sp 4}}+{2 \ {x \sp 2}}+{{15} \ x}+{18} $$ \returnType{Type: Polynomial PrimeField 19} These include the integers mod $p$, where $p$ is prime, and extensions of these fields. \spadcommand{factor u } $$ 3 \ {\left( x+{18} \right)} \ {\left( {x \sp 3}+{x \sp 2}+{8 \ x}+{13} \right)} $$ \returnType{Type: Factored Polynomial PrimeField 19} Convert this to have coefficients in the finite field with $19^3$ elements. See \ref{ugProblemFinite} on page~\pageref{ugProblemFinite} for more information about finite fields. \spadcommand{factor(u :: POLY FFX(PF 19,3)) } $$ 3 \ {\left( x+{18} \right)} \ {\left( x+{5 \ { \%I \sp 2}}+{3 \ \%I}+{13} \right)} \ {\left( x+{{16} \ { \%I \sp 2}}+{{14} \ \%I}+{13} \right)} \ {\left( x+{{17} \ { \%I \sp 2}}+{2 \ \%I}+{13} \right)} $$ \returnType{Type: Factored Polynomial FiniteFieldExtension(PrimeField 19,3)} \subsection{Simple Algebraic Extension Field Coefficients} \label{ugProblemFactorAlg} Polynomials with coefficients in simple algebraic extensions \index{polynomial!factorization!algebraic extension field coefficients} of the rational numbers can be factored. \index{algebraic number} \index{number!algebraic} Here, $aa$ and $bb$ are symbolic roots of polynomials. \spadcommand{aa := rootOf(aa**2+aa+1) } $$ aa $$ \returnType{Type: AlgebraicNumber} \spadcommand{p:=(x**3+aa**2*x+y)*(aa*x**2+aa*x+aa*y**2)**2 } $$ \begin{array}{@{}l} {{\left( -aa -1 \right)} \ {y \sp 5}}+ {{\left( {{\left( -aa -1 \right)}\ {x \sp 3}}+ {aa \ x} \right)}\ {y \sp 4}}+ \\ \\ \displaystyle {{\left( {{\left( -{2 \ aa} -2 \right)}\ {x \sp 2}}+ {{\left( -{2 \ aa} -2 \right)}\ x} \right)}\ {y \sp 3}}+ \\ \\ \displaystyle {{\left( {{\left( -{2 \ aa} -2 \right)}\ {x \sp 5}}+ {{\left( -{2 \ aa} -2 \right)}\ {x \sp 4}}+ {2 \ aa \ {x \sp 3}}+{2 \ aa \ {x \sp 2}} \right)}\ {y \sp 2}}+ \\ \\ \displaystyle {{\left( {{\left( -aa -1 \right)}\ {x \sp 4}}+ {{\left( -{2 \ aa} -2 \right)}\ {x \sp 3}}+ {{\left( -aa -1 \right)}\ {x \sp 2}} \right)}\ y}+ \\ \\ \displaystyle {{\left( -aa -1 \right)}\ {x \sp 7}}+ {{\left( -{2 \ aa} -2 \right)}\ {x \sp 6}} - {x \sp 5}+ {2 \ aa \ {x \sp 4}}+ {aa \ {x \sp 3}} \end{array} $$ \returnType{Type: Polynomial AlgebraicNumber} Note that the second argument to factor can be a list of algebraic extensions to factor over. \spadcommand{factor(p,[aa]) } %Note: this answer differs from the book but is equivalent. $$ {\left( -aa -1 \right)} \ {\left( y+{x \sp 3}+{{\left( -aa -1 \right)} \ x} \right)} \ {{\left( {y \sp 2}+{x \sp 2}+x \right)} \sp 2} $$ \returnType{Type: Factored Polynomial AlgebraicNumber} This factors $x**2+3$ over the integers. \spadcommand{factor(x**2+3)} $$ {x \sp 2}+3 $$ \returnType{Type: Factored Polynomial Integer} Factor the same polynomial over the field obtained by adjoining $aa$ to the rational numbers. \spadcommand{factor(x**2+3,[aa]) } $$ {\left( x -{2 \ aa} -1 \right)} \ {\left( x+{2 \ aa}+1 \right)} $$ \returnType{Type: Factored Polynomial AlgebraicNumber} Factor $x**6+108$ over the same field. \spadcommand{factor(x**6+108,[aa]) } $$ {\left( {x \sp 3} -{{12} \ aa} -6 \right)} \ {\left( {x \sp 3}+{{12} \ aa}+6 \right)} $$ \returnType{Type: Factored Polynomial AlgebraicNumber} \spadcommand{bb:=rootOf(bb**3-2) } $$ bb $$ \returnType{Type: AlgebraicNumber} \spadcommand{factor(x**6+108,[bb]) } $$ {\left( {x \sp 2} -{3 \ bb \ x}+{3 \ {bb \sp 2}} \right)} \ {\left( {x \sp 2}+{3 \ {bb \sp 2}} \right)} \ {\left( {x \sp 2}+{3 \ bb \ x}+{3 \ {bb \sp 2}} \right)} $$ \returnType{Type: Factored Polynomial AlgebraicNumber} Factor again over the field obtained by adjoining both $aa$ and $bb$ to the rational numbers. \spadcommand{factor(x**6+108,[aa,bb]) } $$ \begin{array}{@{}l} {\left( x+{{\left( -{2 \ aa} -1 \right)}\ bb} \right)} \ {\left( x+{{\left( -aa -2 \right)}\ bb} \right)} \ {\left( x+{{\left( -aa+1 \right)}\ bb} \right)} \\ \\ \displaystyle \ {\left( x+{{\left( aa -1 \right)}\ bb} \right)} \ {\left( x+{{\left( aa+2 \right)}\ bb} \right)} \ {\left( x+{{\left( {2 \ aa}+1 \right)}\ bb} \right)} \end{array} $$ \returnType{Type: Factored Polynomial AlgebraicNumber} \subsection{Factoring Rational Functions} \label{ugProblemFactorRatFun} Since fractions of polynomials form a field, every element (other than zero) \index{rational function!factoring} divides any other, so there is no useful notion of irreducible factors. Thus the {\bf factor} operation is not very useful for fractions of polynomials. There is, instead, a specific operation {\bf factorFraction} that separately factors the numerator and denominator and returns a fraction of the factored results. \spadcommand{factorFraction((x**2-4)/(y**2-4))} $$ {{\left( x -2 \right)} \ {\left( x+2 \right)}} \over {{\left( y -2 \right)} \ {\left( y+2 \right)}} $$ \returnType{Type: Fraction Factored Polynomial Integer} You can also use {\bf map}. This expression applies the {\bf factor} operation to the numerator and denominator. \spadcommand{map(factor,(x**2-4)/(y**2-4))} $$ {{\left( x -2 \right)} \ {\left( x+2 \right)}} \over {{\left( y -2 \right)} \ {\left( y+2 \right)}} $$ \returnType{Type: Fraction Factored Polynomial Integer} \section{Manipulating Symbolic Roots of a Polynomial} \label{ugProblemSymRoot} % In this section we show you how to work with one root or all roots \index{root!symbolic} of a polynomial. These roots are represented symbolically (as opposed to being numeric approximations). See \ref{ugxProblemOnePol} on page~\pageref{ugxProblemOnePol} and \ref{ugxProblemPolSys} on page~\pageref{ugxProblemPolSys} for information about solving for the roots of one or more polynomials. \subsection{Using a Single Root of a Polynomial} \label{ugxProblemSymRootOne} Use {\bf rootOf} to get a symbolic root of a polynomial: $rootOf(p, x)$ returns a root of $p(x)$. This creates an algebraic number $a$. \index{algebraic number} \index{number!algebraic} \spadcommand{a := rootOf(a**4+1,a) } $$ a $$ \returnType{Type: Expression Integer} To find the algebraic relation that defines $a$, use {\bf definingPolynomial}. \spadcommand{definingPolynomial a } $$ {a \sp 4}+1 $$ \returnType{Type: Expression Integer} You can use $a$ in any further expression, including a nested {\bf rootOf}. \spadcommand{b := rootOf(b**2-a-1,b) } $$ b $$ \returnType{Type: Expression Integer} Higher powers of the roots are automatically reduced during calculations. \spadcommand{a + b } $$ b+a $$ \returnType{Type: Expression Integer} \spadcommand{\% ** 5 } $$ {{\left( {{10} \ {a \sp 3}}+{{11} \ {a \sp 2}}+{2 \ a} -4 \right)} \ b}+{{15} \ {a \sp 3}}+{{10} \ {a \sp 2}}+{4 \ a} -{10} $$ \returnType{Type: Expression Integer} The operation {\bf zeroOf} is similar to {\bf rootOf}, except that it may express the root using radicals in some cases. \index{radical} \spadcommand{rootOf(c**2+c+1,c)} $$ c $$ \returnType{Type: Expression Integer} \spadcommand{zeroOf(d**2+d+1,d)} $$ {{\sqrt {-3}} -1} \over 2 $$ \returnType{Type: Expression Integer} \spadcommand{rootOf(e**5-2,e)} $$ e $$ \returnType{Type: Expression Integer} \spadcommand{zeroOf(f**5-2,f)} $$ \root {5} \of {2} $$ \returnType{Type: Expression Integer} \subsection{Using All Roots of a Polynomial} \label{ugxProblemSymRootAll} Use {\bf rootsOf} to get all symbolic roots of a polynomial: $rootsOf(p, x)$ returns a list of all the roots of $p(x)$. If $p(x)$ has a multiple root of order $n$, then that root \index{root!multiple} appears $n$ times in the list. \typeout{Make sure these variables are x0 etc} Compute all the roots of $x**4 + 1$. \spadcommand{l := rootsOf(x**4+1,x) } $$ \left[ \%x0, { \%x0 \ \%x1}, - \%x0, -{ \%x0 \ \%x1} \right] $$ \returnType{Type: List Expression Integer} As a side effect, the variables $\%x0, \%x1$ and $\%x2$ are bound to the first three roots of $x**4+1$. \spadcommand{\%x0**5 } $$ - \%x0 $$ \returnType{Type: Expression Integer} Although they all satisfy $x**4 + 1 = 0, \%x0, \%x1,$ and $\%x2$ are different algebraic numbers. To find the algebraic relation that defines each of them, use {\bf definingPolynomial}. \spadcommand{definingPolynomial \%x0 } $$ { \%x0 \sp 4}+1 $$ \returnType{Type: Expression Integer} \spadcommand{definingPolynomial \%x1 } $$ { \%x1 \sp 2}+1 $$ \returnType{Type: Expression Integer} \spadcommand{definingPolynomial \%x2 } $$ - \%x2+ \%\%var $$ \returnType{Type: Expression Integer} We can check that the sum and product of the roots of $x**4+1$ are its trace and norm. \spadcommand{x3 := last l } $$ -{ \%x0 \ \%x1} $$ \returnType{Type: Expression Integer} \spadcommand{\%x0 + \%x1 + \%x2 + x3 } $$ {{\left( - \%x0+1 \right)} \ \%x1}+ \%x0+ \%x2 $$ \returnType{Type: Expression Integer} \spadcommand{\%x0 * \%x1 * \%x2 * x3 } $$ \%x2 \ { \%x0 \sp 2} $$ \returnType{Type: Expression Integer} Corresponding to the pair of operations {\bf rootOf}/{\bf zeroOf} in \ref{ugxProblemOnePol} on page~\pageref{ugxProblemOnePol}, there is an operation {\bf zerosOf} that, like {\bf rootsOf}, computes all the roots of a given polynomial, but which expresses some of them in terms of radicals. \spadcommand{zerosOf(y**4+1,y) } $$ \left[ {{{\sqrt {-1}}+1} \over {\sqrt {2}}}, {{{\sqrt {-1}} -1} \over {\sqrt {2}}}, {{-{\sqrt {-1}} -1} \over {\sqrt {2}}}, {{-{\sqrt {-1}}+1} \over {\sqrt {2}}} \right] $$ \returnType{Type: List Expression Integer} As you see, only one implicit algebraic number was created ($\%y1$), and its defining equation is this. The other three roots are expressed in radicals. \spadcommand{definingPolynomial \%y1 } $$ { \%\%var \sp 2}+1 $$ \returnType{Type: Expression Integer} \section{Computation of Eigenvalues and Eigenvectors} \label{ugProblemEigen} % In this section we show you some of Axiom's facilities for computing and \index{eigenvalue} manipulating eigenvalues and eigenvectors, also called \index{eigenvector} characteristic values and characteristic vectors, \index{characteristic!value} respectively. \index{characteristic!vector} \vskip 4pc Let's first create a matrix with integer entries. \spadcommand{m1 := matrix [ [1,2,1],[2,1,-2],[1,-2,4] ] } $$ \left[ \begin{array}{ccc} 1 & 2 & 1 \\ 2 & 1 & -2 \\ 1 & -2 & 4 \end{array} \right] $$ \returnType{Type: Matrix Integer} To get a list of the {\it rational} eigenvalues, use the operation {\bf eigenvalues}. \spadcommand{leig := eigenvalues(m1) } $$ \left[ 5, {\left( \%K \mid {{ \%K \sp 2} - \%K -5} \right)} \right] $$ \returnType{Type: List Union(Fraction Polynomial Integer,SuchThat(Symbol,Polynomial Integer))} Given an explicit eigenvalue, {\bf eigenvector} computes the eigenvectors corresponding to it. \spadcommand{eigenvector(first(leig),m1) } $$ \left[ {\left[ \begin{array}{c} 0 \\ -{1 \over 2} \\ 1 \end{array} \right]} \right] $$ \returnType{Type: List Matrix Fraction Polynomial Fraction Integer} The operation {\bf eigenvectors} returns a list of pairs of values and vectors. When an eigenvalue is rational, Axiom gives you the value explicitly; otherwise, its minimal polynomial is given, (the polynomial of lowest degree with the eigenvalues as roots), together with a parametric representation of the eigenvector using the eigenvalue. This means that if you ask Axiom to {\bf solve} the minimal polynomial, then you can substitute these roots \index{polynomial!minimal} into the parametric form of the corresponding eigenvectors. \index{minimal polynomial} You must be aware that unless an exact eigenvalue has been computed, the eigenvector may be badly in error. \spadcommand{eigenvectors(m1) } $$ \begin{array}{@{}l} \left[ {\left[ {eigval=5}, {eigmult=1}, {eigvec= {\left[ {\left[ \begin{array}{c} 0 \\ -{1 \over 2} \\ 1 \end{array} \right]} \right]}} \right]}, \right. \\ \\ \displaystyle \left. {\left[ {eigval={\left( \%L \mid {{ \%L \sp 2} - \%L -5} \right)}}, {eigmult=1}, {eigvec= {\left[ {\left[ \begin{array}{c} \%L \\ 2 \\ 1 \end{array} \right]} \right]}} \right]} \right] \end{array} $$ \returnType{Type: List Record(eigval: Union(Fraction Polynomial Integer,SuchThat(Symbol,Polynomial Integer)),eigmult: NonNegativeInteger,eigvec: List Matrix Fraction Polynomial Integer)} Another possibility is to use the operation {\bf radicalEigenvectors} tries to compute explicitly the eigenvectors in terms of radicals. \index{radical} \spadcommand{radicalEigenvectors(m1) } $$ \begin{array}{@{}l} \left[ {\left[ {radval={{{\sqrt {{21}}}+1} \over 2}}, {radmult=1}, {radvect={\left[ {\left[ \begin{array}{c} {{{\sqrt {{21}}}+1} \over 2} \\ 2 \\ 1 \end{array} \right]} \right]}} \right]}, \right. \\ \\ \displaystyle \left[ {radval={{-{\sqrt {{21}}}+1} \over 2}}, {radmult=1}, {radvect={\left[ {\left[ \begin{array}{c} {{-{\sqrt {{21}}}+1} \over 2} \\ 2 \\ 1 \end{array} \right]} \right]}} \right], \\ \\ \displaystyle \left. \left[ {radval=5}, {radmult=1}, {radvect={\left[ {\left[ \begin{array}{c} 0 \\ -{1 \over 2} \\ 1 \end{array} \right]} \right]}} \right] \right] \end{array} $$ \returnType{Type: List Record(radval: Expression Integer,radmult: Integer,radvect: List Matrix Expression Integer)} Alternatively, Axiom can compute real or complex approximations to the \index{approximation} eigenvectors and eigenvalues using the operations {\bf realEigenvectors} or {\bf complexEigenvectors}. They each take an additional argument $\epsilon$ to specify the ``precision'' required. \index{precision} In the real case, this means that each approximation will be within $\pm\epsilon$ of the actual result. In the complex case, this means that each approximation will be within $\pm\epsilon$ of the actual result in each of the real and imaginary parts. The precision can be specified as a {\tt Float} if the results are desired in floating-point notation, or as {\tt Fraction Integer} if the results are to be expressed using rational (or complex rational) numbers. \spadcommand{realEigenvectors(m1,1/1000) } $$ \begin{array}{@{}l} \left[ {\left[ {outval=5}, {outmult=1}, {outvect={\left[ {\left[ \begin{array}{c} 0 \\ -{1 \over 2} \\ 1 \end{array} \right]} \right]}} \right]}, \right. \\ \\ \displaystyle {\left[ {outval={{5717} \over {2048}}}, {outmult=1}, {outvect={\left[ {\left[ \begin{array}{c} {{5717} \over {2048}} \\ 2 \\ 1 \end{array} \right]} \right]}} \right]}, \\ \\ \displaystyle \left. {\left[ {outval=-{{3669} \over {2048}}}, {outmult=1}, {outvect={\left[ {\left[ \begin{array}{c} -{{3669} \over {2048}} \\ 2 \\ 1 \end{array} \right]} \right]}} \right]} \right] \end{array} $$ \returnType{Type: List Record(outval: Fraction Integer,outmult: Integer,outvect: List Matrix Fraction Integer)} If an $n$ by $n$ matrix has $n$ distinct eigenvalues (and therefore $n$ eigenvectors) the operation {\bf eigenMatrix} gives you a matrix of the eigenvectors. \spadcommand{eigenMatrix(m1) } $$ \left[ \begin{array}{ccc} {{{\sqrt {{21}}}+1} \over 2} & {{-{\sqrt {{21}}}+1} \over 2} & 0 \\ 2 & 2 & -{1 \over 2} \\ 1 & 1 & 1 \end{array} \right] $$ \returnType{Type: Union(Matrix Expression Integer,...)} \spadcommand{m2 := matrix [ [-5,-2],[18,7] ] } $$ \left[ \begin{array}{cc} -5 & -2 \\ {18} & 7 \end{array} \right] $$ \returnType{Type: Matrix Integer} \spadcommand{eigenMatrix(m2) } $$ \mbox{\tt "failed"} $$ \returnType{Type: Union("failed",...)} If a symmetric matrix \index{matrix!symmetric} has a basis of orthonormal eigenvectors, then \index{basis!orthonormal} {\bf orthonormalBasis} computes a list of these vectors. \index{orthonormal basis} \spadcommand{m3 := matrix [ [1,2],[2,1] ] } $$ \left[ \begin{array}{cc} 1 & 2 \\ 2 & 1 \end{array} \right] $$ \returnType{Type: Matrix Integer} \spadcommand{orthonormalBasis(m3) } $$ \left[ {\left[ \begin{array}{c} -{1 \over {\sqrt {2}}} \\ {1 \over {\sqrt {2}}} \end{array} \right]}, {\left[ \begin{array}{c} {1 \over {\sqrt {2}}} \\ {1 \over {\sqrt {2}}} \end{array} \right]} \right] $$ \returnType{Type: List Matrix Expression Integer} \section{Solution of Linear and Polynomial Equations} \label{ugProblemLinPolEqn} % In this section we discuss the Axiom facilities for solving systems of linear equations, finding the roots of polynomials and \index{linear equation} solving systems of polynomial equations. For a discussion of the solution of differential equations, see \ref{ugProblemDEQ} on page~\pageref{ugProblemDEQ}. \subsection{Solution of Systems of Linear Equations} \label{ugxProblemLinSys} You can use the operation {\bf solve} to solve systems of linear equations. \index{equation!linear!solving} The operation {\bf solve} takes two arguments, the list of equations and the list of the unknowns to be solved for. A system of linear equations need not have a unique solution. To solve the linear system: $$ \begin{array}{rcrcrcr} x &+& y &+& z &=& 8 \\ 3 x &-& 2 y &+& z &=& 0 \\ x &+& 2 y &+& 2 z &=& 17 \end{array} $$ evaluate this expression. \spadcommand{solve([x+y+z=8,3*x-2*y+z=0,x+2*y+2*z=17],[x,y,z])} $$ \left[ {\left[ {x=-1}, {y=2}, {z=7} \right]} \right] $$ \returnType{Type: List List Equation Fraction Polynomial Integer} Parameters are given as new variables starting with a percent sign and {\tt \%} and the variables are expressed in terms of the parameters. If the system has no solutions then the empty list is returned. When you solve the linear system $$ \begin{array}{rcrcrcr} x&+&2 y&+&3 z&=&2 \\ 2 x&+&3 y&+&4 z&=&2 \\ 3 x&+&4 y&+&5 z&=&2 \end{array} $$ with this expression you get a solution involving a parameter. \spadcommand{solve([x+2*y+3*z=2,2*x+3*y+4*z=2,3*x+4*y+5*z=2],[x,y,z])} $$ \left[ {\left[ {x={ \%Q -2}}, {y={-{2 \ \%Q}+2}}, {z= \%Q} \right]} \right] $$ \returnType{Type: List List Equation Fraction Polynomial Integer} The system can also be presented as a matrix and a vector. The matrix contains the coefficients of the linear equations and the vector contains the numbers appearing on the right-hand sides of the equations. You may input the matrix as a list of rows and the vector as a list of its elements. To solve the system: $$ \begin{array}{rcrcrcr} x&+& y&+& z&=&8 \\ 3 x&-&2 y&+& z&=&0 \\ x&+&2 y&+&2 z&=&17 \end{array} $$ in matrix form you would evaluate this expression. \spadcommand{solve([ [1,1,1],[3,-2,1],[1,2,2] ],[8,0,17])} $$ \left[ {particular={\left[ -1, 2, 7\right]}}, {basis={\left[ {\left[ 0, 0, 0\right]}\right]}} \right] $$ \returnType{Type: Record(particular: Union(Vector Fraction Integer,"failed"), basis: List Vector Fraction Integer)} The solutions are presented as a {\tt Record} with two components: the component {\it particular} contains a particular solution of the given system or the item {\tt "failed"} if there are no solutions, the component {\it basis} contains a list of vectors that are a basis for the space of solutions of the corresponding homogeneous system. If the system of linear equations does not have a unique solution, then the {\it basis} component contains non-trivial vectors. This happens when you solve the linear system $$ \begin{array}{rcrcrcr} x&+&2 y&+&3 z&=&2 \\ 2 x&+&3 y&+&4 z&=&2 \\ 3 x&+&4 y&+&5 z&=&2 \end{array} $$ with this command. \spadcommand{solve([ [1,2,3],[2,3,4],[3,4,5] ],[2,2,2])} $$ \left[ {particular={\left[ -2, 2, 0 \right]}}, {basis={\left[ {\left[ 1, -2, 1 \right]}\right]}} \right] $$ \returnType{Type: Record(particular: Union(Vector Fraction Integer,"failed"), basis: List Vector Fraction Integer)} All solutions of this system are obtained by adding the particular solution with a linear combination of the {\it basis} vectors. When no solution exists then {\tt "failed"} is returned as the {\it particular} component, as follows: \spadcommand{solve([ [1,2,3],[2,3,4],[3,4,5] ],[2,3,2])} $$ \left[ {particular= \mbox{\tt "failed"} }, {basis={\left[ {\left[ 1, -2, 1\right]}\right]}} \right] $$ \returnType{Type: Record(particular: Union(Vector Fraction Integer,"failed"), basis: List Vector Fraction Integer)} When you want to solve a system of homogeneous equations (that is, a system where the numbers on the right-hand sides of the \index{nullspace} equations are all zero) in the matrix form you can omit the second argument and use the {\bf nullSpace} operation. This computes the solutions of the following system of equations: $$ \begin{array}{rcrcrcr} x&+&2 y&+&3 z&=&0 \\ 2 x&+&3 y&+&4 z&=&0 \\ 3 x&+&4 y&+&5 z&=&0 \end{array} $$ The result is given as a list of vectors and these vectors form a basis for the solution space. \spadcommand{nullSpace([ [1,2,3],[2,3,4],[3,4,5] ])} $$ \left[ {\left[ 1, -2, 1 \right]} \right] $$ \returnType{Type: List Vector Integer} \subsection{Solution of a Single Polynomial Equation} \label{ugxProblemOnePol} Axiom can solve polynomial equations producing either approximate \index{polynomial!root finding} or exact solutions. \index{equation!polynomial!solving} Exact solutions are either members of the ground field or can be presented symbolically as roots of irreducible polynomials. This returns the one rational root along with an irreducible polynomial describing the other solutions. \spadcommand{solve(x**3 = 8,x)} $$ \left[ {x=2}, {{{x \sp 2}+{2 \ x}+4}=0} \right] $$ \returnType{Type: List Equation Fraction Polynomial Integer} If you want solutions expressed in terms of radicals you would use this instead. \index{radical} \spadcommand{radicalSolve(x**3 = 8,x)} $$ \left[ {x={-{\sqrt {-3}} -1}}, {x={{\sqrt {-3}} -1}}, {x=2} \right] $$ \returnType{Type: List Equation Expression Integer} The {\bf solve} command always returns a value but {\bf radicalSolve} returns only the solutions that it is able to express in terms of radicals. \index{radical} If the polynomial equation has rational coefficients you can ask for approximations to its real roots by calling solve with a second argument that specifies the ``precision'' \index{precision} $\epsilon$. This means that each approximation will be within $\pm\epsilon$ of the actual result. Notice that the type of second argument controls the type of the result. \spadcommand{solve(x**4 - 10*x**3 + 35*x**2 - 50*x + 25,.0001)} $$ \left[ {x={3.6180114746 09375}}, {x={1.3819885253 90625}} \right] $$ \returnType{Type: List Equation Polynomial Float} If you give a floating-point precision you get a floating-point result; if you give the precision as a rational number you get a rational result. \spadcommand{solve(x**3-2,1/1000)} $$ \left[ {x={{2581} \over {2048}}} \right] $$ \returnType{Type: List Equation Polynomial Fraction Integer} If you want approximate complex results you should use the \index{approximation} command {\bf complexSolve} that takes the same precision argument $\epsilon$. \spadcommand{complexSolve(x**3-2,.0001)} $$ \begin{array}{@{}l} \left[ {x={1.2599182128 90625}}, \right. \\ \\ \displaystyle {x={-{0.6298943279 5395613131} -{{1.0910949707 03125} \ i}}}, \\ \\ \displaystyle \left. {x={-{0.6298943279 5395613131}+{{1.0910949707 03125} \ i}}} \right] \end{array} $$ \returnType{Type: List Equation Polynomial Complex Float} Each approximation will be within $\pm\epsilon$ of the actual result in each of the real and imaginary parts. \spadcommand{complexSolve(x**2-2*\%i+1,1/100)} $$ \left[ {x={-{{13028925} \over {16777216}} -{{{325} \over {256}} \ i}}}, {x={{{13028925} \over {16777216}}+{{{325} \over {256}} \ i}}} \right] $$ \returnType{Type: List Equation Polynomial Complex Fraction Integer} Note that if you omit the {\tt =} from the first argument Axiom generates an equation by equating the first argument to zero. Also, when only one variable is present in the equation, you do not need to specify the variable to be solved for, that is, you can omit the second argument. Axiom can also solve equations involving rational functions. Solutions where the denominator vanishes are discarded. \spadcommand{radicalSolve(1/x**3 + 1/x**2 + 1/x = 0,x)} $$ \left[ {x={{-{\sqrt {-3}} -1} \over 2}}, {x={{{\sqrt {-3}} -1} \over 2}} \right] $$ \returnType{Type: List Equation Expression Integer} \subsection{Solution of Systems of Polynomial Equations} \label{ugxProblemPolSys} Given a system of equations of rational functions with exact coefficients: \index{equation!polynomial!solving} \vskip 0.1cm $$ \begin{array}{c} p_1(x_1, \ldots, x_n) \\ \vdots \\ p_m(x_1,\ldots,x_n) \end{array} $$ Axiom can find numeric or symbolic solutions. The system is first split into irreducible components, then for each component, a triangular system of equations is found that reduces the problem to sequential solution of univariate polynomials resulting from substitution of partial solutions from the previous stage. $$ \begin{array}{c} q_1(x_1, \ldots, x_n) \\ \vdots \\ q_m(x_n) \end{array} $$ Symbolic solutions can be presented using ``implicit'' algebraic numbers defined as roots of irreducible polynomials or in terms of radicals. Axiom can also find approximations to the real or complex roots of a system of polynomial equations to any user-specified accuracy. The operation {\bf solve} for systems is used in a way similar to {\bf solve} for single equations. Instead of a polynomial equation, one has to give a list of equations and instead of a single variable to solve for, a list of variables. For solutions of single equations see \ref{ugxProblemOnePol} on page~\pageref{ugxProblemOnePol}. Use the operation {\bf solve} if you want implicitly presented solutions. \spadcommand{solve([3*x**3 + y + 1,y**2 -4],[x,y])} $$ \left[ {\left[ {x=-1}, {y=2} \right]}, {\left[ {{{x \sp 2} -x+1}=0}, {y=2} \right]}, {\left[ {{{3 \ {x \sp 3}} -1}=0}, {y=-2} \right]} \right] $$ \returnType{Type: List List Equation Fraction Polynomial Integer} \spadcommand{solve([x = y**2-19,y = z**2+x+3,z = 3*x],[x,y,z])} $$ \left[ {\left[ {x={z \over 3}}, {y={{{3 \ {z \sp 2}}+z+9} \over 3}}, {{{9 \ {z \sp 4}}+{6 \ {z \sp 3}}+{{55} \ {z \sp 2}}+{{15} \ z} -{90}}=0} \right]} \right] $$ \returnType{Type: List List Equation Fraction Polynomial Integer} Use {\bf radicalSolve} if you want your solutions expressed in terms of radicals. \spadcommand{radicalSolve([3*x**3 + y + 1,y**2 -4],[x,y])} $$ \begin{array}{@{}l} \left[ {\left[ {x={{{\sqrt {-3}}+1} \over 2}}, {y=2} \right]}, {\left[ {x={{-{\sqrt {-3}}+1} \over 2}}, {y=2} \right]}, \right. \\ \\ \displaystyle {\left[ {x={{-{{\sqrt {-1}} \ {\sqrt {3}}} -1} \over {2 \ {\root {3} \of {3}}}}}, {y=-2} \right]}, {\left[ {x={{{{\sqrt {-1}} \ {\sqrt {3}}} -1} \over {2 \ {\root {3} \of {3}}}}}, {y=-2} \right]}, \\ \\ \displaystyle \left. {\left[ {x={1 \over {\root {3} \of {3}}}}, {y=-2} \right]}, {\left[ {x=-1}, {y=2} \right]} \right] \end{array} $$ \returnType{Type: List List Equation Expression Integer} To get numeric solutions you only need to give the list of equations and the precision desired. The list of variables would be redundant information since there can be no parameters for the numerical solver. If the precision is expressed as a floating-point number you get results expressed as floats. \spadcommand{solve([x**2*y - 1,x*y**2 - 2],.01)} $$ \left[ {\left[ {y={1.5859375}}, {x={0.79296875}} \right]} \right] $$ \returnType{Type: List List Equation Polynomial Float} To get complex numeric solutions, use the operation {\bf complexSolve}, which takes the same arguments as in the real case. \spadcommand{complexSolve([x**2*y - 1,x*y**2 - 2],1/1000)} $$ \begin{array}{@{}l} \left[ {\left[ {y={{1625} \over {1024}}}, {x={{1625} \over {2048}}} \right]}, \right. \\ \\ \displaystyle {\left[ {y={-{{435445573689} \over {549755813888}} -{{{1407} \over {1024}} \ i}}}, {x={-{{435445573689} \over {1099511627776}} -{{{1407} \over {2048}} \ i}}} \right]}, \\ \\ \displaystyle \left. {\left[ {y={-{{435445573689} \over {549755813888}}+{{{1407} \over {1024}} \ i}}}, {x={-{{435445573689} \over {1099511627776}}+{{{1407} \over {2048}} \ i}}} \right]} \right] \end{array} $$ \returnType{Type: List List Equation Polynomial Complex Fraction Integer} It is also possible to solve systems of equations in rational functions over the rational numbers. Note that $[x = 0.0, a = 0.0]$ is not returned as a solution since the denominator vanishes there. \spadcommand{solve([x**2/a = a,a = a*x],.001)} $$ \left[ {\left[ {x={1.0}}, {a=-{1.0}} \right]}, {\left[ {x={1.0}}, {a={1.0}} \right]} \right] $$ \returnType{Type: List List Equation Polynomial Float} When solving equations with denominators, all solutions where the denominator vanishes are discarded. \spadcommand{radicalSolve([x**2/a + a + y**3 - 1,a*y + a + 1],[x,y])} $$ \begin{array}{@{}l} \left[ {\left[ {x=-{\sqrt {{{-{a \sp 4}+{2 \ {a \sp 3}}+{3 \ {a \sp 2}}+{3 \ a}+1} \over {a \sp 2}}}}}, {y={{-a -1} \over a}} \right]}, \right. \\ \\ \displaystyle \left. {\left[ {x={\sqrt {{{-{a \sp 4}+{2 \ {a \sp 3}}+{3 \ {a \sp 2}}+{3 \ a}+1} \over {a \sp 2}}}}}, {y={{-a -1} \over a}} \right]} \right] \end{array} $$ \returnType{Type: List List Equation Expression Integer} \section{Limits} \label{ugProblemLimits} % To compute a limit, you must specify a functional expression, \index{limit} a variable, and a limiting value for that variable. If you do not specify a direction, Axiom attempts to compute a two-sided limit. Issue this to compute the limit $$\lim_{x \rightarrow 1}{{\displaystyle x^2 - 3x + 2}\over{\displaystyle x^2 - 1}}.$$ \spadcommand{limit((x**2 - 3*x + 2)/(x**2 - 1),x = 1)} $$ -{1 \over 2} $$ \returnType{Type: Union(OrderedCompletion Fraction Polynomial Integer,...)} Sometimes the limit when approached from the left is different from the limit from the right and, in this case, you may wish to ask for a one-sided limit. Also, if you have a function that is only defined on one side of a particular value, \index{limit!one-sided vs. two-sided} you can compute a one-sided limit. The function $log(x)$ is only defined to the right of zero, that is, for $x > 0$. Thus, when computing limits of functions involving $log(x)$, you probably want a ``right-hand'' limit. \spadcommand{limit(x * log(x),x = 0,"right")} $$ 0 $$ \returnType{Type: Union(OrderedCompletion Expression Integer,...)} When you do not specify ``$right$'' or ``$left$'' as the optional fourth argument, {\bf limit} tries to compute a two-sided limit. Here the limit from the left does not exist, as Axiom indicates when you try to take a two-sided limit. \spadcommand{limit(x * log(x),x = 0)} $$ \left[ {leftHandLimit= \mbox{\tt "failed"} }, {rightHandLimit=0} \right] $$ \returnType{Type: Union(Record(leftHandLimit: Union(OrderedCompletion Expression Integer,"failed"), rightHandLimit: Union(OrderedCompletion Expression Integer,"failed")),...)} A function can be defined on both sides of a particular value, but tend to different limits as its variable approaches that value from the left and from the right. We can construct an example of this as follows: Since $\sqrt{y^2}$ is simply the absolute value of $y$, the function $\sqrt{y^2} / y$ is simply the sign ($+1$ or $-1$) of the nonzero real number $y$. Therefore, $\sqrt{y^2} / y = -1$ for $y < 0$ and $\sqrt{y^2} / y = +1$ for $y > 0$. This is what happens when we take the limit at $y = 0$. The answer returned by Axiom gives both a ``left-hand'' and a ``right-hand'' limit. \spadcommand{limit(sqrt(y**2)/y,y = 0)} $$ \left[ {leftHandLimit=-1}, {rightHandLimit=1} \right] $$ \returnType{Type: Union(Record(leftHandLimit: Union(OrderedCompletion Expression Integer,"failed"), rightHandLimit: Union(OrderedCompletion Expression Integer,"failed")),...)} Here is another example, this time using a more complicated function. \spadcommand{limit(sqrt(1 - cos(t))/t,t = 0)} $$ \left[ {leftHandLimit=-{1 \over {\sqrt {2}}}}, {rightHandLimit={1 \over {\sqrt {2}}}} \right] $$ \returnType{Type: Union(Record(leftHandLimit: Union(OrderedCompletion Expression Integer,"failed"), rightHandLimit: Union(OrderedCompletion Expression Integer,"failed")),...)} You can compute limits at infinity by passing either \index{limit!at infinity} $+\infty$ or $-\infty$ as the third argument of {\bf limit}. To do this, use the constants $\%plusInfinity$ and $\%minusInfinity$. \spadcommand{limit(sqrt(3*x**2 + 1)/(5*x),x = \%plusInfinity)} $$ {\sqrt {3}} \over 5 $$ \returnType{Type: Union(OrderedCompletion Expression Integer,...)} \spadcommand{limit(sqrt(3*x**2 + 1)/(5*x),x = \%minusInfinity)} $$ -{{\sqrt {3}} \over 5} $$ \returnType{Type: Union(OrderedCompletion Expression Integer,...)} You can take limits of functions with parameters. \index{limit!of function with parameters} As you can see, the limit is expressed in terms of the parameters. \spadcommand{limit(sinh(a*x)/tan(b*x),x = 0)} $$ a \over b $$ \returnType{Type: Union(OrderedCompletion Expression Integer,...)} When you use {\bf limit}, you are taking the limit of a real function of a real variable. When you compute this, Axiom returns $0$ because, as a function of a real variable, $sin(1/z)$ is always between $-1$ and $1$, so $z * sin(1/z)$ tends to $0$ as $z$ tends to $0$. \spadcommand{limit(z * sin(1/z),z = 0)} $$ 0 $$ \returnType{Type: Union(OrderedCompletion Expression Integer,...)} However, as a function of a {\it complex} variable, $sin(1/z)$ is badly \index{limit!real vs. complex} behaved near $0$ (one says that $sin(1/z)$ has an \index{essential singularity} {\it essential singularity} at $z = 0$). \index{singularity!essential} When viewed as a function of a complex variable, $z * sin(1/z)$ does not approach any limit as $z$ tends to $0$ in the complex plane. Axiom indicates this when we call {\bf complexLimit}. \spadcommand{complexLimit(z * sin(1/z),z = 0)} $$ \mbox{\tt "failed"} $$ \returnType{Type: Union("failed",...)} Here is another example. As $x$ approaches $0$ along the real axis, $exp(-1/x**2)$ tends to $0$. \spadcommand{limit(exp(-1/x**2),x = 0)} $$ 0 $$ \returnType{Type: Union(OrderedCompletion Expression Integer,...)} However, if $x$ is allowed to approach $0$ along any path in the complex plane, the limiting value of $exp(-1/x**2)$ depends on the path taken because the function has an essential singularity at $x=0$. This is reflected in the error message returned by the function. \spadcommand{complexLimit(exp(-1/x**2),x = 0)} $$ \mbox{\tt "failed"} $$ \returnType{Type: Union("failed",...)} You can also take complex limits at infinity, that is, limits of a function of $z$ as $z$ approaches infinity on the Riemann sphere. Use the symbol $\%infinity$ to denote ``complex infinity.'' As above, to compute complex limits rather than real limits, use {\bf complexLimit}. \spadcommand{complexLimit((2 + z)/(1 - z),z = \%infinity)} $$ -1 $$ \returnType{Type: OnePointCompletion Fraction Polynomial Integer} In many cases, a limit of a real function of a real variable exists when the corresponding complex limit does not. This limit exists. \spadcommand{limit(sin(x)/x,x = \%plusInfinity)} $$ 0 $$ \returnType{Type: Union(OrderedCompletion Expression Integer,...)} But this limit does not. \spadcommand{complexLimit(sin(x)/x,x = \%infinity)} $$ \mbox{\tt "failed"} $$ \returnType{Type: Union("failed",...)} \section{Laplace Transforms} \label{ugProblemLaplace} Axiom can compute some forward Laplace transforms, mostly \index{Laplace transform} of elementary \index{function!elementary} functions \index{transform!Laplace} not involving logarithms, although some cases of special functions are handled. To compute the forward Laplace transform of $F(t)$ with respect to $t$ and express the result as $f(s)$, issue the command $laplace(F(t), t, s)$. \spadcommand{laplace(sin(a*t)*cosh(a*t)-cos(a*t)*sinh(a*t), t, s)} $$ {4 \ {a \sp 3}} \over {{s \sp 4}+{4 \ {a \sp 4}}} $$ \returnType{Type: Expression Integer} Here are some other non-trivial examples. \spadcommand{laplace((exp(a*t) - exp(b*t))/t, t, s)} $$ -{\log \left({{s -a}} \right)}+{\log\left({{s -b}} \right)} $$ \returnType{Type: Expression Integer} \spadcommand{laplace(2/t * (1 - cos(a*t)), t, s)} $$ {\log \left({{{s \sp 2}+{a \sp 2}}} \right)}-{2 \ {\log \left({s} \right)}} $$ \returnType{Type: Expression Integer} \spadcommand{laplace(exp(-a*t) * sin(b*t) / b**2, t, s)} $$ 1 \over {{b \ {s \sp 2}}+{2 \ a \ b \ s}+{b \sp 3}+{{a \sp 2} \ b}} $$ \returnType{Type: Expression Integer} \spadcommand{laplace((cos(a*t) - cos(b*t))/t, t, s)} $$ {{\log \left({{{s \sp 2}+{b \sp 2}}} \right)}- {\log \left({{{s \sp 2}+{a \sp 2}}} \right)}} \over 2 $$ \returnType{Type: Expression Integer} Axiom also knows about a few special functions. \spadcommand{laplace(exp(a*t+b)*Ei(c*t), t, s)} $$ {{e \sp b} \ {\log \left({{{s+c -a} \over c}} \right)}}\over {s -a} $$ \returnType{Type: Expression Integer} \spadcommand{laplace(a*Ci(b*t) + c*Si(d*t), t, s)} $$ {{a \ {\log \left({{{{s \sp 2}+{b \sp 2}} \over {b \sp 2}}} \right)}}+ {2\ c \ {\arctan \left({{d \over s}} \right)}}}\over {2 \ s} $$ \returnType{Type: Expression Integer} When Axiom does not know about a particular transform, it keeps it as a formal transform in the answer. \spadcommand{laplace(sin(a*t) - a*t*cos(a*t) + exp(t**2), t, s)} $$ {{{\left( {s \sp 4}+{2 \ {a \sp 2} \ {s \sp 2}}+{a \sp 4} \right)} \ {laplace \left({{e \sp {t \sp 2}}, t, s} \right)}}+ {2\ {a \sp 3}}} \over {{s \sp 4}+{2 \ {a \sp 2} \ {s \sp 2}}+{a \sp 4}} $$ \returnType{Type: Expression Integer} \section{Integration} \label{ugProblemIntegration} % Integration is the reverse process of differentiation, that is, \index{integration} an {\it integral} of a function $f$ with respect to a variable $x$ is any function $g$ such that $D(g,x)$ is equal to $f$. The package {\tt FunctionSpaceIntegration} provides the top-level integration operation, \spadfunFrom{integrate}{FunctionSpaceIntegration}, for integrating real-valued elementary functions. \index{FunctionSpaceIntegration} \spadcommand{integrate(cosh(a*x)*sinh(a*x), x)} $$ {{{\sinh \left({{a \ x}} \right)}\sp 2}+ {{\cosh \left({{a \ x}} \right)}\sp 2}} \over {4 \ a} $$ \returnType{Type: Union(Expression Integer,...)} Unfortunately, antiderivatives of most functions cannot be expressed in terms of elementary functions. \spadcommand{integrate(log(1 + sqrt(a * x + b)) / x, x)} $$ \int \sp{\displaystyle x} {{{\log \left( {{{\sqrt {{b+{ \%M \ a}}}}+1}} \right)} \over \%M} \ {d \%M}} $$ \returnType{Type: Union(Expression Integer,...)} Given an elementary function to integrate, Axiom returns a formal integral as above only when it can prove that the integral is not elementary and not when it cannot determine the integral. In this rare case it prints a message that it cannot determine if an elementary integral exists. Similar functions may have antiderivatives \index{antiderivative} that look quite different because the form of the antiderivative depends on the sign of a constant that appears in the function. \spadcommand{integrate(1/(x**2 - 2),x)} $$ {\log \left({{{{{\left( {x \sp 2}+2 \right)}\ {\sqrt {2}}} -{4 \ x}} \over {{x \sp 2} -2}}} \right)} \over {2 \ {\sqrt {2}}} $$ \returnType{Type: Union(Expression Integer,...)} \spadcommand{integrate(1/(x**2 + 2),x)} $$ {\arctan \left({{{x \ {\sqrt {2}}} \over 2}} \right)}\over {\sqrt {2}} $$ \returnType{Type: Union(Expression Integer,...)} If the integrand contains parameters, then there may be several possible antiderivatives, depending on the signs of expressions of the parameters. In this case Axiom returns a list of answers that cover all the possible cases. Here you use the answer involving the square root of $a$ when $a > 0$ and \index{integration!result as list of real functions} the answer involving the square root of $-a$ when $a < 0$. \spadcommand{integrate(x**2 / (x**4 - a**2), x)} $$ \begin{array}{@{}l} \left[ {{{\log \left( {{{{{\left( {x \sp 2}+a \right)} \ {\sqrt {a}}} -{2 \ a \ x}} \over {{x \sp 2} -a}}} \right)}+ {2\ {\arctan \left({{{x \ {\sqrt {a}}} \over a}} \right)}}} \over {4 \ {\sqrt {a}}}}, \right. \\ \\ \displaystyle \left. {{{\log \left({{{{{\left( {x \sp 2} -a \right)} \ {\sqrt {-a}}}+{2 \ a \ x}} \over {{x \sp 2}+a}}} \right)} -{2 \ {\arctan \left({{{x \ {\sqrt {-a}}} \over a}} \right)}}} \over {4 \ {\sqrt {-a}}}} \right] \end{array} $$ \returnType{Type: Union(List Expression Integer,...)} If the parameters and the variables of integration can be complex numbers rather than real, then the notion of sign is not defined. In this case all the possible answers can be expressed as one complex function. To get that function, rather than a list of real functions, use \spadfunFrom{complexIntegrate}{FunctionSpaceComplexIntegration}, which is provided by the package \index{integration!result as a complex functions} {\tt FunctionSpaceComplexIntegration}. \index{FunctionSpaceComplexIntegration} This operation is used for integrating complex-valued elementary functions. \spadcommand{complexIntegrate(x**2 / (x**4 - a**2), x)} $$ \left( \begin{array}{@{}l} {{\sqrt {{4 \ a}}} \ {\log \left( {{{{x \ {\sqrt {-{4 \ a}}}}+{2 \ a}} \over {\sqrt {-{4 \ a}}}}} \right)}} - {{\sqrt {-{4 \ a}}} \ {\log \left( {{{{x \ {\sqrt {{4 \ a}}}}+{2 \ a}} \over {\sqrt {{4 \ a}}}}} \right)}}+ \\ \\ \displaystyle {{\sqrt{-{4 \ a}}} \ {\log \left( {{{{x \ {\sqrt {{4 \ a}}}} -{2 \ a}} \over {\sqrt {{4 \ a}}}}} \right)}} -{{\sqrt {{4 \ a}}} \ {\log \left( {{{{x \ {\sqrt {-{4 \ a}}}} -{2 \ a}} \over {\sqrt {-{4 \ a}}}}} \right)}} \end{array} \right) \over {2 \ {\sqrt {-{4 \ a}}} \ {\sqrt {{4 \ a}}}} $$ \returnType{Type: Expression Integer} As with the real case, antiderivatives for most complex-valued functions cannot be expressed in terms of elementary functions. \spadcommand{complexIntegrate(log(1 + sqrt(a * x + b)) / x, x)} $$ \int \sp{\displaystyle x} {{{\log \left({{{\sqrt {{b+{ \%M \ a}}}}+1}} \right)} \over \%M} \ {d \%M}} $$ \returnType{Type: Expression Integer} Sometimes {\bf integrate} can involve symbolic algebraic numbers such as those returned by \spadfunFrom{rootOf}{Expression}. To see how to work with these strange generated symbols (such as $\%\%a0$), see \ref{ugxProblemSymRootAll} on page~\pageref{ugxProblemSymRootAll}. Definite integration is the process of computing the area between \index{integration!definite} the $x$-axis and the curve of a function $f(x)$. The fundamental theorem of calculus states that if $f$ is continuous on an interval $a..b$ and if there exists a function $g$ that is differentiable on $a..b$ and such that $D(g, x)$ is equal to $f$, then the definite integral of $f$ for $x$ in the interval $a..b$ is equal to $g(b) - g(a)$. The package {\tt RationalFunctionDefiniteIntegration} provides the top-level definite integration operation, \spadfunFrom{integrate}{RationalFunctionDefiniteIntegration}, for integrating real-valued rational functions. \spadcommand{integrate((x**4 - 3*x**2 + 6)/(x**6-5*x**4+5*x**2+4), x = 1..2)} $$ {{2 \ {\arctan \left({8} \right)}}+ {2\ {\arctan \left({5} \right)}}+ {2\ {\arctan \left({2} \right)}}+ {2\ {\arctan \left({{1 \over 2}} \right)}} -\pi} \over 2 $$ \returnType{Type: Union(f1: OrderedCompletion Expression Integer,...)} Axiom checks beforehand that the function you are integrating is defined on the interval $a..b$, and prints an error message if it finds that this is not case, as in the following example: \begin{verbatim} integrate(1/(x**2-2), x = 1..2) >> Error detected within library code: Pole in path of integration You are being returned to the top level of the interpreter. \end{verbatim} When parameters are present in the function, the function may or may not be defined on the interval of integration. If this is the case, Axiom issues a warning that a pole might lie in the path of integration, and does not compute the integral. \spadcommand{integrate(1/(x**2-a), x = 1..2)} $$ potentialPole $$ \returnType{Type: Union(pole: potentialPole,...)} If you know that you are using values of the parameter for which the function has no pole in the interval of integration, use the string {\tt ``noPole''} as a third argument to \spadfunFrom{integrate}{RationalFunctionDefiniteIntegration}: The value here is, of course, incorrect if $sqrt(a)$ is between $1$ and $2.$ \spadcommand{integrate(1/(x**2-a), x = 1..2, "noPole")} $$ \begin{array}{@{}l} \left[ \left( \begin{array}{@{}l} -{\log \left({{{{{\left( -{4 \ {a \sp 2}} -{4 \ a} \right)} \ {\sqrt {a}}}+{a \sp 3}+{6 \ {a \sp 2}}+a} \over {{a \sp 2} -{2 \ a}+1}}} \right)}+ \\ \\ \displaystyle {\log\left({{{{{\left( -{8 \ {a \sp 2}} -{{32} \ a} \right)} \ {\sqrt {a}}}+{a \sp 3}+{{24} \ {a \sp 2}}+{{16} \ a}} \over {{a \sp 2} -{8 \ a}+{16}}}} \right)} \end{array} \right) \over {4 \ {\sqrt {a}}}, \right. \\ \\ \displaystyle \left. {{-{\arctan \left({{{2 \ {\sqrt {-a}}} \over a}} \right)}+ {\arctan\left({{{\sqrt {-a}} \over a}} \right)}} \over {\sqrt {-a}}} \right] \end{array} $$ \returnType{Type: Union(f2: List OrderedCompletion Expression Integer,...)} \section{Working with Power Series} \label{ugProblemSeries} % Axiom has very sophisticated facilities for working with power \index{series} series. \index{power series} Infinite series are represented by a list of the coefficients that have already been determined, together with a function for computing the additional coefficients if needed. The system command that determines how many terms of a series is displayed is {\tt )set streams calculate}. For the purposes of this book, we have used this system command to display fewer than ten terms. \index{set streams calculate} Series can be created from expressions, from functions for the series coefficients, and from applications of operations on existing series. The most general function for creating a series is called {\bf series}, although you can also use {\bf taylor}, {\bf laurent} and {\bf puiseux} in situations where you know what kind of exponents are involved. For information about solving differential equations in terms of power series, see \ref{ugxProblemDEQSeries} on page~\pageref{ugxProblemDEQSeries}. \subsection{Creation of Power Series} \label{ugxProblemSeriesCreate} This is the easiest way to create a power series. This tells Axiom that $x$ is to be treated as a power series, \index{series!creating} so functions of $x$ are again power series. \spadcommand{x := series 'x } $$ x $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} We didn't say anything about the coefficients of the power series, so the coefficients are general expressions over the integers. This allows us to introduce denominators, symbolic constants, and other variables as needed. Here the coefficients are integers (note that the coefficients are the Fibonacci \index{Fibonacci numbers} numbers). \spadcommand{1/(1 - x - x**2) } $$ 1+x+ {2 \ {x \sp 2}}+ {3 \ {x \sp 3}}+ {5 \ {x \sp 4}}+ {8 \ {x \sp 5}}+ {{13} \ {x \sp 6}}+ {{21} \ {x \sp 7}}+ {{34} \ {x \sp 8}}+ {{55} \ {x \sp 9}}+ {{89} \ {x \sp {10}}}+ {O \left({{x \sp {11}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} This series has coefficients that are rational numbers. \spadcommand{sin(x) } $$ x - {{1 \over 6} \ {x \sp 3}}+ {{1 \over {120}} \ {x \sp 5}} - {{1 \over {5040}} \ {x \sp 7}}+ {{1 \over {362880}} \ {x \sp 9}} - {{1 \over {39916800}} \ {x \sp {11}}}+ {O \left({{x \sp {12}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} When you enter this expression you introduce the symbolic constants $sin(1)$ and $cos(1).$ \spadcommand{sin(1 + x) } $$ \begin{array}{@{}l} {\sin \left({1} \right)}+ {{\cos\left({1} \right)}\ x} - {{{\sin \left({1} \right)}\over 2} \ {x \sp 2}} - {{{\cos \left({1} \right)}\over 6} \ {x \sp 3}}+ {{{\sin \left({1} \right)}\over {24}} \ {x \sp 4}}+ {{{\cos \left({1} \right)}\over {120}} \ {x \sp 5}} - {{{\sin \left({1} \right)}\over {720}} \ {x \sp 6}} - \\ \\ \displaystyle {{{\cos \left({1} \right)}\over {5040}} \ {x \sp 7}}+ {{{\sin \left({1} \right)}\over {40320}} \ {x \sp 8}}+ {{{\cos \left({1} \right)}\over {362880}} \ {x \sp 9}} - {{{\sin \left({1} \right)}\over {3628800}} \ {x \sp {10}}}+ {O \left({{x \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} When you enter the expression the variable $a$ appears in the resulting series expansion. \spadcommand{sin(a * x) } $$ {a \ x} - {{{a \sp 3} \over 6} \ {x \sp 3}}+ {{{a \sp 5} \over {120}} \ {x \sp 5}} - {{{a \sp 7} \over {5040}} \ {x \sp 7}}+ {{{a \sp 9} \over {362880}} \ {x \sp 9}} - {{{a \sp {11}} \over {39916800}} \ {x \sp {11}}}+ {O \left({{x \sp {12}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} You can also convert an expression into a series expansion. This expression creates the series expansion of $1/log(y)$ about $y = 1$. For details and more examples, see \ref{ugxProblemSeriesConversions} on page~\pageref{ugxProblemSeriesConversions}. \spadcommand{series(1/log(y),y = 1)} $$ \begin{array}{@{}l} {{\left( y -1 \right)}\sp {\left( -1 \right)}}+ {1\over 2} -{{1 \over {12}} \ {\left( y -1 \right)}}+ {{1\over {24}} \ {{\left( y -1 \right)}\sp 2}} - {{{19} \over {720}} \ {{\left( y -1 \right)}\sp 3}}+ {{3 \over {160}} \ {{\left( y -1 \right)}\sp 4}} - \\ \\ \displaystyle {{{863} \over {60480}} \ {{\left( y -1 \right)}\sp 5}}+ {{{275} \over {24192}} \ {{\left( y -1 \right)}\sp 6}} - {{{33953} \over {3628800}} \ {{\left( y -1 \right)}\sp 7}}+ \\ \\ \displaystyle {{{8183} \over {1036800}} \ {{\left( y -1 \right)}\sp 8}} - {{{3250433} \over {479001600}} \ {{\left( y -1 \right)}\sp 9}}+ {O \left({{{\left( y -1 \right)}\sp {10}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,y,1)} You can create power series with more general coefficients. You normally accomplish this via a type declaration (see \ref{ugTypesDeclare} on page~\pageref{ugTypesDeclare}). See \ref{ugxProblemSeriesFunctions} on page~\pageref{ugxProblemSeriesFunctions} for some warnings about working with declared series. We declare that $y$ is a one-variable Taylor series \index{series!Taylor} ({\tt UTS} is the abbreviation for {\tt UnivariateTaylorSeries}) in the variable $z$ with {\tt FLOAT} (that is, floating-point) coefficients, centered about $0.$ Then, by assignment, we obtain the Taylor expansion of $exp(z)$ with floating-point coefficients. \index{UnivariateTaylorSeries} \spadcommand{y : UTS(FLOAT,'z,0) := exp(z) } $$ \begin{array}{@{}l} {1.0}+z+ {{0.5} \ {z \sp 2}}+ {{0.1666666666\ 6666666667} \ {z \sp 3}}+ \\ \\ \displaystyle {{0.0416666666\ 6666666666 7} \ {z \sp 4}}+ {{0.0083333333\ 3333333333 34} \ {z \sp 5}}+ \\ \\ \displaystyle {{0.0013888888\ 8888888888 89} \ {z \sp 6}}+ {{0.0001984126\ 9841269841 27} \ {z \sp 7}}+ \\ \\ \displaystyle {{0.0000248015\ 8730158730 1587} \ {z \sp 8}}+ {{0.0000027557\ 3192239858 90653} \ {z \sp 9}}+ \\ \\ \displaystyle {{0.2755731922\ 3985890653 E -6} \ {z \sp {10}}}+ {O \left({{z \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariateTaylorSeries(Float,z,0.0)} You can also create a power series by giving an explicit formula for its $n$-th coefficient. For details and more examples, see \ref{ugxProblemSeriesFormula} on page~\pageref{ugxProblemSeriesFormula}. To create a series about $w = 0$ whose $n$-th Taylor coefficient is $1/n!$, you can evaluate this expression. This is the Taylor expansion of $exp(w)$ at $w = 0$. \spadcommand{series(1/factorial(n),n,w = 0)} $$ \begin{array}{@{}l} 1+w+ {{1 \over 2} \ {w \sp 2}}+ {{1 \over 6} \ {w \sp 3}}+ {{1 \over {24}} \ {w \sp 4}}+ {{1 \over {120}} \ {w \sp 5}}+ {{1 \over {720}} \ {w \sp 6}}+ {{1 \over {5040}} \ {w \sp 7}}+ \\ \\ \displaystyle {{1 \over {40320}} \ {w \sp 8}}+ {{1 \over {362880}} \ {w \sp 9}}+ {{1 \over {3628800}} \ {w \sp {10}}}+ {O \left({{w \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,w,0)} \subsection{Coefficients of Power Series} \label{ugxProblemSeriesCoefficients} You can extract any coefficient from a power series---even one that hasn't been computed yet. This is possible because in Axiom, infinite series are represented by a list of the coefficients that have already been determined, together with a function for computing the additional coefficients. (This is known as {\it lazy evaluation}.) When you ask for a \index{series!lazy evaluation} coefficient that hasn't yet been computed, Axiom computes \index{lazy evaluation} whatever additional coefficients it needs and then stores them in the representation of the power series. Here's an example of how to extract the coefficients of a power series. \index{series!extracting coefficients} \spadcommand{x := series(x) } $$ x $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \spadcommand{y := exp(x) * sin(x) } $$ \begin{array}{@{}l} x+ {x \sp 2}+ {{1 \over 3} \ {x \sp 3}} - {{1 \over {30}} \ {x \sp 5}} - {{1 \over {90}} \ {x \sp 6}} - {{1 \over {630}} \ {x \sp 7}}+ {{1 \over {22680}} \ {x \sp 9}}+ \\ \\ \displaystyle {{1 \over {113400}} \ {x \sp {10}}}+ {{1 \over {1247400}} \ {x \sp {11}}}+ {O \left({{x \sp {12}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} This coefficient is readily available. \spadcommand{coefficient(y,6) } $$ -{1 \over {90}} $$ \returnType{Type: Expression Integer} But let's get the fifteenth coefficient of $y$. \spadcommand{coefficient(y,15) } $$ -{1 \over {10216206000}} $$ \returnType{Type: Expression Integer} If you look at $y$ then you see that the coefficients up to order $15$ have all been computed. \spadcommand{y } $$ \begin{array}{@{}l} x+ {x \sp 2}+ {{1 \over 3} \ {x \sp 3}} - {{1 \over {30}} \ {x \sp 5}} - {{1 \over {90}} \ {x \sp 6}} - {{1 \over {630}} \ {x \sp 7}}+ {{1 \over {22680}} \ {x \sp 9}}+ {{1 \over {113400}} \ {x \sp {10}}}+ \\ \\ \displaystyle {{1 \over {1247400}} \ {x \sp {11}}} - {{1 \over {97297200}} \ {x \sp {13}}} - {{1 \over {681080400}} \ {x \sp {14}}} - {{1 \over {10216206000}} \ {x \sp {15}}}+ {O \left({{x \sp {16}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \subsection{Power Series Arithmetic} \label{ugxProblemSeriesArithmetic} You can manipulate power series using the usual arithmetic operations \index{series!arithmetic} $+$, $-$, $*$, and $/$ (from UnivariatePuiseuxSeries) The results of these operations are also power series. \spadcommand{x := series x } $$ x $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \spadcommand{(3 + x) / (1 + 7*x)} $$ \begin{array}{@{}l} 3 - {{20} \ x}+ {{140} \ {x \sp 2}} - {{980} \ {x \sp 3}}+ {{6860} \ {x \sp 4}} - {{48020} \ {x \sp 5}}+ {{336140} \ {x \sp 6}} - {{2352980} \ {x \sp 7}}+ \\ \\ \displaystyle {{16470860} \ {x \sp 8}} - {{115296020} \ {x \sp 9}}+ {{807072140} \ {x \sp {10}}}+ {O \left({{x \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} You can also compute $f(x) ** g(x)$, where $f(x)$ and $g(x)$ are two power series. \spadcommand{base := 1 / (1 - x) } $$ 1+x+ {x \sp 2}+ {x \sp 3}+ {x \sp 4}+ {x \sp 5}+ {x \sp 6}+ {x \sp 7}+ {x \sp 8}+ {x \sp 9}+ {x \sp {10}}+ {O \left({{x \sp {11}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \spadcommand{expon := x * base } $$ x+ {x \sp 2}+ {x \sp 3}+ {x \sp 4}+ {x \sp 5}+ {x \sp 6}+ {x \sp 7}+ {x \sp 8}+ {x \sp 9}+ {x \sp {10}}+ {x \sp {11}}+ {O \left({{x \sp {12}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \spadcommand{base ** expon } $$ \begin{array}{@{}l} 1+ {x \sp 2}+ {{3 \over 2} \ {x \sp 3}}+ {{7 \over 3} \ {x \sp 4}}+ {{{43} \over {12}} \ {x \sp 5}}+ {{{649} \over {120}} \ {x \sp 6}}+ {{{241} \over {30}} \ {x \sp 7}}+ {{{3706} \over {315}} \ {x \sp 8}}+ \\ \\ \displaystyle {{{85763} \over {5040}} \ {x \sp 9}}+ {{{245339} \over {10080}} \ {x \sp {10}}}+ {O \left({{x \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \subsection{Functions on Power Series} \label{ugxProblemSeriesFunctions} Once you have created a power series, you can apply transcendental functions (for example, {\bf exp}, {\bf log}, {\bf sin}, {\bf tan}, {\bf cosh}, etc.) to it. To demonstrate this, we first create the power series expansion of the rational function $${\displaystyle x^2} \over {\displaystyle 1 - 6x + x^2}$$ about $x = 0$. \spadcommand{x := series 'x } $$ x $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \spadcommand{rat := x**2 / (1 - 6*x + x**2) } $$ \begin{array}{@{}l} {x \sp 2}+ {6 \ {x \sp 3}}+ {{35} \ {x \sp 4}}+ {{204} \ {x \sp 5}}+ {{1189} \ {x \sp 6}}+ {{6930} \ {x \sp 7}}+ {{40391} \ {x \sp 8}}+ {{235416} \ {x \sp 9}}+ \\ \\ \displaystyle {{1372105} \ {x \sp {10}}}+ {{7997214} \ {x \sp {11}}}+ {{46611179} \ {x \sp {12}}}+ {O \left({{x \sp {13}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} If you want to compute the series expansion of $$\sin\left({\displaystyle x^2} \over {\displaystyle 1 - 6x + x^2}\right)$$ you simply compute the sine of $rat$. \spadcommand{sin(rat) } $$ \begin{array}{@{}l} {x \sp 2}+ {6 \ {x \sp 3}}+ {{35} \ {x \sp 4}}+ {{204} \ {x \sp 5}}+ {{{7133} \over 6} \ {x \sp 6}}+ {{6927} \ {x \sp 7}}+ {{{80711} \over 2} \ {x \sp 8}}+ {{235068} \ {x \sp 9}}+ \\ \\ \displaystyle {{{164285281} \over {120}} \ {x \sp {10}}}+ {{{31888513} \over 4} \ {x \sp {11}}}+ {{{371324777} \over 8} \ {x \sp {12}}}+ {O \left({{x \sp {13}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \boxed{4.6in}{ \vskip 0.1cm \noindent {\bf Warning:} the type of the coefficients of a power series may affect the kind of computations that you can do with that series. This can only happen when you have made a declaration to specify a series domain with a certain type of coefficient.\\ } If you evaluate then you have declared that $y$ is a one variable Taylor series \index{series!Taylor} ({\tt UTS} is the abbreviation for {\tt UnivariateTaylorSeries}) in the variable $y$ with {\tt FRAC INT} (that is, fractions of integer) coefficients, centered about $0$. \spadcommand{y : UTS(FRAC INT,y,0) := y } $$ y $$ \returnType{Type: UnivariateTaylorSeries(Fraction Integer,y,0)} You can now compute certain power series in $y$, {\it provided} that these series have rational coefficients. \spadcommand{exp(y) } $$ \begin{array}{@{}l} 1+y+ {{1 \over 2} \ {y \sp 2}}+ {{1 \over 6} \ {y \sp 3}}+ {{1 \over {24}} \ {y \sp 4}}+ {{1 \over {120}} \ {y \sp 5}}+ {{1 \over {720}} \ {y \sp 6}}+ {{1 \over {5040}} \ {y \sp 7}}+ {{1 \over {40320}} \ {y \sp 8}}+ \\ \\ \displaystyle {{1 \over {362880}} \ {y \sp 9}}+ {{1 \over {3628800}} \ {y \sp {10}}}+ {O \left({{y \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariateTaylorSeries(Fraction Integer,y,0)} You can get examples of such series by applying transcendental functions to series in $y$ that have no constant terms. \spadcommand{tan(y**2) } $$ {y \sp 2}+ {{1 \over 3} \ {y \sp 6}}+ {{2 \over {15}} \ {y \sp {10}}}+ {O \left({{y \sp {11}}} \right)} $$ \returnType{Type: UnivariateTaylorSeries(Fraction Integer,y,0)} \spadcommand{cos(y + y**5) } $$ 1 - {{1 \over 2} \ {y \sp 2}}+ {{1 \over {24}} \ {y \sp 4}} - {{{721} \over {720}} \ {y \sp 6}}+ {{{6721} \over {40320}} \ {y \sp 8}} - {{{1844641} \over {3628800}} \ {y \sp {10}}}+ {O \left({{y \sp {11}}} \right)} $$ \returnType{Type: UnivariateTaylorSeries(Fraction Integer,y,0)} Similarly, you can compute the logarithm of a power series with rational coefficients if the constant coefficient is $1.$ \spadcommand{log(1 + sin(y)) } $$ \begin{array}{@{}l} y - {{1 \over 2} \ {y \sp 2}}+ {{1 \over 6} \ {y \sp 3}} - {{1 \over {12}} \ {y \sp 4}}+ {{1 \over {24}} \ {y \sp 5}} - {{1 \over {45}} \ {y \sp 6}}+ {{{61} \over {5040}} \ {y \sp 7}} - {{{17} \over {2520}} \ {y \sp 8}}+ {{{277} \over {72576}} \ {y \sp 9}} - \\ \\ \displaystyle {{{31} \over {14175}} \ {y \sp {10}}}+ {O \left({{y \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariateTaylorSeries(Fraction Integer,y,0)} If you wanted to apply, say, the operation {\bf exp} to a power series with a nonzero constant coefficient $a_0$, then the constant coefficient of the result would be $e^{a_0}$, which is {\it not} a rational number. Therefore, evaluating $exp(2 + tan(y))$ would generate an error message. If you want to compute the Taylor expansion of $exp(2 + tan(y))$, you must ensure that the coefficient domain has an operation {\bf exp} defined for it. An example of such a domain is {\tt Expression Integer}, the type of formal functional expressions over the integers. When working with coefficients of this type, \spadcommand{z : UTS(EXPR INT,z,0) := z } $$ z $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,z,0)} this presents no problems. \spadcommand{exp(2 + tan(z)) } $$ \begin{array}{@{}l} {e \sp 2}+ {{e \sp 2} \ z}+ {{{e \sp 2} \over 2} \ {z \sp 2}}+ {{{e \sp 2} \over 2} \ {z \sp 3}}+ {{{3 \ {e \sp 2}} \over 8} \ {z \sp 4}}+ {{{{37} \ {e \sp 2}} \over {120}} \ {z \sp 5}}+ {{{{59} \ {e \sp 2}} \over {240}} \ {z \sp 6}}+ {{{{137} \ {e \sp 2}} \over {720}} \ {z \sp 7}}+ \\ \\ \displaystyle {{{{871} \ {e \sp 2}} \over {5760}} \ {z \sp 8}}+ {{{{41641} \ {e \sp 2}} \over {362880}} \ {z \sp 9}}+ {{{{325249} \ {e \sp 2}} \over {3628800}} \ {z \sp {10}}}+ {O \left({{z \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,z,0)} Another way to create Taylor series whose coefficients are expressions over the integers is to use {\bf taylor} which works similarly to \index{series!Taylor} {\bf series}. This is equivalent to the previous computation, except that now we are using the variable $w$ instead of $z$. \spadcommand{w := taylor 'w } $$ w $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,w,0)} \spadcommand{exp(2 + tan(w)) } $$ \begin{array}{@{}l} {e \sp 2}+ {{e \sp 2} \ w}+ {{{e \sp 2} \over 2} \ {w \sp 2}}+ {{{e \sp 2} \over 2} \ {w \sp 3}}+ {{{3 \ {e \sp 2}} \over 8} \ {w \sp 4}}+ {{{{37} \ {e \sp 2}} \over {120}} \ {w \sp 5}}+ {{{{59} \ {e \sp 2}} \over {240}} \ {w \sp 6}}+ {{{{137} \ {e \sp 2}} \over {720}} \ {w \sp 7}}+ \\ \\ \displaystyle {{{{871} \ {e \sp 2}} \over {5760}} \ {w \sp 8}}+ {{{{41641} \ {e \sp 2}} \over {362880}} \ {w \sp 9}}+ {{{{325249} \ {e \sp 2}} \over {3628800}} \ {w \sp {10}}}+ {O \left({{w \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,w,0)} \subsection{Converting to Power Series} \label{ugxProblemSeriesConversions} The {\tt ExpressionToUnivariatePowerSeries} package provides operations for computing series expansions of functions. \index{ExpressionToUnivariatePowerSeries} Evaluate this to compute the Taylor expansion of $sin x$ about \index{series!Taylor} $x = 0$. The first argument, $sin(x)$, specifies the function whose series expansion is to be computed and the second argument, $x = 0$, specifies that the series is to be expanded in power of $(x - 0)$, that is, in power of $x$. \spadcommand{taylor(sin(x),x = 0)} $$ x - {{1 \over 6} \ {x \sp 3}}+ {{1 \over {120}} \ {x \sp 5}} - {{1 \over {5040}} \ {x \sp 7}}+ {{1 \over {362880}} \ {x \sp 9}}+ {O \left({{x \sp {11}}} \right)} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,x,0)} Here is the Taylor expansion of $sin x$ about $x = \frac{\pi}{6}$: \spadcommand{taylor(sin(x),x = \%pi/6)} $$ \begin{array}{@{}l} {1 \over 2}+ {{{\sqrt {3}} \over 2} \ {\left( x -{\pi \over 6} \right)}} -{{1 \over 4} \ {{\left( x -{\pi \over 6} \right)}\sp 2}} - {{{\sqrt {3}} \over {12}} \ {{\left( x -{\pi \over 6} \right)}\sp 3}}+ {{1 \over {48}} \ {{\left( x -{\pi \over 6} \right)}\sp 4}}+ \\ \\ \displaystyle {{{\sqrt {3}} \over {240}} \ {{\left( x -{\pi \over 6} \right)}\sp 5}} - {{1 \over {1440}} \ {{\left( x -{\pi \over 6} \right)}\sp 6}} - {{{\sqrt {3}} \over {10080}} \ {{\left( x -{\pi \over 6} \right)}\sp 7}}+ {{1 \over {80640}} \ {{\left( x -{\pi \over 6} \right)}\sp 8}}+ \\ \\ \displaystyle {{{\sqrt {3}} \over {725760}} \ {{\left( x -{\pi \over 6} \right)}\sp 9}} - {{1 \over {7257600}} \ {{\left( x -{\pi \over 6} \right)}\sp {10}}}+ {O \left({{{\left( x -{\pi \over 6} \right)}\sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,x,pi/6)} The function to be expanded into a series may have variables other than \index{series!multiple variables} the series variable. For example, we may expand $tan(x*y)$ as a Taylor series in $x$ \spadcommand{taylor(tan(x*y),x = 0)} $$ {y \ x}+ {{{y \sp 3} \over 3} \ {x \sp 3}}+ {{{2 \ {y \sp 5}} \over {15}} \ {x \sp 5}}+ {{{{17} \ {y \sp 7}} \over {315}} \ {x \sp 7}}+ {{{{62} \ {y \sp 9}} \over {2835}} \ {x \sp 9}}+ {O \left({{x \sp {11}}} \right)} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,x,0)} or as a Taylor series in $y$. \spadcommand{taylor(tan(x*y),y = 0)} $$ {x \ y}+ {{{x \sp 3} \over 3} \ {y \sp 3}}+ {{{2 \ {x \sp 5}} \over {15}} \ {y \sp 5}}+ {{{{17} \ {x \sp 7}} \over {315}} \ {y \sp 7}}+ {{{{62} \ {x \sp 9}} \over {2835}} \ {y \sp 9}}+ {O \left({{y \sp {11}}} \right)} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,y,0)} A more interesting function is $${\displaystyle t e^{x t}} \over{\displaystyle e^t - 1}$$ When we expand this function as a Taylor series in $t$ the $n$-th order coefficient is the $n$-th Bernoulli \index{Bernoulli!polynomial} polynomial \index{polynomial!Bernoulli} divided by $n!$. \spadcommand{bern := taylor(t*exp(x*t)/(exp(t) - 1),t = 0) } $$ \begin{array}{@{}l} 1+ {{{{2 \ x} -1} \over 2} \ t}+ {{{{6 \ {x \sp 2}} -{6 \ x}+1} \over {12}} \ {t \sp 2}}+ {{{{2 \ {x \sp 3}} -{3 \ {x \sp 2}}+x} \over {12}} \ {t \sp 3}}+ \\ \\ \displaystyle {{{{{30} \ {x \sp 4}} -{{60} \ {x \sp 3}}+{{30} \ {x \sp 2}} -1} \over {720}} \ {t \sp 4}}+ {{{{6 \ {x \sp 5}} -{{15} \ {x \sp 4}}+{{10} \ {x \sp 3}} -x} \over {720}} \ {t \sp 5}}+ \\ \\ \displaystyle {{{{{42} \ {x \sp 6}} -{{126} \ {x \sp 5}}+{{105} \ {x \sp 4}} -{{21} \ {x \sp 2}}+1} \over {30240}} \ {t \sp 6}}+ {{{{6 \ {x \sp 7}} -{{21} \ {x \sp 6}}+{{21} \ {x \sp 5}} -{7 \ {x \sp 3}}+x} \over {30240}} \ {t \sp 7}}+ \\ \\ \displaystyle {{{{{30} \ {x \sp 8}} -{{120} \ {x \sp 7}}+{{140} \ {x \sp 6}} - {{70} \ {x \sp 4}}+{{20} \ {x \sp 2}} -1} \over {1209600}} \ {t \sp 8}}+ \\ \\ \displaystyle {{{{{10} \ {x \sp 9}} -{{45} \ {x \sp 8}}+{{60} \ {x \sp 7}} - {{42} \ {x \sp 5}}+{{20} \ {x \sp 3}} -{3 \ x}} \over {3628800}} \ {t \sp 9}}+ \\ \\ \displaystyle {{{{{66} \ {x \sp {10}}} -{{330} \ {x \sp 9}}+{{495} \ {x \sp 8}} - {{462} \ {x \sp 6}}+{{330} \ {x \sp 4}} -{{99} \ {x \sp 2}}+5} \over {239500800}} \ {t \sp {10}}}+ {O \left({{t \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,t,0)} Therefore, this and the next expression produce the same result. \spadcommand{factorial(6) * coefficient(bern,6) } $$ {{{42} \ {x \sp 6}} - {{126} \ {x \sp 5}}+ {{105} \ {x \sp 4}} - {{21} \ {x \sp 2}}+1} \over {42} $$ \returnType{Type: Expression Integer} \spadcommand{bernoulliB(6,x)} $$ {x \sp 6} - {3 \ {x \sp 5}}+ {{5 \over 2} \ {x \sp 4}} - {{1 \over 2} \ {x \sp 2}}+ {1 \over {42}} $$ \returnType{Type: Polynomial Fraction Integer} Technically, a series with terms of negative degree is not considered to be a Taylor series, but, rather, a \index{series!Laurent} {\it Laurent series}. \index{Laurent series} If you try to compute a Taylor series expansion of $\frac{x}{\log x}$ at $x = 1$ via $taylor(x/log(x),x = 1)$ you get an error message. The reason is that the function has a {\it pole} at $x = 1$, meaning that its series expansion about this point has terms of negative degree. A series with finitely many terms of negative degree is called a Laurent series. You get the desired series expansion by issuing this. \spadcommand{laurent(x/log(x),x = 1)} $$ \begin{array}{@{}l} {{\left( x -1 \right)}\sp {\left( -1\right)}}+ {3\over 2}+ {{5 \over {12}} \ {\left( x -1 \right)}} -{{1 \over {24}} \ {{\left( x -1 \right)}\sp 2}}+ {{{11} \over {720}} \ {{\left( x -1 \right)}\sp 3}} - {{{11} \over {1440}} \ {{\left( x -1 \right)}\sp 4}}+ \\ \\ \displaystyle {{{271} \over {60480}} \ {{\left( x -1 \right)}\sp 5}} - {{{13} \over {4480}} \ {{\left( x -1 \right)}\sp 6}}+ {{{7297} \over {3628800}} \ {{\left( x -1 \right)}\sp 7}} - {{{425} \over {290304}} \ {{\left( x -1 \right)}\sp 8}}+ \\ \\ \displaystyle {{{530113} \over {479001600}} \ {{\left( x -1 \right)}\sp 9}}+ {O \left({{{\left( x -1 \right)}\sp {10}}} \right)} \end{array} $$ \returnType{Type: UnivariateLaurentSeries(Expression Integer,x,1)} Similarly, a series with terms of fractional degree is neither a Taylor series nor a Laurent series. Such a series is called a \index{series!Puiseux} {\it Puiseux series}. \index{Puiseux series} The expression $laurent(sqrt(sec(x)),x = 3 * \%pi/2)$ results in an error message because the series expansion about this point has terms of fractional degree. However, this command produces what you want. \spadcommand{puiseux(sqrt(sec(x)),x = 3 * \%pi/2)} $$ {{\left( x -{{3 \ \pi} \over 2} \right)}\sp {\left( -{1 \over 2} \right)}}+ {{1\over {12}} \ {{\left( x -{{3 \ \pi} \over 2} \right)}\sp {3 \over 2}}}+ {{1 \over {160}} \ {{\left( x -{{3 \ \pi} \over 2} \right)}\sp {7 \over 2}}}+ {O \left({{{\left( x -{{3 \ \pi} \over 2} \right)}\sp 5}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,(3*pi)/2)} Finally, consider the case of functions that do not have Puiseux expansions about certain points. An example of this is $x^x$ about $x = 0$. $puiseux(x**x,x=0)$ produces an error message because of the type of singularity of the function at $x = 0$. The general function {\bf series} can be used in this case. Notice that the series returned is not, strictly speaking, a power series because of the $log(x)$ in the expansion. \spadcommand{series(x**x,x=0)} $$ \begin{array}{@{}l} 1+ {{\log \left({x} \right)}\ x}+ {{{{\log \left({x} \right)}\sp 2} \over 2} \ {x \sp 2}}+ {{{{\log \left({x} \right)}\sp 3} \over 6} \ {x \sp 3}}+ {{{{\log \left({x} \right)}\sp 4} \over {24}} \ {x \sp 4}}+ {{{{\log \left({x} \right)}\sp 5} \over {120}} \ {x \sp 5}}+ {{{{\log \left({x} \right)}\sp 6} \over {720}} \ {x \sp 6}}+ \\ \\ \displaystyle {{{{\log \left({x} \right)}\sp 7} \over {5040}} \ {x \sp 7}}+ {{{{\log \left({x} \right)}\sp 8} \over {40320}} \ {x \sp 8}}+ {{{{\log \left({x} \right)}\sp 9} \over {362880}} \ {x \sp 9}}+ {{{{\log \left({x} \right)}\sp {10}} \over {3628800}} \ {x \sp {10}}}+ {O \left({{x \sp {11}}} \right)} \end{array} $$ \returnType{Type: GeneralUnivariatePowerSeries(Expression Integer,x,0)} \boxed{4.6in}{ \vskip 0.1cm The operation {\bf series} returns the most general type of infinite series. The user who is not interested in distinguishing between various types of infinite series may wish to use this operation exclusively.\\ } \subsection{Power Series from Formulas} \label{ugxProblemSeriesFormula} The {\tt GenerateUnivariatePowerSeries} package enables you to \index{series!giving formula for coefficients} create power series from explicit formulas for their $n$-th coefficients. In what follows, we construct series expansions for certain transcendental functions by giving formulas for their coefficients. You can also compute such series expansions directly simply by specifying the function and the point about which the series is to be expanded. \index{GenerateUnivariatePowerSeries} See \ref{ugxProblemSeriesConversions} on page~\pageref{ugxProblemSeriesConversions} for more information. Consider the Taylor expansion of $e^x$ \index{series!Taylor} about $x = 0$: $$ \begin{array}{ccl} e^x &=& \displaystyle 1 + x + \frac{x^2}{2} + \frac{x^3}{6} + \cdots \\ \\ &=& \displaystyle\sum_{n=0}^\infty \frac{x^n}{n!} \end{array} $$ The $n$-th Taylor coefficient is $1/n!$. This is how you create this series in Axiom. \spadcommand{series(n +-> 1/factorial(n),x = 0)} $$ \begin{array}{@{}l} 1+x+ {{1 \over 2} \ {x \sp 2}}+ {{1 \over 6} \ {x \sp 3}}+ {{1 \over {24}} \ {x \sp 4}}+ {{1 \over {120}} \ {x \sp 5}}+ {{1 \over {720}} \ {x \sp 6}}+ {{1 \over {5040}} \ {x \sp 7}}+ {{1 \over {40320}} \ {x \sp 8}}+ \\ \\ \displaystyle {{1 \over {362880}} \ {x \sp 9}}+ {{1 \over {3628800}} \ {x \sp {10}}}+ {O \left({{x \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} The first argument specifies a formula for the $n$-th coefficient by giving a function that maps $n$ to $1/n!$. The second argument specifies that the series is to be expanded in powers of $(x - 0)$, that is, in powers of $x$. Since we did not specify an initial degree, the first term in the series was the term of degree 0 (the constant term). Note that the formula was given as an anonymous function. These are discussed in \ref{ugUserAnon} on page~\pageref{ugUserAnon}. Consider the Taylor expansion of $log x$ about $x = 1$: $$ \begin{array}{ccl} \log(x) &=& \displaystyle (x - 1) - \frac{(x - 1)^2}{2} + \frac{(x - 1)^3}{3} - \cdots \\ \\ &=& \displaystyle\sum_{n = 1}^\infty (-1)^{n-1} \frac{(x - 1)^n}{n} \end{array}$$ If you were to evaluate the expression $series(n +-> (-1)**(n-1) / n, x = 1)$ you would get an error message because Axiom would try to calculate a term of degree $0$ and therefore divide by $0.$ Instead, evaluate this. The third argument, $1..$, indicates that only terms of degree $n = 1, ...$ are to be computed. \spadcommand{series(n +-> (-1)**(n-1)/n,x = 1,1..)} $$ \begin{array}{@{}l} {\left( x -1 \right)} -{{1 \over 2} \ {{\left( x -1 \right)}\sp 2}}+ {{1 \over 3} \ {{\left( x -1 \right)}\sp 3}} - {{1 \over 4} \ {{\left( x -1 \right)}\sp 4}}+ {{1 \over 5} \ {{\left( x -1 \right)}\sp 5}} - {{1 \over 6} \ {{\left( x -1 \right)}\sp 6}}+ \\ \\ \displaystyle {{1 \over 7} \ {{\left( x -1 \right)}\sp 7}} - {{1 \over 8} \ {{\left( x -1 \right)}\sp 8}}+ {{1 \over 9} \ {{\left( x -1 \right)}\sp 9}} - {{1 \over {10}} \ {{\left( x -1 \right)}\sp {10}}}+ {{1 \over {11}} \ {{\left( x -1 \right)}\sp {11}}}+ \\ \\ \displaystyle {O \left({{{\left( x -1 \right)}\sp {12}}} \right)} \end{array} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,1)} Next consider the Taylor expansion of an odd function, say, $sin(x)$: $$\sin(x) = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \cdots$$ Here every other coefficient is zero and we would like to give an explicit formula only for the odd Taylor coefficients. This is one way to do it. The third argument, $1..$, specifies that the first term to be computed is the term of degree 1. The fourth argument, $2$, specifies that we increment by $2$ to find the degrees of subsequent terms, that is, the next term is of degree $1 + 2$, the next of degree $1 + 2 + 2$, etc. \spadcommand{series(n +-> (-1)**((n-1)/2)/factorial(n),x = 0,1..,2)} $$ x - {{1 \over 6} \ {x \sp 3}}+ {{1 \over {120}} \ {x \sp 5}} - {{1 \over {5040}} \ {x \sp 7}}+ {{1 \over {362880}} \ {x \sp 9}} - {{1 \over {39916800}} \ {x \sp {11}}}+ {O \left({{x \sp {12}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} The initial degree and the increment do not have to be integers. For example, this expression produces a series expansion of $\sin(x^{\frac{1}{3}})$. \spadcommand{series(n +-> (-1)**((3*n-1)/2)/factorial(3*n),x = 0,1/3..,2/3)} $$ {x \sp {1 \over 3}} - {{1 \over 6} \ x}+ {{1 \over {120}} \ {x \sp {5 \over 3}}} - {{1 \over {5040}} \ {x \sp {7 \over 3}}}+ {{1 \over {362880}} \ {x \sp 3}} - {{1 \over {39916800}} \ {x \sp {{11} \over 3}}}+ {O \left({{x \sp 4}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} While the increment must be positive, the initial degree may be negative. This yields the Laurent expansion of $csc(x)$ at $x = 0$. (bernoulli(numer(n+1)) is necessary because bernoulli takes integer arguments.) \spadcommand{cscx := series(n +-> (-1)**((n-1)/2) * 2 * (2**n-1) * bernoulli(numer(n+1)) / factorial(n+1), x=0, -1..,2) } $$ {x \sp {\left( -1 \right)}}+ {{1\over 6} \ x}+ {{7 \over {360}} \ {x \sp 3}}+ {{{31} \over {15120}} \ {x \sp 5}}+ {{{127} \over {604800}} \ {x \sp 7}}+ {{{73} \over {3421440}} \ {x \sp 9}}+ {O \left({{x \sp {10}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} Of course, the reciprocal of this power series is the Taylor expansion of $sin(x)$. \spadcommand{1/cscx } $$ x - {{1 \over 6} \ {x \sp 3}}+ {{1 \over {120}} \ {x \sp 5}} - {{1 \over {5040}} \ {x \sp 7}}+ {{1 \over {362880}} \ {x \sp 9}} - {{1 \over {39916800}} \ {x \sp {11}}}+ {O \left({{x \sp {12}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} As a final example,here is the Taylor expansion of $asin(x)$ about $x = 0$. \spadcommand{asinx := series(n +-> binomial(n-1,(n-1)/2)/(n*2**(n-1)),x=0,1..,2) } $$ x+ {{1 \over 6} \ {x \sp 3}}+ {{3 \over {40}} \ {x \sp 5}}+ {{5 \over {112}} \ {x \sp 7}}+ {{{35} \over {1152}} \ {x \sp 9}}+ {{{63} \over {2816}} \ {x \sp {11}}}+ {O \left({{x \sp {12}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} When we compute the $sin$ of this series, we get $x$ (in the sense that all higher terms computed so far are zero). \spadcommand{sin(asinx) } $$ x+{O \left({{x \sp {12}}} \right)} $$ \returnType{Type: UnivariatePuiseuxSeries(Expression Integer,x,0)} \boxed{4.6in}{ \vskip 0.1cm Axiom isn't sufficiently ``symbolic'' in the sense we might wish. It is an open problem to decide that ``x'' is the only surviving term. Two attacks on the problem might be: (1) Notice that all of the higher terms are identically zero but Axiom can't decide that from the information it knows. Presumably we could attack this problem by looking at the sin function as a taylor series around x=0 and seeing the term cancellation occur. This uses a term-difference mechanism. (2) Notice that there is no way to decide that the stream for asinx is actually the definition of asin(x). But we could recognize that the stream for asin(x) has a generator term and so will a taylor series expansion of sin(x). From these two generators it may be possible in certain cases to decide that the application of one generator to the other will yield only ``x''. This trick involves finding the correct inverse for the stream functions. If we can find an inverse for the ``remaining tail'' of the stream we could conclude cancellation and thus turn an infinite stream into a finite object. In general this is the zero-equivalence problem and is undecidable.\\ } As we discussed in \ref{ugxProblemSeriesConversions} on page~\pageref{ugxProblemSeriesConversions}, you can also use the operations {\bf taylor}, {\bf laurent} and {\bf puiseux} instead of {\bf series} if you know ahead of time what kind of exponents a series has. You can't go wrong using {\bf series}, though. \subsection{Substituting Numerical Values in Power Series} \label{ugxProblemSeriesSubstitute} Use \spadfunFrom{eval}{UnivariatePowerSeriesCategory} \index{approximation} to substitute a numerical value for a variable in \index{series!numerical approximation} a power series. For example, here's a way to obtain numerical approximations of $\%e$ from the Taylor series expansion of $exp(x)$. First you create the desired Taylor expansion. \spadcommand{f := taylor(exp(x)) } $$ \begin{array}{@{}l} 1+x+ {{1 \over 2} \ {x \sp 2}}+ {{1 \over 6} \ {x \sp 3}}+ {{1 \over {24}} \ {x \sp 4}}+ {{1 \over {120}} \ {x \sp 5}}+ {{1 \over {720}} \ {x \sp 6}}+ {{1 \over {5040}} \ {x \sp 7}}+ \\ \\ \displaystyle {{1 \over {40320}} \ {x \sp 8}}+ {{1 \over {362880}} \ {x \sp 9}}+ {{1 \over {3628800}} \ {x \sp {10}}}+ {O \left({{x \sp {11}}} \right)} \end{array} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,x,0)} Then you evaluate the series at the value $1.0$. The result is a sequence of the partial sums. \spadcommand{eval(f,1.0)} $$ \begin{array}{@{}l} \left[ {1.0}, {2.0}, {2.5}, {2.6666666666\ 666666667}, {2.7083333333\ 333333333}, \right. \\ \\ \displaystyle {2.7166666666\ 666666667}, {2.7180555555\ 555555556}, {2.7182539682\ 53968254}, \\ \\ \displaystyle \left. {2.7182787698\ 412698413}, {2.7182815255\ 731922399}, \ldots \right] \end{array} $$ \returnType{Type: Stream Expression Float} \subsection{Example: Bernoulli Polynomials and Sums of Powers} \label{ugxProblemSeriesBernoulli} Axiom provides operations for computing definite and \index{summation!definite} indefinite sums. \index{summation!indefinite} You can compute the sum of the first ten fourth powers by evaluating this. This creates a list whose entries are $m^4$ as $m$ ranges from 1 to 10, and then computes the sum of the entries of that list. \spadcommand{reduce(+,[m**4 for m in 1..10])} $$ 25333 $$ \returnType{Type: PositiveInteger} You can also compute a formula for the sum of the first $k$ fourth powers, where $k$ is an unspecified positive integer. \spadcommand{sum4 := sum(m**4, m = 1..k) } $$ {{6 \ {k \sp 5}}+{{15} \ {k \sp 4}}+{{10} \ {k \sp 3}} -k} \over {30} $$ \returnType{Type: Fraction Polynomial Integer} This formula is valid for any positive integer $k$. For instance, if we replace $k$ by 10, \index{summation!definite} we obtain the number we computed earlier. \spadcommand{eval(sum4, k = 10) } $$ 25333 $$ \returnType{Type: Fraction Polynomial Integer} You can compute a formula for the sum of the first $k$ $n$-th powers in a similar fashion. Just replace the $4$ in the definition of {\bf sum4} by any expression not involving $k$. Axiom computes these formulas using Bernoulli polynomials; \index{Bernoulli!polynomial} we \index{polynomial!Bernoulli} use the rest of this section to describe this method. First consider this function of $t$ and $x$. \spadcommand{f := t*exp(x*t) / (exp(t) - 1) } $$ {t \ {e \sp {\left( t \ x \right)}}}\over {{e \sp t} -1} $$ \returnType{Type: Expression Integer} Since the expressions involved get quite large, we tell Axiom to show us only terms of degree up to $5.$ \spadcommand{)set streams calculate 5 } \index{set streams calculate} If we look at the Taylor expansion of $f(x, t)$ about $t = 0,$ we see that the coefficients of the powers of $t$ are polynomials in $x$. \spadcommand{ff := taylor(f,t = 0) } $$ \begin{array}{@{}l} 1+ {{{{2 \ x} -1} \over 2} \ t}+ {{{{6 \ {x \sp 2}} -{6 \ x}+1} \over {12}} \ {t \sp 2}}+ {{{{2 \ {x \sp 3}} -{3 \ {x \sp 2}}+x} \over {12}} \ {t \sp 3}}+ \\ \\ \displaystyle {{{{{30} \ {x \sp 4}} -{{60} \ {x \sp 3}}+{{30} \ {x \sp 2}} -1} \over {720}} \ {t \sp 4}}+ {{{{6 \ {x \sp 5}} -{{15} \ {x \sp 4}}+{{10} \ {x \sp 3}} -x} \over {720}} \ {t \sp 5}}+ {O \left({{t \sp 6}} \right)} \end{array} $$ Type: UnivariateTaylorSeries(Expression Integer,t,0) In fact, the $n$-th coefficient in this series is essentially the $n$-th Bernoulli polynomial: the $n$-th coefficient of the series is ${1 \over {n!}} B_n(x)$, where $B_n(x)$ is the $n$-th Bernoulli polynomial. Thus, to obtain the $n$-th Bernoulli polynomial, we multiply the $n$-th coefficient of the series $ff$ by $n!$. For example, the sixth Bernoulli polynomial is this. \spadcommand{factorial(6) * coefficient(ff,6) } $$ {{{42} \ {x \sp 6}} -{{126} \ {x \sp 5}}+{{105} \ {x \sp 4}} - {{21} \ {x \sp 2}}+1} \over {42} $$ \returnType{Type: Expression Integer} We derive some properties of the function $f(x,t)$. First we compute $f(x + 1,t) - f(x,t)$. \spadcommand{g := eval(f, x = x + 1) - f } $$ {{t \ {e \sp {\left( {t \ x}+t \right)}}} -{t \ {e \sp {\left( t \ x \right)}}}} \over {{e \sp t} -1} $$ \returnType{Type: Expression Integer} If we normalize $g$, we see that it has a particularly simple form. \spadcommand{normalize(g) } $$ t \ {e \sp {\left( t \ x \right)}} $$ \returnType{Type: Expression Integer} From this it follows that the $n$-th coefficient in the Taylor expansion of $g(x,t)$ at $t = 0$ is $${1\over{(n-1)!}}x^{n-1}$$. If you want to check this, evaluate the next expression. \spadcommand{taylor(g,t = 0) } $$ t+ {x \ {t \sp 2}}+ {{{x \sp 2} \over 2} \ {t \sp 3}}+ {{{x \sp 3} \over 6} \ {t \sp 4}}+ {{{x \sp 4} \over {24}} \ {t \sp 5}}+ {O \left({{t \sp 6}} \right)} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,t,0)} However, since $$g(x,t) = f(x+1,t)-f(x,t)$$ it follows that the $n$-th coefficient is $${1 \over {n!}}(B_n(x+1)-B_n(x))$$ Equating coefficients, we see that $${1\over{(n-1)!}}x^{n-1} = {1\over{n!}}(B_n(x + 1) - B_n(x))$$ and, therefore, $$x^{n-1} = {1\over{n}}(B_n(x + 1) - B_n(x))$$ Let's apply this formula repeatedly, letting $x$ vary between two integers $a$ and $b$, with $a < b$: $$ \begin{array}{lcl} a^{n-1} & = & {1 \over n} (B_n(a + 1) - B_n(a)) \\ (a + 1)^{n-1} & = & {1 \over n} (B_n(a + 2) - B_n(a + 1)) \\ (a + 2)^{n-1} & = & {1 \over n} (B_n(a + 3) - B_n(a + 2)) \\ & \vdots & \\ (b - 1)^{n-1} & = & {1 \over n} (B_n(b) - B_n(b - 1)) \\ b^{n-1} & = & {1 \over n} (B_n(b + 1) - B_n(b)) \end{array} $$ When we add these equations we find that the sum of the left-hand sides is $$\sum_{m=a}^{b} m^{n-1},$$ the sum of the $$(n-1)^{\hbox{\small\rm st}}$$ powers from $a$ to $b$. The sum of the right-hand sides is a ``telescoping series.'' After cancellation, the sum is simply $${1\over{n}}(B_n(b + 1) - B_n(a))$$ Replacing $n$ by $n + 1$, we have shown that $$ \sum_{m = a}^{b} m^n = {1 \over {\displaystyle n + 1}} (B_{n+1}(b + 1) - B_{n+1}(a)) $$ Let's use this to obtain the formula for the sum of fourth powers. First we obtain the Bernoulli polynomial $B_5$. \spadcommand{B5 := factorial(5) * coefficient(ff,5) } $$ {{6 \ {x \sp 5}} -{{15} \ {x \sp 4}}+{{10} \ {x \sp 3}} -x} \over 6 $$ \returnType{Type: Expression Integer} To find the sum of the first $k$ 4th powers, we multiply $1/5$ by $B_5(k+1) - B_5(1)$. \spadcommand{1/5 * (eval(B5, x = k + 1) - eval(B5, x = 1)) } $$ {{6 \ {k \sp 5}}+{{15} \ {k \sp 4}}+{{10} \ {k \sp 3}} -k} \over {30} $$ \returnType{Type: Expression Integer} This is the same formula that we obtained via $sum(m**4, m = 1..k)$. \spadcommand{sum4 } $$ {{6 \ {k \sp 5}}+{{15} \ {k \sp 4}}+{{10} \ {k \sp 3}} -k} \over {30} $$ \returnType{Type: Fraction Polynomial Integer} At this point you may want to do the same computation, but with an exponent other than $4.$ For example, you might try to find a formula for the sum of the first $k$ 20th powers. \section{Solution of Differential Equations} \label{ugProblemDEQ} In this section we discuss Axiom's facilities for \index{equation!differential!solving} solving \index{differential equation} differential equations in closed-form and in series. Axiom provides facilities for closed-form solution of \index{equation!differential!solving in closed-form} single differential equations of the following kinds: \begin{itemize} \item linear ordinary differential equations, and \item non-linear first order ordinary differential equations when integrating factors can be found just by integration. \end{itemize} For a discussion of the solution of systems of linear and polynomial equations, see \ref{ugProblemLinPolEqn} on page~\pageref{ugProblemLinPolEqn}. \subsection{Closed-Form Solutions of Linear Differential Equations} \label{ugxProblemLDEQClosed} A {\it differential equation} is an equation involving an unknown {\it function} and one or more of its derivatives. \index{differential equation} The equation is called {\it ordinary} if derivatives with respect to \index{equation!differential} only one dependent variable appear in the equation (it is called {\it partial} otherwise). The package {\tt ElementaryFunctionODESolver} provides the top-level operation {\bf solve} for finding closed-form solutions of ordinary differential equations. \index{ElementaryFunctionODESolver} To solve a differential equation, you must first create an operator for \index{operator} the unknown function. We let $y$ be the unknown function in terms of $x$. \spadcommand{y := operator 'y } $$ y $$ \returnType{Type: BasicOperator} You then type the equation using {\tt D} to create the derivatives of the unknown function $y(x)$ where $x$ is any symbol you choose (the so-called {\it dependent variable}). This is how you enter the equation $y'' + y' + y = 0$. \spadcommand{deq := D(y x, x, 2) + D(y x, x) + y x = 0} $$ {{{y \sb {{\ }} \sp {,,}} \left({x} \right)}+ {{y \sb {{\ }} \sp {,}} \left({x} \right)}+ {y \left({x} \right)}}=0 $$ \returnType{Type: Equation Expression Integer} The simplest way to invoke the {\bf solve} command is with three arguments. \begin{itemize} \item the differential equation, \item the operator representing the unknown function, \item the dependent variable. \end{itemize} So, to solve the above equation, we enter this. \spadcommand{solve(deq, y, x) } $$ \left[ {particular=0}, {basis={\left[ {{\cos \left({{{x \ {\sqrt {3}}} \over 2}} \right)} \ {e \sp {\left( -{x \over 2} \right)}}}, {{e \sp {\left( -{x \over 2} \right)}} \ {\sin \left({{{x \ {\sqrt {3}}} \over 2}} \right)}}\right]}} \right] $$ \returnType{Type: Union(Record(particular: Expression Integer,basis: List Expression Integer),...)} Since linear ordinary differential equations have infinitely many solutions, {\bf solve} returns a {\it particular solution} $f_p$ and a basis $f_1,\dots,f_n$ for the solutions of the corresponding homogenuous equation. Any expression of the form $$f_p + c_1 f_1 + \dots c_n f_n$$ where the $c_i$ do not involve the dependent variable is also a solution. This is similar to what you get when you solve systems of linear algebraic equations. A way to select a unique solution is to specify {\it initial conditions}: choose a value $a$ for the dependent variable and specify the values of the unknown function and its derivatives at $a$. If the number of initial conditions is equal to the order of the equation, then the solution is unique (if it exists in closed form!) and {\bf solve} tries to find it. To specify initial conditions to {\bf solve}, use an {\tt Equation} of the form $x = a$ for the third parameter instead of the dependent variable, and add a fourth parameter consisting of the list of values $y(a), y'(a), ...$. To find the solution of $y'' + y = 0$ satisfying $y(0) = y'(0) = 1$, do this. \spadcommand{deq := D(y x, x, 2) + y x } $$ {{y \sb {{\ }} \sp {,,}} \left({x} \right)}+{y\left({x} \right)} $$ \returnType{Type: Expression Integer} You can omit the $= 0$ when you enter the equation to be solved. \spadcommand{solve(deq, y, x = 0, [1, 1]) } $$ {\sin \left({x} \right)}+{\cos\left({x} \right)} $$ \returnType{Type: Union(Expression Integer,...)} Axiom is not limited to linear differential equations with constant coefficients. It can also find solutions when the coefficients are rational or algebraic functions of the dependent variable. Furthermore, Axiom is not limited by the order of the equation. Axiom can solve the following third order equations with polynomial coefficients. \spadcommand{deq := x**3 * D(y x, x, 3) + x**2 * D(y x, x, 2) - 2 * x * D(y x, x) + 2 * y x = 2 * x**4 } $$ {{{x \sp 3} \ {{y \sb {{\ }} \sp {,,,}} \left({x} \right)}}+ {{x\sp 2} \ {{y \sb {{\ }} \sp {,,}} \left({x} \right)}}- {2 \ x \ {{y \sb {{\ }} \sp {,}} \left({x} \right)}}+ {2\ {y \left({x} \right)}}}= {2\ {x \sp 4}} $$ \returnType{Type: Equation Expression Integer} \spadcommand{solve(deq, y, x) } $$ \begin{array}{@{}l} \left[ {particular={{{x \sp 5} -{{10} \ {x \sp 3}}+{{20} \ {x \sp 2}}+4} \over {{15} \ x}}}, \right. \\ \\ \displaystyle \left. {basis={\left[ {{{2 \ {x \sp 3}} -{3 \ {x \sp 2}}+1} \over x}, {{{x \sp 3} -1} \over x}, {{{x \sp 3} -{3 \ {x \sp 2}} -1} \over x} \right]}} \right] \end{array} $$ \returnType{Type: Union(Record(particular: Expression Integer,basis: List Expression Integer),...)} Here we are solving a homogeneous equation. \spadcommand{deq := (x**9+x**3) * D(y x, x, 3) + 18 * x**8 * D(y x, x, 2) - 90 * x * D(y x, x) - 30 * (11 * x**6 - 3) * y x } $$ {{\left( {x \sp 9}+{x \sp 3} \right)}\ {{y \sb {{\ }} \sp {,,,}} \left({x} \right)}}+ {{18}\ {x \sp 8} \ {{y \sb {{\ }} \sp {,,}} \left({x} \right)}}- {{90} \ x \ {{y \sb {{\ }} \sp {,}} \left({x} \right)}}+ {{\left(-{{330} \ {x \sp 6}}+{90} \right)}\ {y \left({x} \right)}} $$ \returnType{Type: Expression Integer} \spadcommand{solve(deq, y, x) } $$ \left[ {particular=0}, {basis={\left[ {x \over {{x \sp 6}+1}}, {{x \ {e \sp {\left( -{{\sqrt {{91}}} \ {\log \left({x} \right)}}\right)}}} \over {{x \sp 6}+1}}, {{x \ {e \sp {\left( {\sqrt {{91}}} \ {\log \left({x} \right)}\right)}}} \over {{x \sp 6}+1}} \right]}} \right] $$ \returnType{Type: Union(Record(particular: Expression Integer,basis: List Expression Integer),...)} On the other hand, and in contrast with the operation {\bf integrate}, it can happen that Axiom finds no solution and that some closed-form solution still exists. While it is mathematically complicated to describe exactly when the solutions are guaranteed to be found, the following statements are correct and form good guidelines for linear ordinary differential equations: \begin{itemize} \item If the coefficients are constants, Axiom finds a complete basis of solutions (i,e, all solutions). \item If the coefficients are rational functions in the dependent variable, Axiom at least finds all solutions that do not involve algebraic functions. \end{itemize} Note that this last statement does not mean that Axiom does not find the solutions that are algebraic functions. It means that it is not guaranteed that the algebraic function solutions will be found. This is an example where all the algebraic solutions are found. \spadcommand{deq := (x**2 + 1) * D(y x, x, 2) + 3 * x * D(y x, x) + y x = 0 } $$ {{{\left( {x \sp 2}+1 \right)}\ {{y \sb {{\ }} \sp {,,}} \left({x} \right)}}+ {3\ x \ {{y \sb {{\ }} \sp {,}} \left({x} \right)}}+ {y\left({x} \right)}}=0 $$ \returnType{Type: Equation Expression Integer} \spadcommand{solve(deq, y, x) } $$ \left[ {particular=0}, {basis={\left[ {1 \over {\sqrt {{{x \sp 2}+1}}}}, {{\log \left({{{\sqrt {{{x \sp 2}+1}}} -x}} \right)} \over {\sqrt {{{x \sp 2}+1}}}} \right]}} \right] $$ \returnType{Type: Union(Record(particular: Expression Integer,basis: List Expression Integer),...)} \subsection{Closed-Form Solutions of Non-Linear Differential Equations} \label{ugxProblemNLDEQClosed} This is an example that shows how to solve a non-linear first order ordinary differential equation manually when an integrating factor can be found just by integration. At the end, we show you how to solve it directly. Let's solve the differential equation $y' = y / (x + y log y)$. Using the notation $m(x, y) + n(x, y) y' = 0$, we have $m = -y$ and $n = x + y log y$. \spadcommand{m := -y } $$ -y $$ \returnType{Type: Polynomial Integer} \spadcommand{n := x + y * log y } $$ {y \ {\log \left({y} \right)}}+x $$ \returnType{Type: Expression Integer} We first check for exactness, that is, does $dm/dy = dn/dx$? \spadcommand{D(m, y) - D(n, x) } $$ -2 $$ \returnType{Type: Expression Integer} This is not zero, so the equation is not exact. Therefore we must look for an integrating factor: a function $mu(x,y)$ such that $d(mu m)/dy = d(mu n)/dx$. Normally, we first search for $mu(x,y)$ depending only on $x$ or only on $y$. Let's search for such a $mu(x)$ first. \spadcommand{mu := operator 'mu } $$ mu $$ \returnType{Type: BasicOperator} \spadcommand{a := D(mu(x) * m, y) - D(mu(x) * n, x) } $$ {{\left( -{y \ {\log \left({y} \right)}}-x \right)} \ {{mu \sb {{\ }} \sp {,}} \left({x} \right)}}- {2 \ {mu \left({x} \right)}} $$ \returnType{Type: Expression Integer} If the above is zero for a function $mu$ that does {\it not} depend on $y$, then $mu(x)$ is an integrating factor. \spadcommand{solve(a = 0, mu, x) } $$ \left[ {particular=0}, {basis={\left[ {1 \over {{{y \sp 2} \ {{\log \left({y} \right)}\sp 2}}+ {2 \ x \ y \ {\log \left({y} \right)}}+ {x\sp 2}}} \right]}} \right] $$ \returnType{Type: Union(Record(particular: Expression Integer,basis: List Expression Integer),...)} The solution depends on $y$, so there is no integrating factor that depends on $x$ only. Let's look for one that depends on $y$ only. \spadcommand{b := D(mu(y) * m, y) - D(mu(y) * n, x) } $$ -{y \ {{mu \sb {{\ }} \sp {,}} \left({y} \right)}}- {2 \ {mu \left({y} \right)}} $$ \returnType{Type: Expression Integer} \spadcommand{sb := solve(b = 0, mu, y) } $$ \left[ {particular=0}, {basis={\left[ {1 \over {y \sp 2}} \right]}} \right] $$ \returnType{Type: Union(Record(particular: Expression Integer,basis: List Expression Integer),...)} \noindent We've found one! The above $mu(y)$ is an integrating factor. We must multiply our initial equation (that is, $m$ and $n$) by the integrating factor. \spadcommand{intFactor := sb.basis.1 } $$ 1 \over {y \sp 2} $$ \returnType{Type: Expression Integer} \spadcommand{m := intFactor * m } $$ -{1 \over y} $$ \returnType{Type: Expression Integer} \spadcommand{n := intFactor * n } $$ {{y \ {\log \left({y} \right)}}+x}\over {y \sp 2} $$ \returnType{Type: Expression Integer} Let's check for exactness. \spadcommand{D(m, y) - D(n, x) } $$ 0 $$ \returnType{Type: Expression Integer} We must solve the exact equation, that is, find a function $s(x,y)$ such that $ds/dx = m$ and $ds/dy = n$. We start by writing $s(x, y) = h(y) + integrate(m, x)$ where $h(y)$ is an unknown function of $y$. This guarantees that $ds/dx = m$. \spadcommand{h := operator 'h } $$ h $$ \returnType{Type: BasicOperator} \spadcommand{sol := h y + integrate(m, x) } $$ {{y \ {h \left({y} \right)}}-x} \over y $$ \returnType{Type: Expression Integer} All we want is to find $h(y)$ such that $ds/dy = n$. \spadcommand{dsol := D(sol, y) } $$ {{{y \sp 2} \ {{h \sb {{\ }} \sp {,}} \left({y} \right)}}+x}\over {y \sp 2} $$ \returnType{Type: Expression Integer} \spadcommand{nsol := solve(dsol = n, h, y) } $$ \left[ {particular={{{\log \left({y} \right)}\sp 2} \over 2}}, {basis={\left[ 1 \right]}} \right] $$ \returnType{Type: Union(Record(particular: Expression Integer,basis: List Expression Integer),...)} The above particular solution is the $h(y)$ we want, so we just replace $h(y)$ by it in the implicit solution. \spadcommand{eval(sol, h y = nsol.particular) } $$ {{y \ {{\log \left({y} \right)}\sp 2}} -{2 \ x}} \over {2 \ y} $$ \returnType{Type: Expression Integer} A first integral of the initial equation is obtained by setting this result equal to an arbitrary constant. Now that we've seen how to solve the equation ``by hand,'' we show you how to do it with the {\bf solve} operation. First define $y$ to be an operator. \spadcommand{y := operator 'y } $$ y $$ \returnType{Type: BasicOperator} Next we create the differential equation. \spadcommand{deq := D(y x, x) = y(x) / (x + y(x) * log y x) } $$ {{y \sb {{\ }} \sp {,}} \left({x} \right)}= {{y\left({x} \right)}\over {{{y \left({x} \right)}\ {\log \left({{y \left({x} \right)}}\right)}}+x}} $$ \returnType{Type: Equation Expression Integer} Finally, we solve it. \spadcommand{solve(deq, y, x) } $$ {{{y \left({x} \right)}\ {{\log \left({{y \left({x} \right)}}\right)}\sp 2}}- {2 \ x}} \over {2 \ {y \left({x} \right)}} $$ \returnType{Type: Union(Expression Integer,...)} \subsection{Power Series Solutions of Differential Equations} \label{ugxProblemDEQSeries} The command to solve differential equations in power \index{equation!differential!solving in power series} series \index{power series} around \index{series!power} a particular initial point with specific initial conditions is called {\bf seriesSolve}. It can take a variety of parameters, so we illustrate its use with some examples. Since the coefficients of some solutions are quite large, we reset the default to compute only seven terms. \spadcommand{)set streams calculate 7 } You can solve a single nonlinear equation of any order. For example, we solve $$y''' = sin(y'') * exp(y) + cos(x)$$ subject to $$y(0) = 1, y'(0) = 0, y''(0) = 0$$ We first tell Axiom that the symbol $'y$ denotes a new operator. \spadcommand{y := operator 'y } $$ y $$ \returnType{Type: BasicOperator} Enter the differential equation using $y$ like any system function. \spadcommand{eq := D(y(x), x, 3) - sin(D(y(x), x, 2))*exp(y(x)) = cos(x)} $$ {{{y \sb {{\ }} \sp {,,,}} \left({x} \right)}- {{e \sp {y \left({x} \right)}}\ {\sin \left({{{y \sb {{\ }} \sp {,,}} \left({x} \right)}}\right)}}}= {\cos\left({x} \right)} $$ \returnType{Type: Equation Expression Integer} Solve it around $x = 0$ with the initial conditions $y(0) = 1, y'(0) = y''(0) = 0$. \spadcommand{seriesSolve(eq, y, x = 0, [1, 0, 0])} $$ 1+ {{1 \over 6} \ {x \sp 3}}+ {{e \over {24}} \ {x \sp 4}}+ {{{{e \sp 2} -1} \over {120}} \ {x \sp 5}}+ {{{{e \sp 3} -{2 \ e}} \over {720}} \ {x \sp 6}}+ {{{{e \sp 4} -{8 \ {e \sp 2}}+{4 \ e}+1} \over {5040}} \ {x \sp 7}}+ {O \left({{x \sp 8}} \right)} $$ \returnType{Type: UnivariateTaylorSeries(Expression Integer,x,0)} You can also solve a system of nonlinear first order equations. For example, we solve a system that has $tan(t)$ and $sec(t)$ as solutions. We tell Axiom that $x$ is also an operator. \spadcommand{x := operator 'x} $$ x $$ \returnType{Type: BasicOperator} Enter the two equations forming our system. \spadcommand{eq1 := D(x(t), t) = 1 + x(t)**2} $$ {{x \sb {{\ }} \sp {,}} \left({t} \right)}= {{{x\left({t} \right)}\sp 2}+1} $$ \returnType{Type: Equation Expression Integer} \spadcommand{eq2 := D(y(t), t) = x(t) * y(t)} $$ {{y \sb {{\ }} \sp {,}} \left({t} \right)}= {{x\left({t} \right)}\ {y \left({t} \right)}} $$ \returnType{Type: Equation Expression Integer} Solve the system around $t = 0$ with the initial conditions $x(0) = 0$ and $y(0) = 1$. Notice that since we give the unknowns in the order $[x, y]$, the answer is a list of two series in the order $$[{\rm series\ for\ } x(t), {\rm \ series\ for\ }y(t)]$$ \spadcommand{seriesSolve([eq2, eq1], [x, y], t = 0, [y(0) = 1, x(0) = 0])} \begin{verbatim} Compiling function %BZ with type List UnivariateTaylorSeries( Expression Integer,t,0) -> UnivariateTaylorSeries(Expression Integer,t,0) Compiling function %CA with type List UnivariateTaylorSeries( Expression Integer,t,0) -> UnivariateTaylorSeries(Expression Integer,t,0) \end{verbatim} $$ \left[ {t+ {{1 \over 3} \ {t \sp 3}}+ {{2 \over {15}} \ {t \sp 5}}+ {{{17} \over {315}} \ {t \sp 7}}+ {O \left({{t \sp 8}} \right)}}, {1+{{1 \over 2} \ {t \sp 2}}+ {{5 \over {24}} \ {t \sp 4}}+ {{{61} \over {720}} \ {t \sp 6}}+ {O \left({{t \sp 8}} \right)}} \right] $$ \returnType{Type: List UnivariateTaylorSeries(Expression Integer,t,0)} \noindent The order in which we give the equations and the initial conditions has no effect on the order of the solution. \section{Finite Fields} \label{ugProblemFinite} A {\it finite field} (also called a {\it Galois field}) is a finite algebraic structure where one can add, multiply and divide under the same laws (for example, commutativity, associativity or distributivity) as apply to the rational, real or complex numbers. Unlike those three fields, for any finite field there exists a positive prime integer $p$, called the {\bf characteristic}, such that $p x = 0$ for any element $x$ in the finite field. In fact, the number of elements in a finite field is a power of the characteristic and for each prime $p$ and positive integer $n$ there exists exactly one finite field with $p^n$ elements, up to isomorphism.\footnote{For more information about the algebraic structure and properties of finite fields, see, for example, S. Lang, {\it Algebra}, Second Edition, New York: Addison-Wesley Publishing Company, Inc., 1984, ISBN 0 201 05487 6; or R. Lidl, H. Niederreiter, {\it Finite Fields}, Encyclopedia of Mathematics and Its Applications, Vol. 20, Cambridge: Cambridge Univ. Press, 1983, ISBN 0 521 30240 4.} When $n = 1,$ the field has $p$ elements and is called a {\it prime field}, discussed in the next section. There are several ways of implementing extensions of finite fields, and Axiom provides quite a bit of freedom to allow you to choose the one that is best for your application. Moreover, we provide operations for converting among the different representations of extensions and different extensions of a single field. Finally, note that you usually need to package-call operations from finite fields if the operations do not take as an argument an object of the field. See \ref{ugTypesPkgCall} on page~\pageref{ugTypesPkgCall} for more information on package-calling. \subsection{Modular Arithmetic and Prime Fields} \label{ugxProblemFinitePrime} \index{finite field} \index{Galois!field} \index{field!finite!prime} \index{field!prime} \index{field!Galois} \index{prime field} \index{modular arithmetic} \index{arithmetic!modular} Let $n$ be a positive integer. It is well known that you can get the same result if you perform addition, subtraction or multiplication of integers and then take the remainder on dividing by $n$ as if you had first done such remaindering on the operands, performed the arithmetic and then (if necessary) done remaindering again. This allows us to speak of arithmetic {\it modulo} $n$ or, more simply {\it mod} $n$. In Axiom, you use {\tt IntegerMod} to do such arithmetic. \spadcommand{(a,b) : IntegerMod 12 } \returnType{Type: Void} \spadcommand{(a, b) := (16, 7) } $$ 7 $$ \returnType{Type: IntegerMod 12} \spadcommand{[a - b, a * b] } $$ \left[ 9, 4 \right] $$ \returnType{Type: List IntegerMod 12} If $n$ is not prime, there is only a limited notion of reciprocals and division. \spadcommand{a / b } \begin{verbatim} There are 12 exposed and 13 unexposed library operations named / having 2 argument(s) but none was determined to be applicable. Use HyperDoc Browse, or issue )display op / to learn more about the available operations. Perhaps package-calling the operation or using coercions on the arguments will allow you to apply the operation. Cannot find a definition or applicable library operation named / with argument type(s) IntegerMod 12 IntegerMod 12 Perhaps you should use "@" to indicate the required return type, or "$" to specify which version of the function you need. \end{verbatim} \spadcommand{recip a } $$ \mbox{\tt "failed"} $$ \returnType{Type: Union("failed",...)} Here $7$ and $12$ are relatively prime, so $7$ has a multiplicative inverse modulo $12$. \spadcommand{recip b } $$ 7 $$ \returnType{Type: Union(IntegerMod 12,...)} If we take $n$ to be a prime number $p$, then taking inverses and, therefore, division are generally defined. Use {\tt PrimeField} instead of {\tt IntegerMod} for $n$ prime. \spadcommand{c : PrimeField 11 := 8 } $$ 8 $$ \returnType{Type: PrimeField 11} \spadcommand{inv c } $$ 7 $$ \returnType{Type: PrimeField 11} You can also use $1/c$ and $c**(-1)$ for the inverse of $c$. \spadcommand{9/c } $$ 8 $$ \returnType{Type: PrimeField 11} {\tt PrimeField} (abbreviation {\tt PF}) checks if its argument is prime when you try to use an operation from it. If you know the argument is prime (particularly if it is large), {\tt InnerPrimeField} (abbreviation {\tt IPF}) assumes the argument has already been verified to be prime. If you do use a number that is not prime, you will eventually get an error message, most likely a division by zero message. For computer science applications, the most important finite fields are {\tt PrimeField 2} and its extensions. In the following examples, we work with the finite field with $p = 101$ elements. \spadcommand{GF101 := PF 101 } $$ \mbox{\rm PrimeField 101} $$ \returnType{Type: Domain} Like many domains in Axiom, finite fields provide an operation for returning a random element of the domain. \spadcommand{x := random()\$GF101 } $$ 8 $$ \returnType{Type: PrimeField 101} \spadcommand{y : GF101 := 37 } $$ 37 $$ \returnType{Type: PrimeField 101} \spadcommand{z := x/y } $$ 63 $$ \returnType{Type: PrimeField 101} \spadcommand{z * y - x } $$ 0 $$ \returnType{Type: PrimeField 101} The element $2$ is a {\it primitive element} of this field, \index{primitive element} \index{element!primitive} \spadcommand{pe := primitiveElement()\$GF101 } $$ 2 $$ \returnType{Type: PrimeField 101} in the sense that its powers enumerate all nonzero elements. \spadcommand{[pe**i for i in 0..99] } $$ \begin{array}{@{}l} \left[ 1, 2, 4, 8, {16}, {32}, {64}, {27}, {54}, 7, {14}, {28}, {56}, {11}, {22}, {44}, {88}, {75}, {49}, {98}, \right. \\ \displaystyle {95}, {89}, {77}, {53}, 5, {10}, {20}, {40}, {80}, {59}, {17}, {34}, {68}, {35}, {70}, {39}, {78}, {55}, 9, \\ \displaystyle {18}, {36}, {72}, {43}, {86}, {71}, {41}, {82}, {63}, {25}, {50}, {100}, {99}, {97}, {93}, {85}, {69}, {37}, \\ \displaystyle {74}, {47}, {94}, {87}, {73}, {45}, {90}, {79}, {57}, {13}, {26}, {52}, 3, 6, {12}, {24}, {48}, {96}, {91}, \\ \displaystyle {81}, {61}, {21}, {42}, {84}, {67}, {33}, {66}, {31}, {62}, {23}, {46}, {92}, {83}, {65}, {29}, {58}, {15}, {30}, \\ \displaystyle \left. {60}, {19}, {38}, {76}, {51} \right] \end{array} $$ \returnType{Type: List PrimeField 101} If every nonzero element is a power of a primitive element, how do you determine what the exponent is? Use \index{discrete logarithm} {\bf discreteLog}. \index{logarithm!discrete} \spadcommand{ex := discreteLog(y) } $$ 56 $$ \returnType{Type: PositiveInteger} \spadcommand{pe ** ex } $$ 37 $$ \returnType{Type: PrimeField 101} The {\bf order} of a nonzero element $x$ is the smallest positive integer $t$ such $x^t = 1$. \spadcommand{order y } $$ 25 $$ \returnType{Type: PositiveInteger} The order of a primitive element is the defining $p-1$. \spadcommand{order pe } $$ 100 $$ \returnType{Type: PositiveInteger} \subsection{Extensions of Finite Fields} \label{ugxProblemFiniteExtensionFinite} \index{finite field} \index{field!finite!extension of} When you want to work with an extension of a finite field in Axiom, you have three choices to make: \begin{enumerate} \item Do you want to generate an extension of the prime field (for example, {\tt PrimeField 2}) or an extension of a given field? \item Do you want to use a representation that is particularly efficient for multiplication, exponentiation and addition but uses a lot of computer memory (a representation that models the cyclic group structure of the multiplicative group of the field extension and uses a Zech logarithm table), one that \index{Zech logarithm} uses a normal basis for the vector space structure of the field extension, or one that performs arithmetic modulo an irreducible polynomial? The cyclic group representation is only usable up to ``medium'' (relative to your machine's performance) sized fields. If the field is large and the normal basis is relatively simple, the normal basis representation is more efficient for exponentiation than the irreducible polynomial representation. \item Do you want to provide a polynomial explicitly, a root of which ``generates'' the extension in one of the three senses in (2), or do you wish to have the polynomial generated for you? \end{enumerate} This illustrates one of the most important features of Axiom: you can choose exactly the right data-type and representation to suit your application best. We first tell you what domain constructors to use for each case above, and then give some examples. \hangafter=1\hangindent=2pc Constructors that automatically generate extensions of the prime field: \newline {\tt FiniteField} \newline {\tt FiniteFieldCyclicGroup} \newline {\tt FiniteFieldNormalBasis} \hangafter=1\hangindent=2pc Constructors that generate extensions of an arbitrary field: \newline {\tt FiniteFieldExtension} \newline {\tt FiniteFieldExtensionByPolynomial} \newline {\tt FiniteFieldCyclicGroupExtension} \newline {\tt FiniteFieldCyclicGroupExtensionByPolynomial} \newline {\tt FiniteFieldNormalBasisExtension} \newline {\tt FiniteFieldNormalBasisExtensionByPolynomial} \hangafter=1\hangindent=2pc Constructors that use a cyclic group representation: \newline {\tt FiniteFieldCyclicGroup} \newline {\tt FiniteFieldCyclicGroupExtension} \newline {\tt FiniteFieldCyclicGroupExtensionByPolynomial} \hangafter=1\hangindent=2pc Constructors that use a normal basis representation: \newline {\tt FiniteFieldNormalBasis} \newline {\tt FiniteFieldNormalBasisExtension} \newline {\tt FiniteFieldNormalBasisExtensionByPolynomial} \hangafter=1\hangindent=2pc Constructors that use an irreducible modulus polynomial representation: \newline {\tt FiniteField} \newline {\tt FiniteFieldExtension} \newline {\tt FiniteFieldExtensionByPolynomial} \hangafter=1\hangindent=2pc Constructors that generate a polynomial for you: \newline {\tt FiniteField} \newline {\tt FiniteFieldExtension} \newline {\tt FiniteFieldCyclicGroup} \newline {\tt FiniteFieldCyclicGroupExtension} \newline {\tt FiniteFieldNormalBasis} \newline {\tt FiniteFieldNormalBasisExtension} \hangafter=1\hangindent=2pc Constructors for which you provide a polynomial: \newline {\tt FiniteFieldExtensionByPolynomial} \newline {\tt FiniteFieldCyclicGroupExtensionByPolynomial} \newline {\tt FiniteFieldNormalBasisExtensionByPolynomial} These constructors are discussed in the following sections where we collect together descriptions of extension fields that have the same underlying representation.\footnote{For more information on the implementation aspects of finite fields, see J. Grabmeier, A. Scheerhorn, {\it Finite Fields in AXIOM,} Technical Report, IBM Heidelberg Scientific Center, 1992.} If you don't really care about all this detail, just use {\tt FiniteField}. As your knowledge of your application and its Axiom implementation grows, you can come back and choose an alternative constructor that may improve the efficiency of your code. Note that the exported operations are almost the same for all constructors of finite field extensions and include the operations exported by {\tt PrimeField}. \subsection{Irreducible Modulus Polynomial Representations} \label{ugxProblemFiniteModulus} All finite field extension constructors discussed in this \index{finite field} section \index{field!finite!extension of} use a representation that performs arithmetic with univariate (one-variable) polynomials modulo an irreducible polynomial. This polynomial may be given explicitly by you or automatically generated. The ground field may be the prime field or one you specify. See \ref{ugxProblemFiniteExtensionFinite} on page~\pageref{ugxProblemFiniteExtensionFinite} for general information about finite field extensions. For {\tt FiniteField} (abbreviation {\tt FF}) you provide a prime number $p$ and an extension degree $n$. This degree can be 1. Axiom uses the prime field {\tt PrimeField(p)}, here {\tt PrimeField 2}, and it chooses an irreducible polynomial of degree $n$, here 12, over the ground field. \spadcommand{GF4096 := FF(2,12); } \returnType{Type: Domain} The objects in the generated field extension are polynomials of degree at most $n-1$ with coefficients in the prime field. The polynomial indeterminate is automatically chosen by Axiom and is typically something like $\%A$ or $\%D$. These (strange) variables are {\it only} for output display; there are several ways to construct elements of this field. The operation {\bf index} enumerates the elements of the field extension and accepts as argument the integers from 1 to $p ^ n$. The expression $index(p)$ always gives the indeterminate. \spadcommand{a := index(2)\$GF4096 } $$ \%A $$ \returnType{Type: FiniteField(2,12)} You can build polynomials in $a$ and calculate in $GF4096$. \spadcommand{b := a**12 - a**5 + a } $$ { \%A \sp 5}+{ \%A \sp 3}+ \%A+1 $$ \returnType{Type: FiniteField(2,12)} \spadcommand{b ** 1000 } $$ { \%A \sp {10}}+ { \%A \sp 9}+ { \%A \sp 7}+ { \%A \sp 5}+ { \%A \sp 4}+ { \%A \sp 3}+ \%A $$ \returnType{Type: FiniteField(2,12)} \spadcommand{c := a/b } $$ { \%A \sp {11}}+ { \%A \sp 8}+ { \%A \sp 7}+ { \%A \sp 5}+ { \%A \sp 4}+ { \%A \sp 3}+ { \%A \sp 2} $$ \returnType{Type: FiniteField(2,12)} Among the available operations are {\bf norm} and {\bf trace}. \spadcommand{norm c } $$ 1 $$ \returnType{Type: PrimeField 2} \spadcommand{trace c } $$ 0 $$ \returnType{Type: PrimeField 2} Since any nonzero element is a power of a primitive element, how do we discover what the exponent is? The operation {\bf discreteLog} calculates \index{discrete logarithm} the exponent and, \index{logarithm!discrete} if it is called with only one argument, always refers to the primitive element returned by {\bf primitiveElement}. \spadcommand{dL := discreteLog a } $$ 1729 $$ \returnType{Type: PositiveInteger} \spadcommand{g ** dL } $$ g \sp {1729} $$ \returnType{Type: Polynomial Integer} {\tt FiniteFieldExtension} (abbreviation {\tt FFX}) is similar to {\tt FiniteField} except that the ground-field for {\tt FiniteFieldExtension} is arbitrary and chosen by you. In case you select the prime field as ground field, there is essentially no difference between the constructed two finite field extensions. \spadcommand{GF16 := FF(2,4); } \returnType{Type: Domain} \spadcommand{GF4096 := FFX(GF16,3); } \returnType{Type: Domain} \spadcommand{r := (random()\$GF4096) ** 20 } $$ {{\left( { \%B \sp 2}+1 \right)}\ { \%C \sp 2}}+ {{\left( { \%B \sp 3}+{ \%B \sp 2}+1 \right)}\ \%C}+ { \%B \sp 3}+ { \%B \sp 2}+ \%B+1 $$ \returnType{Type: FiniteFieldExtension(FiniteField(2,4),3)} \spadcommand{norm(r) } $$ { \%B \sp 2}+ \%B $$ \returnType{Type: FiniteField(2,4)} {\tt FiniteFieldExtensionByPolynomial} (abbreviation {\tt FFP}) is similar to {\tt FiniteField} and {\tt FiniteFieldExtension} but is more general. \spadcommand{GF4 := FF(2,2); } \returnType{Type: Domain} \spadcommand{f := nextIrreduciblePoly(random(6)\$FFPOLY(GF4))\$FFPOLY(GF4) } $$ {? \sp 6}+ {{\left( \%D+1 \right)}\ {? \sp 5}}+ {{\left( \%D+1 \right)}\ {? \sp 4}}+ {{\left( \%D+1 \right)}\ ?}+1 $$ \returnType{Type: Union(SparseUnivariatePolynomial FiniteField(2,2),...)} For {\tt FFP} you choose both the ground field and the irreducible polynomial used in the representation. The degree of the extension is the degree of the polynomial. \spadcommand{GF4096 := FFP(GF4,f); } \returnType{Type: Domain} \spadcommand{discreteLog random()\$GF4096 } $$ 582 $$ \returnType{Type: PositiveInteger} \subsection{Cyclic Group Representations} \label{ugxProblemFiniteCyclic} \index{finite field} \index{field!finite!extension of} In every finite field there exist elements whose powers are all the nonzero elements of the field. Such an element is called a {\it primitive element}. In {\tt FiniteFieldCyclicGroup} (abbreviation {\tt FFCG}) \index{group!cyclic} the nonzero elements are represented by the powers of a fixed primitive \index{element!primitive} element \index{primitive element} of the field (that is, a generator of its cyclic multiplicative group). Multiplication (and hence exponentiation) using this representation is easy. To do addition, we consider our primitive element as the root of a primitive polynomial (an irreducible polynomial whose roots are all primitive). See \ref{ugxProblemFiniteUtility} on page~\pageref{ugxProblemFiniteUtility} for examples of how to compute such a polynomial. To use {\tt FiniteFieldCyclicGroup} you provide a prime number and an extension degree. \spadcommand{GF81 := FFCG(3,4); } \returnType{Type: Domain} Axiom uses the prime field, here {\tt PrimeField 3}, as the ground field and it chooses a primitive polynomial of degree $n$, here 4, over the prime field. \spadcommand{a := primitiveElement()\$GF81 } $$ \%F \sp 1 $$ \returnType{Type: FiniteFieldCyclicGroup(3,4)} You can calculate in $GF81$. \spadcommand{b := a**12 - a**5 + a } $$ \%F \sp {72} $$ \returnType{Type: FiniteFieldCyclicGroup(3,4)} In this representation of finite fields the discrete logarithm of an element can be seen directly in its output form. \spadcommand{b } $$ \%F \sp {72} $$ \returnType{Type: FiniteFieldCyclicGroup(3,4)} \spadcommand{discreteLog b } $$ 72 $$ \returnType{Type: PositiveInteger} {\tt FiniteFieldCyclicGroupExtension} (abbreviation {\tt FFCGX}) is similar to {\tt FiniteFieldCyclicGroup} except that the ground field for {\tt FiniteFieldCyclicGroupExtension} is arbitrary and chosen by you. In case you select the prime field as ground field, there is essentially no difference between the constructed two finite field extensions. \spadcommand{GF9 := FF(3,2); } \returnType{Type: Domain} \spadcommand{GF729 := FFCGX(GF9,3); } \returnType{Type: Domain} \spadcommand{r := (random()\$GF729) ** 20 } $$ \%H \sp {420} $$ \returnType{Type: FiniteFieldCyclicGroupExtension(FiniteField(3,2),3)} \spadcommand{trace(r) } $$ 0 $$ \returnType{Type: FiniteField(3,2)} {\tt FiniteFieldCyclicGroupExtensionByPolynomial} (abbreviation {\tt FFCGP}) is similar to {\tt FiniteFieldCyclicGroup} and {\tt FiniteFieldCyclicGroupExtension} but is more general. For {\tt FiniteFieldCyclicGroupExtensionByPolynomial} you choose both the ground field and the irreducible polynomial used in the representation. The degree of the extension is the degree of the polynomial. \spadcommand{GF3 := PrimeField 3; } \returnType{Type: Domain} We use a utility operation to generate an irreducible primitive polynomial (see \ref{ugxProblemFiniteUtility} on page~\pageref{ugxProblemFiniteUtility}). The polynomial has one variable that is ``anonymous'': it displays as a question mark. \spadcommand{f := createPrimitivePoly(4)\$FFPOLY(GF3) } $$ {? \sp 4}+?+2 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 3} \spadcommand{GF81 := FFCGP(GF3,f); } \returnType{Type: Domain} Let's look at a random element from this field. \spadcommand{random()\$GF81 } $$ \%K \sp {13} $$ \returnType{Type: FiniteFieldCyclicGroupExtensionByPolynomial(PrimeField 3,?**4+?+2)} \subsection{Normal Basis Representations} \label{ugxProblemFiniteNormal} \index{finite field} \index{field!finite!extension of} \index{basis!normal} \index{normal basis} Let $K$ be a finite extension of degree $n$ of the finite field $F$ and let $F$ have $q$ elements. An element $x$ of $K$ is said to be {\it normal} over $F$ if the elements $$1, x^q, x^{q^2}, \ldots, x^{q^{n-1}}$$ form a basis of $K$ as a vector space over $F$. Such a basis is called a {\it normal basis}.\footnote{This agrees with the general definition of a normal basis because the $n$ distinct powers of the automorphism $x \mapsto x^q$ constitute the Galois group of $K/F$.} If $x$ is normal over $F$, its minimal \index{polynomial!minimal} polynomial is also said to be {\it normal} over $F$. \index{minimal polynomial} There exist normal bases for all finite extensions of arbitrary finite fields. In {\tt FiniteFieldNormalBasis} (abbreviation {\tt FFNB}), the elements of the finite field are represented by coordinate vectors with respect to a normal basis. You provide a prime $p$ and an extension degree $n$. \spadcommand{K := FFNB(3,8) } $$ FiniteFieldNormalBasis(3,8) $$ \returnType{Type: Domain} Axiom uses the prime field {\tt PrimeField(p)}, here {\tt PrimeField 3}, and it chooses a normal polynomial of degree $n$, here 8, over the ground field. The remainder class of the indeterminate is used as the normal element. The polynomial indeterminate is automatically chosen by Axiom and is typically something like $\%A$ or $\%D$. These (strange) variables are only for output display; there are several ways to construct elements of this field. The output of the basis elements is something like $\%A^{q^i}.$ \spadcommand{a := normalElement()\$K } $$ \%I $$ \returnType{Type: FiniteFieldNormalBasis(3,8)} You can calculate in $K$ using $a$. \spadcommand{b := a**12 - a**5 + a } $$ {2 \ { \%I \sp {q \sp 7}}}+{ \%I \sp {q \sp 5}}+{ \%I \sp q} $$ \returnType{Type: FiniteFieldNormalBasis(3,8)} {\tt FiniteFieldNormalBasisExtension} (abbreviation {\tt FFNBX}) is similar to {\tt FiniteFieldNormalBasis} except that the groundfield for {\tt FiniteFieldNormalBasisExtension} is arbitrary and chosen by you. In case you select the prime field as ground field, there is essentially no difference between the constructed two finite field extensions. \spadcommand{GF9 := FFNB(3,2); } \returnType{Type: Domain} \spadcommand{GF729 := FFNBX(GF9,3); } \returnType{Type: Domain} \spadcommand{r := random()\$GF729 } $$ 2 \ \%K \ { \%L \sp q} $$ \returnType{Type: FiniteFieldNormalBasisExtension(FiniteFieldNormalBasis(3,2),3)} \spadcommand{r + r**3 + r**9 + r**27 } $$ {2 \ \%K \ { \%L \sp {q \sp 2}}}+ {{\left( {2 \ { \%K \sp q}}+{2 \ \%K} \right)}\ { \%L \sp q}}+ {2 \ { \%K \sp q} \ \%L} $$ \returnType{Type: FiniteFieldNormalBasisExtension(FiniteFieldNormalBasis(3,2),3)} {\tt FiniteFieldNormalBasisExtensionByPolynomial} (abbreviation {\tt FFNBP}) is similar to {\tt FiniteFieldNormalBasis} and {\tt FiniteFieldNormalBasisExtension} but is more general. For {\tt FiniteFieldNormalBasisExtensionByPolynomial} you choose both the ground field and the irreducible polynomial used in the representation. The degree of the extension is the degree of the polynomial. \spadcommand{GF3 := PrimeField 3; } \returnType{Type: Domain} We use a utility operation to generate an irreducible normal polynomial (see \ref{ugxProblemFiniteUtility} on page~\pageref{ugxProblemFiniteUtility}). The polynomial has one variable that is ``anonymous'': it displays as a question mark. \spadcommand{f := createNormalPoly(4)\$FFPOLY(GF3) } $$ {? \sp 4}+{2 \ {? \sp 3}}+2 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 3} \spadcommand{GF81 := FFNBP(GF3,f); } \returnType{Type: Domain} Let's look at a random element from this field. \spadcommand{r := random()\$GF81 } $$ { \%M \sp {q \sp 2}}+{2 \ { \%M \sp q}}+{2 \ \%M} $$ \returnType{Type: FiniteFieldNormalBasisExtensionByPolynomial(PrimeField 3,?**4+2*?**3+2)} \spadcommand{r * r**3 * r**9 * r**27 } $$ {2 \ { \%M \sp {q \sp 3}}}+ {2 \ { \%M \sp {q \sp 2}}}+ {2 \ { \%M \sp q}}+ {2 \ \%M} $$ \returnType{Type: FiniteFieldNormalBasisExtensionByPolynomial(PrimeField 3,?**4+2*?**3+2)} \spadcommand{norm r } $$ 2 $$ \returnType{Type: PrimeField 3} \subsection{Conversion Operations for Finite Fields} \label{ugxProblemFiniteConversion} \index{field!finite!conversions} Let $K$ be a finite field. \spadcommand{K := PrimeField 3 } $$ \mbox{\rm PrimeField 3} $$ \returnType{Type: Domain} An extension field $K_m$ of degree $m$ over $K$ is a subfield of an extension field $K_n$ of degree $n$ over $K$ if and only if $m$ divides $n$. \begin{center} \begin{tabular}{ccc} $K_n$ \\ $|$ \\ $K_m$ & $\Longleftrightarrow$ & $m | n$ \\ $|$ \\ K \end{tabular} \end{center} {\tt FiniteFieldHomomorphisms} provides conversion operations between different extensions of one fixed finite ground field and between different representations of these finite fields. Let's choose $m$ and $n$, \spadcommand{(m,n) := (4,8) } $$ 8 $$ \returnType{Type: PositiveInteger} build the field extensions, \spadcommand{Km := FiniteFieldExtension(K,m) } $$ \mbox{\rm FiniteFieldExtension(PrimeField 3,4)} $$ \returnType{Type: Domain} and pick two random elements from the smaller field. \spadcommand{Kn := FiniteFieldExtension(K,n) } $$ \mbox{\rm FiniteFieldExtension(PrimeField 3,8)} $$ \returnType{Type: Domain} \spadcommand{a1 := random()\$Km } $$ {2 \ { \%A \sp 3}}+{ \%A \sp 2} $$ \returnType{Type: FiniteFieldExtension(PrimeField 3,4)} \spadcommand{b1 := random()\$Km } $$ { \%A \sp 3}+{ \%A \sp 2}+{2 \ \%A}+1 $$ \returnType{Type: FiniteFieldExtension(PrimeField 3,4)} Since $m$ divides $n$, $K_m$ is a subfield of $K_n$. \spadcommand{a2 := a1 :: Kn } $$ \%B \sp 4 $$ \returnType{Type: FiniteFieldExtension(PrimeField 3,8)} Therefore we can convert the elements of $K_m$ into elements of $K_n$. \spadcommand{b2 := b1 :: Kn } $$ {2 \ { \%B \sp 6}}+{2 \ { \%B \sp 4}}+{ \%B \sp 2}+1 $$ \returnType{Type: FiniteFieldExtension(PrimeField 3,8)} To check this, let's do some arithmetic. \spadcommand{a1+b1 - ((a2+b2) :: Km) } $$ 0 $$ \returnType{Type: FiniteFieldExtension(PrimeField 3,4)} \spadcommand{a1*b1 - ((a2*b2) :: Km) } $$ 0 $$ \returnType{Type: FiniteFieldExtension(PrimeField 3,4)} There are also conversions available for the situation, when $K_m$ and $K_n$ are represented in different ways (see \ref{ugxProblemFiniteExtensionFinite} on page~\pageref{ugxProblemFiniteExtensionFinite}). For example let's choose $K_m$ where the representation is 0 plus the cyclic multiplicative group and $K_n$ with a normal basis representation. \spadcommand{Km := FFCGX(K,m) } $$ \mbox{\rm FiniteFieldCyclicGroupExtension(PrimeField 3,4)} $$ \returnType{Type: Domain} \spadcommand{Kn := FFNBX(K,n) } $$ \mbox{\rm FiniteFieldNormalBasisExtension(PrimeField 3,8)} $$ \returnType{Type: Domain} \spadcommand{(a1,b1) := (random()\$Km,random()\$Km) } $$ \%C \sp {13} $$ \returnType{Type: FiniteFieldCyclicGroupExtension(PrimeField 3,4)} \spadcommand{a2 := a1 :: Kn } $$ {2 \ { \%D \sp {q \sp 6}}}+ {2 \ { \%D \sp {q \sp 5}}}+ {2 \ { \%D \sp {q \sp 4}}}+ {2 \ { \%D \sp {q \sp 2}}}+ {2 \ { \%D \sp q}}+ {2 \ \%D} $$ \returnType{Type: FiniteFieldNormalBasisExtension(PrimeField 3,8)} \spadcommand{b2 := b1 :: Kn } $$ {2 \ { \%D \sp {q \sp 7}}}+ { \%D \sp {q \sp 6}}+ { \%D \sp {q \sp 5}}+ { \%D \sp {q \sp 4}}+ {2 \ { \%D \sp {q \sp 3}}}+ { \%D \sp {q \sp 2}}+ { \%D \sp q}+ \%D $$ \returnType{Type: FiniteFieldNormalBasisExtension(PrimeField 3,8)} Check the arithmetic again. \spadcommand{a1+b1 - ((a2+b2) :: Km) } $$ 0 $$ \returnType{Type: FiniteFieldCyclicGroupExtension(PrimeField 3,4)} \spadcommand{a1*b1 - ((a2*b2) :: Km) } $$ 0 $$ \returnType{Type: FiniteFieldCyclicGroupExtension(PrimeField 3,4)} \subsection{Utility Operations for Finite Fields} \label{ugxProblemFiniteUtility} {\tt FiniteFieldPolynomialPackage} (abbreviation {\tt FFPOLY}) provides operations for generating, counting and testing polynomials over finite fields. Let's start with a couple of definitions: \begin{itemize} \item A polynomial is {\it primitive} if its roots are primitive \index{polynomial!primitive} elements in an extension of the coefficient field of degree equal to the degree of the polynomial. \item A polynomial is {\it normal} over its coefficient field \index{polynomial!normal} if its roots are linearly independent elements in an extension of the coefficient field of degree equal to the degree of the polynomial. \end{itemize} In what follows, many of the generated polynomials have one ``anonymous'' variable. This indeterminate is displayed as a question mark ({\tt ``?''}). To fix ideas, let's use the field with five elements for the first few examples. \spadcommand{GF5 := PF 5; } \returnType{Type: Domain} You can generate irreducible polynomials of any (positive) degree \index{polynomial!irreducible} (within the storage capabilities of the computer and your ability to wait) by using \spadfunFrom{createIrreduciblePoly}{FiniteFieldPolynomialPackage}. \spadcommand{f := createIrreduciblePoly(8)\$FFPOLY(GF5) } $$ {? \sp 8}+{? \sp 4}+2 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} Does this polynomial have other important properties? Use {\bf primitive?} to test whether it is a primitive polynomial. \spadcommand{primitive?(f)\$FFPOLY(GF5) } $$ {\tt false} $$ \returnType{Type: Boolean} Use {\bf normal?} to test whether it is a normal polynomial. \spadcommand{normal?(f)\$FFPOLY(GF5) } $$ {\tt false} $$ \returnType{Type: Boolean} \noindent Note that this is actually a trivial case, because a normal polynomial of degree $n$ must have a nonzero term of degree $n-1$. We will refer back to this later. To get a primitive polynomial of degree 8 just issue this. \spadcommand{p := createPrimitivePoly(8)\$FFPOLY(GF5) } $$ {? \sp 8}+{? \sp 3}+{? \sp 2}+?+2 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} \spadcommand{primitive?(p)\$FFPOLY(GF5) } $$ {\tt true} $$ \returnType{Type: Boolean} This polynomial is not normal, \spadcommand{normal?(p)\$FFPOLY(GF5) } $$ {\tt false} $$ \returnType{Type: Boolean} but if you want a normal one simply write this. \spadcommand{n := createNormalPoly(8)\$FFPOLY(GF5) } $$ {? \sp 8}+{4 \ {? \sp 7}}+{? \sp 3}+1 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} This polynomial is not primitive! \spadcommand{primitive?(n)\$FFPOLY(GF5) } $$ {\tt false} $$ \returnType{Type: Boolean} This could have been seen directly, as the constant term is 1 here, which is not a primitive element up to the factor ($-1$) raised to the degree of the polynomial.\footnote{Cf. Lidl, R. \& Niederreiter, H., {\it Finite Fields,} Encycl. of Math. 20, (Addison-Wesley, 1983), p.90, Th. 3.18.} What about polynomials that are both primitive and normal? The existence of such a polynomial is by no means obvious. \footnote{The existence of such polynomials is proved in Lenstra, H. W. \& Schoof, R. J., {\it Primitive Normal Bases for Finite Fields,} Math. Comp. 48, 1987, pp. 217-231.} % If you really need one use either \spadfunFrom{createPrimitiveNormalPoly}{FiniteFieldPolynomialPackage} or \spadfunFrom{createNormalPrimitivePoly}{FiniteFieldPolynomialPackage}. \spadcommand{createPrimitiveNormalPoly(8)\$FFPOLY(GF5) } $$ {? \sp 8}+{4 \ {? \sp 7}}+{2 \ {? \sp 5}}+2 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} If you want to obtain additional polynomials of the various types above as given by the {\bf create...} operations above, you can use the {\bf next...} operations. For instance, \spadfunFrom{nextIrreduciblePoly}{FiniteFieldPolynomialPackage} yields the next monic irreducible polynomial with the same degree as the input polynomial. By ``next'' we mean ``next in a natural order using the terms and coefficients.'' This will become more clear in the following examples. This is the field with five elements. \spadcommand{GF5 := PF 5; } \returnType{Type: Domain} Our first example irreducible polynomial, say of degree 3, must be ``greater'' than this. \spadcommand{h := monomial(1,8)\$SUP(GF5) } $$ ? \sp 8 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} You can generate it by doing this. \spadcommand{nh := nextIrreduciblePoly(h)\$FFPOLY(GF5) } $$ {? \sp 8}+2 $$ \returnType{Type: Union(SparseUnivariatePolynomial PrimeField 5,...)} Notice that this polynomial is not the same as the one \spadfunFrom{createIrreduciblePoly}{FiniteFieldPolynomialPackage}. \spadcommand{createIrreduciblePoly(3)\$FFPOLY(GF5) } $$ {? \sp 3}+?+1 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} You can step through all irreducible polynomials of degree 8 over the field with 5 elements by repeatedly issuing this. \spadcommand{nh := nextIrreduciblePoly(nh)\$FFPOLY(GF5) } $$ {? \sp 8}+3 $$ \returnType{Type: Union(SparseUnivariatePolynomial PrimeField 5,...)} You could also ask for the total number of these. \spadcommand{numberOfIrreduciblePoly(5)\$FFPOLY(GF5) } $$ 624 $$ \returnType{Type: PositiveInteger} We hope that ``natural order'' on polynomials is now clear: first we compare the number of monomials of two polynomials (``more'' is ``greater''); then, if necessary, the degrees of these monomials (lexicographically), and lastly their coefficients (also lexicographically, and using the operation {\bf lookup} if our field is not a prime field). Also note that we make both polynomials monic before looking at the coefficients: multiplying either polynomial by a nonzero constant produces the same result. The package {\tt FiniteFieldPolynomialPackage} also provides similar operations for primitive and normal polynomials. With the exception of the number of primitive normal polynomials; we're not aware of any known formula for this. \spadcommand{numberOfPrimitivePoly(3)\$FFPOLY(GF5) } $$ 20 $$ \returnType{Type: PositiveInteger} Take these, \spadcommand{m := monomial(1,1)\$SUP(GF5) } $$ ? $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} \spadcommand{f := m**3 + 4*m**2 + m + 2 } $$ {? \sp 3}+{4 \ {? \sp 2}}+?+2 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} and then we have: \spadcommand{f1 := nextPrimitivePoly(f)\$FFPOLY(GF5) } $$ {? \sp 3}+{4 \ {? \sp 2}}+{4 \ ?}+2 $$ \returnType{Type: Union(SparseUnivariatePolynomial PrimeField 5,...)} What happened? \spadcommand{nextPrimitivePoly(f1)\$FFPOLY(GF5) } $$ {? \sp 3}+{2 \ {? \sp 2}}+3 $$ \returnType{Type: Union(SparseUnivariatePolynomial PrimeField 5,...)} Well, for the ordering used in \spadfunFrom{nextPrimitivePoly}{FiniteFieldPolynomialPackage} we use as first criterion a comparison of the constant terms of the polynomials. Analogously, in \spadfunFrom{nextNormalPoly}{FiniteFieldPolynomialPackage} we first compare the monomials of degree 1 less than the degree of the polynomials (which is nonzero, by an earlier remark). \spadcommand{f := m**3 + m**2 + 4*m + 1 } $$ {? \sp 3}+{? \sp 2}+{4 \ ?}+1 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 5} \spadcommand{f1 := nextNormalPoly(f)\$FFPOLY(GF5) } $$ {? \sp 3}+{? \sp 2}+{4 \ ?}+3 $$ \returnType{Type: Union(SparseUnivariatePolynomial PrimeField 5,...)} \spadcommand{nextNormalPoly(f1)\$FFPOLY(GF5) } $$ {? \sp 3}+{2 \ {? \sp 2}}+1 $$ \returnType{Type: Union(SparseUnivariatePolynomial PrimeField 5,...)} \noindent We don't have to restrict ourselves to prime fields. Let's consider, say, a field with 16 elements. \spadcommand{GF16 := FFX(FFX(PF 2,2),2); } \returnType{Type: Domain} We can apply any of the operations described above. \spadcommand{createIrreduciblePoly(5)\$FFPOLY(GF16) } $$ {? \sp 5}+ \%G $$ \returnType{Type: SparseUnivariatePolynomial FiniteFieldExtension(FiniteFieldExtension(PrimeField 2,2),2)} Axiom also provides operations for producing random polynomials of a given degree \spadcommand{random(5)\$FFPOLY(GF16) } $$ \begin{array}{@{}l} {? \sp 5}+ {{\left( { \%F \ \%G}+1 \right)}\ {? \sp 4}}+ { \%F \ \%G \ {? \sp 3}}+ {{\left( \%G+ \%F+1 \right)}\ {? \sp 2}}+ \\ \\ \displaystyle {{\left( {{\left( \%F+1 \right)}\ \%G}+ \%F \right)}\ ?}+1 \end{array} $$ \returnType{Type: SparseUnivariatePolynomial FiniteFieldExtension(FiniteFieldExtension(PrimeField 2,2),2)} or with degree between two given bounds. \spadcommand{random(3,9)\$FFPOLY(GF16) } $$ {? \sp 3}+ {{\left( { \%F \ \%G}+1 \right)}\ {? \sp 2}}+ {{\left( \%G+ \%F+1 \right)}\ ?}+1 $$ \returnType{Type: SparseUnivariatePolynomial FiniteFieldExtension(FiniteFieldExtension(PrimeField 2,2),2)} {\tt FiniteFieldPolynomialPackage2} (abbreviation {\tt FFPOLY2}) exports an operation {\bf rootOfIrreduciblePoly} for finding one root of an irreducible polynomial $f$ \index{polynomial!root of} in an extension field of the coefficient field. The degree of the extension has to be a multiple of the degree of $f$. It is not checked whether $f$ actually is irreducible. To illustrate this operation, we fix a ground field $GF$ \spadcommand{GF2 := PrimeField 2; } \returnType{Type: Domain} and then an extension field. \spadcommand{F := FFX(GF2,12) } $$ \mbox{\rm FiniteFieldExtension(PrimeField 2,12)} $$ \returnType{Type: Domain} We construct an irreducible polynomial over $GF2$. \spadcommand{f := createIrreduciblePoly(6)\$FFPOLY(GF2) } $$ {? \sp 6}+?+1 $$ \returnType{Type: SparseUnivariatePolynomial PrimeField 2} We compute a root of $f$. \spadcommand{root := rootOfIrreduciblePoly(f)\$FFPOLY2(F,GF2) } $$ { \%H \sp {11}}+{ \%H \sp 8}+{ \%H \sp 7}+{ \%H \sp 5}+ \%H+1 $$ \returnType{Type: FiniteFieldExtension(PrimeField 2,12)} and check the result \spadcommand{eval(f, monomial(1,1)\$SUP(F) = root) } $$ 0 $$ \returnType{Type: SparseUnivariatePolynomial FiniteFieldExtension(PrimeField 2,12)} \section{Primary Decomposition of Ideals} \label{ugProblemIdeal} Axiom provides a facility for the primary decomposition \index{ideal!primary decomposition} of \index{primary decomposition of ideal} polynomial ideals over fields of characteristic zero. The algorithm %is discussed in \cite{gtz:gbpdpi} and works in essentially two steps: \begin{enumerate} \item the problem is solved for 0-dimensional ideals by ``generic'' projection on the last coordinate \item a ``reduction process'' uses localization and ideal quotients to reduce the general case to the 0-dimensional one. \end{enumerate} The Axiom constructor {\tt PolynomialIdeals} represents ideals with coefficients in any field and supports the basic ideal operations, including intersection, sum and quotient. {\tt IdealDecompositionPackage} contains the specific operations for the primary decomposition and the computation of the radical of an ideal with polynomial coefficients in a field of characteristic 0 with an effective algorithm for factoring polynomials. The following examples illustrate the capabilities of this facility. First consider the ideal generated by $x^2 + y^2 - 1$ (which defines a circle in the $(x,y)$-plane) and the ideal generated by $x^2 - y^2$ (corresponding to the straight lines $x = y$ and $x = -y$. \spadcommand{(n,m) : List DMP([x,y],FRAC INT) } \returnType{Type: Void} \spadcommand{m := [x**2+y**2-1] } $$ \left[ {{x \sp 2}+{y \sp 2} -1} \right] $$ \returnType{Type: List DistributedMultivariatePolynomial([x,y],Fraction Integer)} \spadcommand{n := [x**2-y**2] } $$ \left[ {{x \sp 2} -{y \sp 2}} \right] $$ \returnType{Type: List DistributedMultivariatePolynomial([x,y],Fraction Integer)} We find the equations defining the intersection of the two loci. This correspond to the sum of the associated ideals. \spadcommand{id := ideal m + ideal n } $$ \left[ {{x \sp 2} -{1 \over 2}}, {{y \sp 2} -{1 \over 2}} \right] $$ \returnType{Type: PolynomialIdeals(Fraction Integer, DirectProduct(2,NonNegativeInteger),OrderedVariableList [x,y], DistributedMultivariatePolynomial([x,y],Fraction Integer))} We can check if the locus contains only a finite number of points, that is, if the ideal is zero-dimensional. \spadcommand{zeroDim? id } $$ {\tt true} $$ \returnType{Type: Boolean} \spadcommand{zeroDim?(ideal m) } $$ {\tt false} $$ \returnType{Type: Boolean} \spadcommand{dimension ideal m } $$ 1 $$ \returnType{Type: PositiveInteger} We can find polynomial relations among the generators ($f$ and $g$ are the parametric equations of the knot). \spadcommand{(f,g):DMP([x,y],FRAC INT) } \returnType{Type: Void} \spadcommand{f := x**2-1 } $$ {x \sp 2} -1 $$ \returnType{Type: DistributedMultivariatePolynomial([x,y],Fraction Integer)} \spadcommand{g := x*(x**2-1) } $$ {x \sp 3} -x $$ \returnType{Type: DistributedMultivariatePolynomial([x,y],Fraction Integer)} \spadcommand{relationsIdeal [f,g] } $$ {\left[ {-{ \%B \sp 2}+{ \%A \sp 3}+{ \%A \sp 2}} \right]} \mid {\left[ { \%A={{x \sp 2} -1}}, { \%B={{x \sp 3} -x}} \right]} $$ \returnType{Type: SuchThat(List Polynomial Fraction Integer, List Equation Polynomial Fraction Integer)} We can compute the primary decomposition of an ideal. \spadcommand{l: List DMP([x,y,z],FRAC INT) } \returnType{Type: Void} \spadcommand{l:=[x**2+2*y**2,x*z**2-y*z,z**2-4] } $$ \left[ {{x \sp 2}+{2 \ {y \sp 2}}}, {{x \ {z \sp 2}} -{y \ z}}, {{z \sp 2} -4} \right] $$ \returnType{Type: List DistributedMultivariatePolynomial([x,y,z],Fraction Integer)} \spadcommand{ld:=primaryDecomp ideal l } $$ \left[ {\left[ {x+{{1 \over 2} \ y}}, {y \sp 2}, {z+2} \right]}, {\left[ {x -{{1 \over 2} \ y}}, {y \sp 2}, {z -2} \right]} \right] $$ \returnType{Type: List PolynomialIdeals(Fraction Integer, DirectProduct(3,NonNegativeInteger), OrderedVariableList [x,y,z], DistributedMultivariatePolynomial([x,y,z],Fraction Integer))} We can intersect back. \spadcommand{reduce(intersect,ld) } $$ \left[ {x -{{1 \over 4} \ y \ z}}, {y \sp 2}, {{z \sp 2} -4} \right] $$ \returnType{Type: PolynomialIdeals(Fraction Integer, DirectProduct(3,NonNegativeInteger), OrderedVariableList [x,y,z], DistributedMultivariatePolynomial([x,y,z],Fraction Integer))} We can compute the radical of every primary component. \spadcommand{reduce(intersect,[radical ld.i for i in 1..2]) } $$ \left[ x, y, {{z \sp 2} -4} \right] $$ \returnType{Type: PolynomialIdeals(Fraction Integer, DirectProduct(3,NonNegativeInteger), OrderedVariableList [x,y,z], DistributedMultivariatePolynomial([x,y,z],Fraction Integer))} Their intersection is equal to the radical of the ideal of $l$. \spadcommand{radical ideal l } $$ \left[x, y, {{z \sp 2} -4} \right] $$ \returnType{Type: PolynomialIdeals(Fraction Integer, DirectProduct(3,NonNegativeInteger), OrderedVariableList [x,y,z], DistributedMultivariatePolynomial([x,y,z],Fraction Integer))} \section{Computation of Galois Groups} \label{ugProblemGalois} As a sample use of Axiom's algebraic number facilities, \index{group!Galois} we compute \index{Galois!group} the Galois group of the polynomial $p(x) = x^5 - 5 x + 12$. \spadcommand{p := x**5 - 5*x + 12 } $$ {x \sp 5} -{5 \ x}+{12} $$ \returnType{Type: Polynomial Integer} We would like to construct a polynomial $f(x)$ such that the splitting \index{field!splitting} field \index{splitting field} of $p(x)$ is generated by one root of $f(x)$. First we construct a polynomial $r = r(x)$ such that one root of $r(x)$ generates the field generated by two roots of the polynomial $p(x)$. (As it will turn out, the field generated by two roots of $p(x)$ is, in fact, the splitting field of $p(x)$.) From the proof of the primitive element theorem we know that if $a$ and $b$ are algebraic numbers, then the field ${\bf Q}(a,b)$ is equal to ${\bf Q}(a+kb)$ for an appropriately chosen integer $k$. In our case, we construct the minimal polynomial of $a_i - a_j$, where $a_i$ and $a_j$ are two roots of $p(x)$. We construct this polynomial using {\bf resultant}. The main result we need is the following: If $f(x)$ is a polynomial with roots $a_i \ldots a_m$ and $g(x)$ is a polynomial with roots $b_i \ldots b_n$, then the polynomial $h(x) = resultant(f(y), g(x-y), y)$ is a polynomial of degree $m*n$ with roots $a_i + b_j, i = 1 \ldots m, j = 1 \ldots n$. For $f(x)$ we use the polynomial $p(x)$. For $g(x)$ we use the polynomial $-p(-x)$. Thus, the polynomial we first construct is $resultant(p(y), -p(y-x), y)$. \spadcommand{q := resultant(eval(p,x,y),-eval(p,x,y-x),y) } $$ \begin{array}{@{}l} {x \sp {25}} - {{50} \ {x \sp {21}}} - {{2375} \ {x \sp {17}}}+ {{90000} \ {x \sp {15}}} - {{5000} \ {x \sp {13}}}+ {{2700000} \ {x \sp {11}}}+ {{250000} \ {x \sp 9}}+ \\ \\ \displaystyle {{18000000} \ {x \sp 7}}+ {{64000000} \ {x \sp 5}} \end{array} $$ \returnType{Type: Polynomial Integer} The roots of $q(x)$ are $a_i - a_j, i \leq 1, j \leq 5$. Of course, there are five pairs $(i,j)$ with $i = j$, so $0$ is a 5-fold root of $q(x)$. Let's get rid of this factor. \spadcommand{q1 := exquo(q, x**5) } $$ \begin{array}{@{}l} {x \sp {20}} - {{50} \ {x \sp {16}}} -