\documentclass{book}
%\usepackage{axiom}
\usepackage{graphicx}
% struggle with latex figurefloating 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) 19912002, 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 printondemand 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 manyears 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 spacetime 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 selfcontained 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 stateoftheart 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**4949*x**4+9 = 0,1.e49)}
$$
\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, nonlinear optimization, linear
algebra, basic statistics, stepwise 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 hardcopy output.
\subsection{HyperDoc}
\begin{figure}[htbp]
\includegraphics[bbllx=1, bblly=1, bburx=298, bbury=290]{ps/hroot.ps}
\caption{Hyperdoc opening menu}
\label{figintrobr}
\end{figure}
HyperDoc presents you windows on the world of Axiom,
offering online help, examples, tutorials, a browser, and reference
material. HyperDoc gives you online 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 mouseactive; 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{figintrobr} on
page~\pageref{figintrobr} 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 userdefined function is one
that computes the successive Legendre polynomials. Axiom lets
you define these polynomials in a piecewise 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*n1)*x*p(n1)  (n1) * p(n2))/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 computationthey 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 machinecode. 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 typeanalyzed 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 runtime 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 typechecking. Unlike these languages, types in
Axiom are dynamic objects: they are created at runtime 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 easeofuse.
The Axiom interpreter uses typeinferencing 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 lowerlevel 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 typecorrectness. 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, directedacyclic 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 lexicographiccomparison in an algorithm.
However, it is wrong to use the same {\tt <} with this definition
of absolutevalue: $$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}:
floatingpoint 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 typechecking at compile time;
\item fast linkage to operations in domainvalued parameters;
\item optimization techniques to be used for partially specified types
(operations for ``vectors of $R$'', for instance, can be opencoded 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 codeeconomy.
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 floatingpoint 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 floatingpoint values in exponent notation
and the latter causes it to use fixedpoint 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 nonzero values if the arithmetic
is performed modulo a prime number. Thus arithmetic modulo a nonprime
integer is possible but the reciprocal operation is undefined and will
generate an error. Attempting to use the {\tt PrimeField} type constructor
with a nonprime argument will generate an error. An example of nonprime
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. Multiline
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 socalled ``plus plus'' comments are used
within the algebra files and are processed by the compiler to add
to the documentation. The socalled ``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 $n1$ 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
sideeffect 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 onedimensional 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}
Onedimensional 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 onedimensional 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.
Onedimensional 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 onedimensional 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 onedimensional 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 onedimensional 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 onedimensional
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 oneline 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 userdefined
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 ifthenelse} 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 ifthenelse} 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 rowmajor
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 predefined. 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{
multiset
UnivariatePolynomial
MultivariatePolynomial
DistributedMultivariatePolynomial
HomogeneousDistributedMultivariatePolynomial
NewDistributedMultivariatePolynomial
GeneralDistributedMultivariatePolynomial
}
\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 ifthenelse} 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 righthand side of the expression is evaluated, yielding $1$.
This value is then assigned to $a$.
\spadcommand{a := 1}
$$
1
$$
\returnType{Type: PositiveInteger}
The righthand 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 righthand 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 righthand side of each delayed assignment is left unevaluated
until the variables on the lefthand 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 ifthenelse} 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 ifthenelse} 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{ifthenelse}
\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 ifthenelse} 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 ifthenelse}
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 twoline 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
interpretcode 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 mean 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 ifthen} 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 $mn+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 straightforward 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 semicolon
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 Ctrlc}.
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{UserDefined 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 oneline examples of functions, together
with larger ones that are defined piecebypiece 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
``mapsto'' 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 packagecall} 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 greaterthan 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} beforeusing 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{OneLine Functions}
\label{ugUserOne}
As you use Axiom, you will find that you will write many short
functions \index{function!oneline definition} to codify sequences of
operations that you often perform. In this section we write some
simple oneline functions.
This is a simple recursive factorial function for positive integers.
\spadcommand{fac n == if n < 3 then n else n * fac(n1)}
\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
packagecalling 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
packagecalling 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 functionshow 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 righthandside of a function evaluation is
not evaluated until the lefthandside 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 packagecall}
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 packagecall 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 nonrecursive part, if that exists. This may be remedied
by declaring the function.
\end{verbatim}
Again, we could packagecall 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{interpretcode mode} in interpretcode 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 interpretcode 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 runtime 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{PieceWise Function Definitions}
\label{ugUserPiece}
To move beyond functions defined in one line, we introduce in this
section functions that are defined piecebypiece. That is, we say
``use this definition when the argument is suchandsuch and use this
other definition when the argument is thatandthat.''
\subsection{A Basic Example}
\label{ugUserPieceBasic}
There are many other ways to define a factorial function for
nonnegative integers. You might
\index{function!piecewise definition}
say \index{piecewise function definition} factorial of
$0$ is $1$, otherwise factorial of $n$ is $n$ times factorial of
$n1$. 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 nonnegative"}
\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 nonnegative
\end{verbatim}
\returnType{Type: PositiveInteger}
To see the current piecewise 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 nonnegative)
facto n == n facto(n  1)
\end{verbatim}
In general a {\it piecewise 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 piecewise definitions for the factorial function are examples
of recursive functions, that is, functions that are defined in terms
of themselves. Here is an interesting doublyrecursive 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, piecewise 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 doublyrecursive 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
piecewise 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(n1)
\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 piecewise definition.
\spadcommand{fib(1) == 1}
\returnType{Type: Void}
\spadcommand{fib(2) == 1}
\returnType{Type: Void}
\spadcommand{fib(n) == fib(n1) + fib(n2)}
\returnType{Type: Void}
As defined, this recurrence relation is obviously doublyrecursive.
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 fivehundredth 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*n1)*x*p(n1)  (n1)*p(n2))/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(xy)/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 piecewise 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..(n1) repeat
for j in n..(i+1) by 1 repeat
if m.j < m.(j1) then swap(m,j,j1)
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 $i1$ 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.(j1) repeat
swap(m,j,j1)
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 selfdocumentation, 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 linebyline, from toptobottom.
The righthand side of an assignment is looked at before the lefthand
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 righthand 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 unchangedit 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( + , [ (xi)**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 < index1 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(n1)  2 \, p(n2) + 4 \, p(n3)$
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 ``mapsto'' 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 fourbyfour 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 greatgrandparents. Well, a
greatgrandparent 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 runtime 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 greatgrandparents?
\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
piecewise 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(i1,j1)+pascal(i,j1)
\end{verbatim}
\returnType{Type: Void}
Now that we have defined the coefficients in Pascal's triangle, let's
write a couple of oneliners 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,i1)
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,x1,0,x1,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 lefthand side of a rewrite rule is called a {\it pattern};
its rightside side is called its {\it substitution}.
Create a rewrite rule named {\bf logrule}. The generated symbol
beginning with a ``{\tt \%}'' is a placeholder 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 righthand 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
righthand 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)==(1sin(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(xy)  cos(x + y))/2
cos(x) * cos(y) == (cos(xy) + cos(x+y))/2
sin(x) * cos(y) == (sin(xy) + 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 lefthand 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 nonzero, 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 welldefined {\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
twodi\men\sion\al and threedi\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} controlpanel 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{TwoDimensional Graphics}
\label{ugGraphTwoD}
The Axiom twodi\men\sion\al graphics package provides the ability
to \index{graphics!twodimensional} display
\begin{itemize}
\item curves defined by functions of a single real variable
\item curves defined by parametric equations
\item implicit nonsingular 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 TwoDimensional Functions of One Variable}
\label{ugGraphTwoDPlot}
\index{curve!one variable function} The first kind of
twodi\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) == (x1)*(x2)*(x3) }
%\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 TwoDimensional Parametric Plane Curves}
\label{ugGraphTwoDPar}
The second kind of twodi\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 twodi\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 twodi\men\sion\al graph is a nonsingular
``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}
Nonsingular 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!nonsingular} \index{smooth curve}
\index{nonsingular curve}
\boxed{4.6in}{
\vskip 0.1cm
The general format for drawing a nonsingular 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*x1) }
\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{TwoDimensional 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 yaxis.
\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 twodi\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 threedi\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 twodi\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{TwoDimensional ControlPanel}
\label{ugGraphTwoDControl}
\index{graphics!2D controlpanel}
Once you have created a viewport, move your mouse to the viewport and click
with your left mouse button to display a controlpanel.
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 controlpanel.}
\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{Twodimensional controlpanel.}
\end{figure}
%\end{texonly}
\subsubsection{Transformations}
\index{graphics!2D controlpanel!transformations}
Object transformations are executed from the controlpanel by mouseactivated
potentiometer windows.
%
\begin{description}
%
\item[Scale:] To scale a graph, click on a mouse button
\index{graphics!2D controlpanel!scale}
within the {\bf Scale} window in the upper left corner of the controlpanel.
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
nonuniform.
%
\item[Translate:] To translate a graph, click the mouse in the
\index{graphics!2D controlpanel!translate}
{\bf Translate} window in the direction you wish the graph to move.
This window is located in the upper right corner of the controlpanel.
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 controlpanel!messages}
The window directly below the transformation potentiometer windows is
used to display system messages relating to the viewport and the controlpanel.
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 controlpanel!multiple graphs}
The {\bf Graphs} window contains buttons that allow the placement
of twodi\men\sion\al graphs into one of nine available slots in any other
twodi\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 controlpanel!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 controlpanel!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 controlpanel!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 controlpanel!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 controlpanel!buttons}
%
\begin{description}
%
\item[Axes] turns the coordinate axes on or off.
\index{graphics!2D controlpanel!axes}
%
\item[Units] turns the units along the {\tt x}
and {\tt y} axis on or off.
\index{graphics!2D controlpanel!units}
%
\item[Box] encloses the area of the viewport graph
in a bounding box, or removes the box if already enclosed.
\index{graphics!2D controlpanel!box}
%
\item[Pts] turns on or off the display of points.
\index{graphics!2D controlpanel!points}
%
\item[Lines] turns on or off the display
of lines connecting points.
\index{graphics!2D controlpanel!lines}
%
\item[PS] writes the current viewport contents to
\index{graphics!2D controlpanel!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 controlpanel!reset}
%
\item[Hide] makes the controlpanel disappear.
\index{graphics!2D controlpanel!hide}
%
\item[Quit] queries whether the current viewport
\index{graphics!2D controlpanel!quit}
session should be terminated.
\end{description}
\subsection{Operations for TwoDimensional Graphics}
\label{ugGraphTwoDops}
Here is a summary of useful Axiom operations for twodi\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 twodi\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 twodi\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 twodi\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 twodi\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 twodi\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 twodi\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 twodi\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 lefthand 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 lefthand corner of a twodi\men\sion\al viewport, relative to the
display root window.
The upper lefthand 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 twodi\men\sion\al controlpanel 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 lefthand 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 TwoDimensional Graphs}
\label{ugGraphTwoDbuild}
In this section we demonstrate how to create twodi\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 TwoDimensional Viewport from a List of Points}
Axiom creates lists of points in a twodi\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 twodi\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 TwoDimensional 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 twodi\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{ThreeDimensional Graphics}
\label{ugGraphThreeD}
%
The Axiom threedi\men\sion\al graphics package provides the ability to
\index{graphics!threedimensional}
%
\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 ThreeDimensional Functions of Two Variables}
\label{ugGraphThreeDPlot}
\index{surface!two variable function}
The simplest threedi\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 ThreeDimensional Parametric Space Curves}
\label{ugGraphThreeDParm}
A second kind of threedi\men\sion\al graph is a threedi\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 threedi\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 ThreeDimensional Parametric Surfaces}
\label{ugGraphThreeDPar}
\index{surface!parametric}
A third kind of threedi\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 threedi\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{ThreeDimensional 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 wiremesh 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 threespace 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 threespace object.
\spadcommand{s := create3Space()\$(ThreeSpace DFLOAT) }
$$
{3Space 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 threespace 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 threespace object can also be obtained from an existing threedi\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 threespace 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 threespace 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 threespace 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 threespace 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}
$$
{3Space 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}
$$
{3Space 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 ThreeDimensional Objects From Primitives}
\label{ugGraphThreeDBuild}
Rather than using the {\bf draw} and {\bf makeObject} commands,
\index{graphics!advanced!build 3D objects}
you can create threedi\men\sion\al graphs from primitives.
Operation \spadfunFrom{create3Space}{ThreeSpace} creates a
threespace 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 threespace object $space$.
\spadcommand{space := create3Space()\$(ThreeSpace DFLOAT) }
$$
{3Space 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] ]) }
$$
{3Space 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] ]) }
$$
{3Space 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] ]) }
$$
{3Space 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] ]) }
$$
{3Space 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] ]) }
$$
{3Space 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] ]) }
$$
{3Space 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] ]) }
$$
{3Space 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] ]) }
$$
{3Space 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 threedi\men\sion\al objects.
Again start with an empty threespace object.
\spadcommand{spaceC := create3Space()\$(ThreeSpace DFLOAT) }
$$
{3Space 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]) }
$$
{3Space with }1 \mbox{\rm component}
$$
\returnType{Type: ThreeSpace DoubleFloat}
\spadcommand{polygon(spaceC,[d,h,e,a]) }
$$
{3Space with }2 \mbox{\rm components}
$$
\returnType{Type: ThreeSpace DoubleFloat}
\spadcommand{polygon(spaceC,[c,d,a,b]) }
$$
{3Space with }3 \mbox{\rm components}
$$
\returnType{Type: ThreeSpace DoubleFloat}
\spadcommand{polygon(spaceC,[g,c,b,f]) }
$$
{3Space with }4 \mbox{\rm components}
$$
\returnType{Type: ThreeSpace DoubleFloat}
\spadcommand{polygon(spaceC,[h,g,f,e]) }
$$
{3Space with }5 \mbox{\rm components}
$$
\returnType{Type: ThreeSpace DoubleFloat}
\spadcommand{polygon(spaceC,[e,f,b,a]) }
$$
{3Space 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 zcoordinate.
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{ThreeDimensional Clipping}
\label{ugGraphClip}
A threedi\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{ThreeDimensional ControlPanel}
\label{ugGraphThreeDControl}
\index{graphics!3D controlpanel}
Once you have created a viewport, move your mouse to the viewport
and click with your left mouse button.
This displays a controlpanel 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{Threedimensional controlpanel.}
\end{figure}
\subsubsection{Transformations}
We recommend you first select the {\bf Bounds} button while
\index{graphics!3D controlpanel!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 controlpanel!rotate}
within the {\bf Rotate} window in the upper left corner of the
controlpanel.
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 controlpanel!scale}
within the {\bf Scale} window in the upper center of the
controlpanel, 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[nonuniform:] If any of the axes buttons are
not selected, nonuniform 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 controlpanel!translate}
{\bf Translate} window the direction you want the graph to move.
This window is located in the upper right corner of the
controlpanel 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 controlpanel!messages}
The window directly below the potentiometer windows for transformations is
used to display system messages relating to the viewport, the controlpanel
and the current graph displaying status.
\subsubsection{Colormap}
\index{graphics!3D controlpanel!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 controlpanel!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 controlpanel!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 controlpanel!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 controlpanel!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 controlpanel!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 controlpanel!bounds}
The region that encloses the entire volume of the viewport graph is displayed.
%
\item[Axes] displays Cartesian
\index{graphics!3D controlpanel!axes}
coordinate axes of the space, or turns them off if previously selected.
%
\item[Outline] causes
\index{graphics!3D controlpanel!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 viceversa.
\index{graphics!3D controlpanel!bw}
When this button is selected the
controlpanel 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 controlpanel described below.
%
\item[ViewVolume] takes you to another controlpanel as described below.
\index{graphics!3D controlpanel!save}
%
\item[Save] creates a menu of the possible file types that can
be written using the controlpanel.
The {\bf Exit} button leaves the save menu.
The {\bf Pixmap} button writes an Axiom pixmap of
\index{graphics!3D controlpanel!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 controlpanel!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 controlpanel!reset}
characteristics back to their initial states.
%
\item[Hide] causes the controlpanel for the
\index{graphics!3D controlpanel!hide}
corresponding viewport to disappear from the screen.
%
\item[Quit] queries whether the current viewport
\index{graphics!3D controlpanel!quit}
session should be terminated.
\end{description}
\subsubsection{Light}
\index{graphics!3D controlpanel!light}
%>>>\begin{figure}[htbp]
%>>>\begin{picture}(183,252)(125,0)
%>>>\special{psfile=ps/3Dlight.ps}
%>>>\end{picture}
%>>>\caption{ThreeDimensional Lighting Panel.}
%>>>\end{figure}
The {\bf Light} button changes the controlpanel into the
{\bf Lighting ControlPanel}. 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 controlpanel!move xy}
{\bf Lighting ControlPanel} 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 controlpanel!move z}
{\bf Lighting ControlPanel} title and in the center. This
changes the {\bf Z}
location of the light vector.
%
\item[Intensity:]
Below the {\bf Lighting ControlPanel} title
\index{graphics!3D controlpanel!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 controlpanel!view volume}
The {\bf View Volume} button changes the controlpanel 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{ThreeDimensional Volume Panel.}
%>>>\end{figure}
\begin{description}
\item[Eye Reference:] At the top of this panel is the
\index{graphics!3D controlpanel!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 controlpanel!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 controlpanel!perspective}
The {\bf Show Region} button indicates whether the clipping region
of the
\index{graphics!3D controlpanel!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 controlpanel!clipping on}
is drawn.
The left side of the {\bf Clip Volume} window shows the clipping
\index{graphics!3D controlpanel!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 ThreeDimensional Graphics}
\label{ugGraphThreeDops}
Here is a summary of useful Axiom operations for threedi\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!controlpanel}
controlpanel 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}
lefthand 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 threedi\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 threedi\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 threedi\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 lefthand 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}
lefthand corner of a twodi\men\sion\al viewport, relative to the display root
window (the upper lefthand 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 twodi\men\sion\al and threedi\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 threedi\men\sion\al viewport defaults, {\tt Axiom.2D.}
for twodi\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 controlpanel.
{\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 twodi\men\sion\al controlpanel.
{\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 threedi\men\sion\al viewport windows.
This is also used for twodi\men\sion\al controlpanels 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 controlpanel.
{\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 controlpanel 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 threedi\men\sion\al graphs,
in the lighting and viewingvolume controlpanel 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
twodi\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
threedi\men\sion\al controlpanel.
{\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 floatingpoint 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 floatingpoint numbers in which the exponent and the
\index{floatingpoint number}
significand may have any number of digits.
\index{number!floatingpoint}
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{floatingpoint number!complex}
the corresponding software implementations of complex floatingpoint numbers.
\index{complex!floatingpoint number}
In this section the term {\it floatingpoint type} means any of these
\index{number!complex floatingpoint}
four types.
%
The floatingpoint 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 floatingpoint type
\index{root!numeric approximation}
is real or complex: for the real floatingpoint 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 floatingpoint types, the principal value is returned.
\index{principal value}
Also, for real floatingpoint 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 floatingpoint 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 machineprecision
\index{special functions}
floatingpoint 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^{z1} 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^{u1} (1t)^{v1} 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 floatingpoint 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
floatingpoint 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{1t z}{12 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}{12 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}{1t}}}{1t} = \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{12 t z+t^2}} = \sum_{n=0}^{\infty} P_n (z) t^n.$$
These operations require nonnegative 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 numbertheoretic 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**5x**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**32) }
$$
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**24)/(y**24))}
$$
{{\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**24)/(y**24))}
$$
{{\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**2a1,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**52,e)}
$$
e
$$
\returnType{Type: Expression Integer}
\spadcommand{zeroOf(f**52,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 floatingpoint 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*x2*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 righthand 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
nontrivial 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 righthand 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 floatingpoint precision you get a floatingpoint result;
if you give the precision as a rational number you get a rational result.
\spadcommand{solve(x**32,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**32,.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**22*\%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 userspecified 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**219,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 floatingpoint 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 twosided 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
onesided limit. Also, if you have a function that is only defined on
one side of a particular value, \index{limit!onesided vs. twosided}
you can compute a onesided 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 ``righthand'' 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 twosided limit. Here the
limit from the left does not exist, as Axiom indicates when you try to
take a twosided 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
``lefthand'' and a ``righthand'' 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 nontrivial 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 toplevel
integration operation, \spadfunFrom{integrate}{FunctionSpaceIntegration},
for integrating realvalued 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 complexvalued 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 complexvalued
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 toplevel definite integration operation,
\spadfunFrom{integrate}{RationalFunctionDefiniteIntegration},
for integrating realvalued rational functions.
\spadcommand{integrate((x**4  3*x**2 + 6)/(x**65*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**22), 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**2a), 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**2a), 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 onevariable Taylor series
\index{series!Taylor} ({\tt UTS} is the abbreviation for
{\tt UnivariateTaylorSeries}) in the variable $z$ with {\tt FLOAT}
(that is, floatingpoint) coefficients, centered about $0.$ Then, by
assignment, we obtain the Taylor expansion of $exp(z)$ with
floatingpoint 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 serieseven 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)^{n1} \frac{(x  1)^n}{n}
\end{array}$$
If you were to evaluate the expression
$series(n +> (1)**(n1) / 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)**(n1)/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)**((n1)/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*n1)/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)**((n1)/2) * 2 * (2**n1) * 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(n1,(n1)/2)/(n*2**(n1)),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 termdifference 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 zeroequivalence 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{(n1)!}}x^{n1}$$.
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{(n1)!}}x^{n1} = {1\over{n!}}(B_n(x + 1)  B_n(x))$$
and, therefore,
$$x^{n1} = {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^{n1} & = & {1 \over n} (B_n(a + 1)  B_n(a)) \\
(a + 1)^{n1} & = & {1 \over n} (B_n(a + 2)  B_n(a + 1)) \\
(a + 2)^{n1} & = & {1 \over n} (B_n(a + 3)  B_n(a + 2)) \\
& \vdots & \\
(b  1)^{n1} & = & {1 \over n} (B_n(b)  B_n(b  1)) \\
b^{n1} & = & {1 \over n} (B_n(b + 1)  B_n(b))
\end{array}
$$
When we add these equations we find that the sum of the lefthand
sides is
$$\sum_{m=a}^{b} m^{n1},$$
the sum of the
$$(n1)^{\hbox{\small\rm st}}$$
powers from $a$ to $b$. The sum of the righthand 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 closedform and in series.
Axiom provides facilities for closedform solution of
\index{equation!differential!solving in closedform} single
differential equations of the following kinds:
\begin{itemize}
\item linear ordinary differential equations, and
\item nonlinear 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{ClosedForm 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 toplevel operation {\bf solve} for finding closedform
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 socalled {\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 closedform
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{ClosedForm Solutions of NonLinear Differential Equations}
\label{ugxProblemNLDEQClosed}
This is an example that shows how to solve a nonlinear 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: AddisonWesley 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 packagecall
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 packagecalling.
\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
packagecalling 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 $p1$.
\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 datatype 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 (onevariable)
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 $n1$ 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 groundfield 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^{n1}}$$
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 $n1$. 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, (AddisonWesley, 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. 217231.}
%
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 0dimensional ideals by ``generic''
projection on the last coordinate
\item a ``reduction process'' uses localization and ideal quotients
to reduce the general case to the 0dimensional 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**21] }
$$
\left[
{{x \sp 2}+{y \sp 2} 1}
\right]
$$
\returnType{Type: List
DistributedMultivariatePolynomial([x,y],Fraction Integer)}
\spadcommand{n := [x**2y**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 zerodimensional.
\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**21 }
$$
{x \sp 2} 1
$$
\returnType{Type: DistributedMultivariatePolynomial([x,y],Fraction Integer)}
\spadcommand{g := x*(x**21) }
$$
{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**2y*z,z**24] }
$$
\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(xy), 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(yx), y)$.
\spadcommand{q := resultant(eval(p,x,y),eval(p,x,yx),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 5fold 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}}} 
{{2375} \ {x \sp {12}}}+
{{90000} \ {x \sp {10}}} 
{{5000} \ {x \sp 8}}+
{{2700000} \ {x \sp 6}}+
\\
\\
\displaystyle
{{250000} \ {x \sp 4}}+
{{18000000} \ {x \sp 2}}+
{64000000}
\end{array}
$$
\returnType{Type: Union(Polynomial Integer,...)}
Factor the polynomial $q1$.
\spadcommand{factoredQ := factor q1 }
$$
\begin{array}{@{}l}
{\left(
{x \sp {10}} 
{{10} \ {x \sp 8}} 
{{75} \ {x \sp 6}}+
{{1500} \ {x \sp 4}} 
{{5500} \ {x \sp 2}}+
{16000}
\right)} *
\\
\\
\displaystyle
{\left(
{x \sp {10}}+
{{10} \ {x \sp 8}}+
{{125} \ {x \sp 6}}+
{{500} \ {x \sp 4}}+
{{2500} \ {x \sp 2}}+
{4000}
\right)}
\end{array}
$$
\returnType{Type: Factored Polynomial Integer}
We see that $q1$ has two irreducible factors, each of degree $10$.
(The fact that the polynomial $q1$ has two factors of degree $10$ is
enough to show that the Galois group of $p(x)$ is the dihedral group
of order $10$.\footnote{See McKay, Soicher, Computing Galois Groups
over the Rationals, Journal of Number Theory 20, 273281 (1983). We
do not assume the results of this paper, however, and we continue with
the computation.} Note that the type of $factoredQ$ is {\tt FR POLY
INT}, that is, {\tt Factored Polynomial Integer}. \index{Factored}
This is a special data type for recording factorizations of
polynomials with integer coefficients.
We can access the individual factors using the operation
\spadfunFrom{nthFactor}{Factored}.
\spadcommand{r := nthFactor(factoredQ,1) }
$$
{x \sp {10}} {{10} \ {x \sp 8}} {{75} \ {x \sp 6}}+{{1500} \ {x \sp 4}}
{{5500} \ {x \sp 2}}+{16000}
$$
\returnType{Type: Polynomial Integer}
Consider the polynomial $r = r(x)$. This is the minimal polynomial of
the difference of two roots of $p(x)$. Thus, the splitting field of
$p(x)$ contains a subfield of degree $10$. We show that this subfield
is, in fact, the splitting field of $p(x)$ by showing that $p(x)$
factors completely over this field.
First we create a symbolic root of the polynomial $r(x)$. (We
replaced $x$ by $b$ in the polynomial $r$ so that our symbolic root
would be printed as $b$.)
\spadcommand{beta:AN := rootOf(eval(r,x,b)) }
$$
b
$$
\returnType{Type: AlgebraicNumber}
We next tell Axiom to view $p(x)$ as a univariate polynomial in $x$
with algebraic number coefficients. This is accomplished with this
type declaration.
\spadcommand{p := p::UP(x,INT)::UP(x,AN) }
$$
{x \sp 5} {5 \ x}+{12}
$$
\returnType{Type: UnivariatePolynomial(x,AlgebraicNumber)}
Factor $p(x)$ over the field ${\bf Q}(\beta)$.
(This computation will take some time!)
\spadcommand{algFactors := factor(p,[beta]) }
$$
\begin{array}{@{}l}
{\left(
x+
{\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}} 
{{116} \ {b \sp 8}}+
{{780} \ {b \sp 7}}+
{{2640} \ {b \sp 6}}+
{{14895} \ {b \sp 5}} 
\\
\\
\displaystyle
{{8820} \ {b \sp 4}} 
{{127050} \ {b \sp 3}} 
{{327000} \ {b \sp 2}} 
{{405200} \ b}+
{2062400}
\end{array}
\right)
\over {1339200}}
\right)}
\\
\\
\displaystyle
{\left(
x+
{{{{17} \ {b \sp 8}}+
{{156} \ {b \sp 6}}+
{{2979} \ {b \sp 4}} 
{{25410} \ {b \sp 2}} 
{14080}} \over {66960}}
\right)}
\\
\\
\displaystyle
\ {\left(
x+
{{{{143} \ {b \sp 8}} 
{{2100} \ {b \sp 6}} 
{{10485} \ {b \sp 4}}+
{{290550} \ {b \sp 2}} 
{{334800} \ b} 
{960800}}
\over {669600}}
\right)}
\\
\\
\displaystyle
\ {\left(
x+
{{{{143} \ {b \sp 8}} 
{{2100} \ {b \sp 6}} 
{{10485} \ {b \sp 4}}+
{{290550} \ {b \sp 2}}+
{{334800} \ b} 
{960800}}
\over {669600}}
\right)}
\\
\\
\displaystyle
{\left(
x+
{\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}} 
{{116} \ {b \sp 8}} 
{{780} \ {b \sp 7}}+
{{2640} \ {b \sp 6}} 
{{14895} \ {b \sp 5}} 
\\
\\
\displaystyle
{{8820} \ {b \sp 4}}+
{{127050} \ {b \sp 3}} 
{{327000} \ {b \sp 2}}+
{{405200} \ b}+
{2062400}
\end{array}
\right)
\over {1339200}}
\right)}
\end{array}
$$
\returnType{Type: Factored UnivariatePolynomial(x,AlgebraicNumber)}
When factoring over number fields, it is important to specify the
field over which the polynomial is to be factored, as polynomials have
different factorizations over different fields. When you use the
operation {\bf factor}, the field over which the polynomial is
factored is the field generated by
\begin{enumerate}
\item the algebraic numbers that appear
in the coefficients of the polynomial, and
\item the algebraic numbers that
appear in a list passed as an optional second argument of the operation.
\end{enumerate}
In our case, the coefficients of $p$
are all rational integers and only $beta$
appears in the list, so the field is simply
${\bf Q}(\beta)$.
It was necessary to give the list $[beta]$ as a second argument of the
operation because otherwise the polynomial would have been factored
over the field generated by its coefficients, namely the rational
numbers.
\spadcommand{factor(p) }
$$
{x \sp 5} {5 \ x}+{12}
$$
\returnType{Type: Factored UnivariatePolynomial(x,AlgebraicNumber)}
We have shown that the splitting field of $p(x)$ has degree $10$.
Since the symmetric group of degree 5 has only one transitive subgroup
of order $10$, we know that the Galois group of $p(x)$ must be this
group, the dihedral group \index{group!dihedral} of order $10$.
Rather than stop here, we explicitly compute the action of the Galois
group on the roots of $p(x)$.
First we assign the roots of $p(x)$ as the values of five \index{root}
variables.
We can obtain an individual root by negating the constant coefficient of
one of the factors of $p(x)$.
\spadcommand{factor1 := nthFactor(algFactors,1) }
$$
x+
{
\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}} 
{{116} \ {b \sp 8}}+
{{780} \ {b \sp 7}}+
{{2640} \ {b \sp 6}}+
{{14895} \ {b \sp 5}} 
\\
\\
\displaystyle
{{8820} \ {b \sp 4}} 
{{127050} \ {b \sp 3}} 
{{327000} \ {b \sp 2}} 
{{405200} \ b}+
{2062400}
\end{array}
\right)
\over {1339200}}
$$
\returnType{Type: UnivariatePolynomial(x,AlgebraicNumber)}
\spadcommand{root1 := coefficient(factor1,0) }
$$
\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}}+
{{116} \ {b \sp 8}} 
{{780} \ {b \sp 7}} 
{{2640} \ {b \sp 6}} 
{{14895} \ {b \sp 5}}+
\\
\\
\displaystyle
{{8820} \ {b \sp 4}}+
{{127050} \ {b \sp 3}}+
{{327000} \ {b \sp 2}}+
{{405200} \ b} 
{2062400}
\end{array}
\right)
\over {1339200}
$$
\returnType{Type: AlgebraicNumber}
We can obtain a list of all the roots in this way.
\spadcommand{roots := [coefficient(nthFactor(algFactors,i),0) for i in 1..5] }
$$
\begin{array}{@{}l}
\left[
\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}}+
{{116} \ {b \sp 8}} 
{{780} \ {b \sp 7}} 
{{2640} \ {b \sp 6}} 
{{14895} \ {b \sp 5}}+
{{8820} \ {b \sp 4}}+
\\
\\
\displaystyle
{{127050} \ {b \sp 3}}+
{{327000} \ {b \sp 2}}+
{{405200} \ b} 
{2062400}
\end{array}
\right)
\over {1339200},
\right.
\\
\\
\displaystyle
{{{{17} \ {b \sp 8}} 
{{156} \ {b \sp 6}} 
{{2979} \ {b \sp 4}}+
{{25410} \ {b \sp 2}}+
{14080}}
\over {66960}},
\\
\\
\displaystyle
{{{{143} \ {b \sp 8}}+
{{2100} \ {b \sp 6}}+
{{10485} \ {b \sp 4}} 
{{290550} \ {b \sp 2}}+
{{334800} \ b}+
{960800}}
\over {669600}},
\\
\\
\displaystyle
{{{{143} \ {b \sp 8}}+
{{2100} \ {b \sp 6}}+
{{10485} \ {b \sp 4}} 
{{290550} \ {b \sp 2}} 
{{334800} \ b}+{960800}}
\over {669600}},
\\
\\
\displaystyle
\left.
\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}}+
{{116} \ {b \sp 8}}+
{{780} \ {b \sp 7}} 
{{2640} \ {b \sp 6}}+
{{14895} \ {b \sp 5}}+
{{8820} \ {b \sp 4}} 
\\
\\
\displaystyle
{{127050} \ {b \sp 3}}+
{{327000} \ {b \sp 2}}
{{405200} \ b} 
{2062400}
\end{array}
\right)
\over {1339200}
\right]
\end{array}
$$
\returnType{Type: List AlgebraicNumber}
The expression
\begin{verbatim}
 coefficient(nthFactor(algFactors, i), 0)}
\end{verbatim}
is the $i $th root of $p(x)$ and the elements of $roots$ are the
$i$th roots of $p(x)$ as $i$ ranges from $1$ to $5$.
Assign the roots as the values of the variables $a1,...,a5$.
\spadcommand{(a1,a2,a3,a4,a5) := (roots.1,roots.2,roots.3,roots.4,roots.5) }
$$
\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}}+
{{116} \ {b \sp 8}}+
{{780} \ {b \sp 7}} 
{{2640} \ {b \sp 6}}+
{{14895} \ {b \sp 5}}+
{{8820} \ {b \sp 4}} 
\\
\\
\displaystyle
{{127050} \ {b \sp 3}}+
{{327000} \ {b \sp 2}}
{{405200} \ b} 
{2062400}
\end{array}
\right)
\over {1339200}
$$
\returnType{Type: AlgebraicNumber}
Next we express the roots of $r(x)$ as polynomials in $beta$. We
could obtain these roots by calling the operation {\bf factor}:
$factor(r, [beta])$ factors $r(x)$ over ${\bf Q}(\beta)$. However,
this is a lengthy computation and we can obtain the roots of $r(x)$ as
differences of the roots $a1,...,a5$ of $p(x)$. Only ten of these
differences are roots of $r(x)$ and the other ten are roots of the
other irreducible factor of $q1$. We can determine if a given value
is a root of $r(x)$ by evaluating $r(x)$ at that particular value.
(Of course, the order in which factors are returned by the operation
{\bf factor} is unimportant and may change with different
implementations of the operation. Therefore, we cannot predict in
advance which differences are roots of $r(x)$ and which are not.)
Let's look at four examples (two are roots of $r(x)$ and
two are not).
\spadcommand{eval(r,x,a1  a2) }
$$
0
$$
\returnType{Type: Polynomial AlgebraicNumber}
\spadcommand{eval(r,x,a1  a3) }
$$
\left(
\begin{array}{@{}l}
{{47905} \ {b \sp 9}}+
{{66920} \ {b \sp 8}} 
{{536100} \ {b \sp 7}} 
{{980400} \ {b \sp 6}} 
{{3345075} \ {b \sp 5}} 
{{5787000} \ {b \sp 4}}+
\\
\\
\displaystyle
{{75572250} \ {b \sp 3}}+
{{161688000} \ {b \sp 2}} 
{{184600000} \ b} 
{710912000}
\end{array}
\right)
\over {4464}
$$
\returnType{Type: Polynomial AlgebraicNumber}
\spadcommand{eval(r,x,a1  a4) }
$$
0
$$
\returnType{Type: Polynomial AlgebraicNumber}
\spadcommand{eval(r,x,a1  a5) }
$$
{{{405} \ {b \sp 8}}+
{{3450} \ {b \sp 6}} 
{{19875} \ {b \sp 4}} 
{{198000} \ {b \sp 2}} 
{588000}}
\over {31}
$$
\returnType{Type: Polynomial AlgebraicNumber}
Take one of the differences that was a root of $r(x)$ and assign it to
the variable $bb$.
For example, if $eval(r,x,a1  a4)$ returned $0$, you would enter this.
\spadcommand{bb := a1  a4 }
$$
\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}}+
{{402} \ {b \sp 8}} 
{{780} \ {b \sp 7}} 
{{6840} \ {b \sp 6}} 
{{14895} \ {b \sp 5}} 
{{12150} \ {b \sp 4}}+
\\
\\
\displaystyle
{{127050} \ {b \sp 3}}+
{{908100} \ {b \sp 2}}+
{{1074800} \ b} 
{3984000}
\end{array}
\right)
\over {1339200}
$$
\returnType{Type: AlgebraicNumber}
Of course, if the difference is, in fact, equal to the root $beta$,
you should choose another root of $r(x)$.
Automorphisms of the splitting field are given by mapping a generator
of the field, namely $beta$, to other roots of its minimal polynomial.
Let's see what happens when $beta$ is mapped to $bb$.
We compute the images of the roots $a1,...,a5$ under this automorphism:
\spadcommand{aa1 := subst(a1,beta = bb) }
$$
{{{143} \ {b \sp 8}}+
{{2100} \ {b \sp 6}}+
{{10485} \ {b \sp 4}}
{{290550} \ {b \sp 2}}+
{{334800} \ b}+
{960800}}
\over {669600}
$$
\returnType{Type: AlgebraicNumber}
\spadcommand{aa2 := subst(a2,beta = bb) }
$$
\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}}+
{{116} \ {b \sp 8}}+
{{780} \ {b \sp 7}} 
{{2640} \ {b \sp 6}}+
{{14895} \ {b \sp 5}}+
{{8820} \ {b \sp 4}} 
\\
\\
\displaystyle
{{127050} \ {b \sp 3}}+
{{327000} \ {b \sp 2}} 
{{405200} \ b} 
{2062400}
\end{array}
\right)
\over {1339200}
$$
\returnType{Type: AlgebraicNumber}
\spadcommand{aa3 := subst(a3,beta = bb) }
$$
\left(
\begin{array}{@{}l}
{{85} \ {b \sp 9}}+
{{116} \ {b \sp 8}} 
{{780} \ {b \sp 7}} 
{{2640} \ {b \sp 6}} 
{{14895} \ {b \sp 5}}+
{{8820} \ {b \sp 4}}+
\\
\\
\displaystyle
{{127050} \ {b \sp 3}}+
{{327000} \ {b \sp 2}}+
{{405200} \ b} 
{2062400}
\end{array}
\right)
\over {1339200}
$$
\returnType{Type: AlgebraicNumber}
\spadcommand{aa4 := subst(a4,beta = bb) }
$$
{{{143} \ {b \sp 8}}+
{{2100} \ {b \sp 6}}+
{{10485} \ {b \sp 4}}
{{290550} \ {b \sp 2}} 
{{334800} \ b}+
{960800}}
\over {669600}
$$
\returnType{Type: AlgebraicNumber}
\spadcommand{aa5 := subst(a5,beta = bb) }
$$
{{{17} \ {b \sp 8}} 
{{156} \ {b \sp 6}} 
{{2979} \ {b \sp 4}}+
{{25410} \ {b \sp 2}}+
{14080}}
\over {66960}
$$
\returnType{Type: AlgebraicNumber}
Of course, the values $aa1,...,aa5$ are simply a permutation of the values
$a1,...,a5$.
Let's find the value of $aa1$ (execute as many of the following five commands
as necessary).
\spadcommand{(aa1 = a1) :: Boolean }
$$
{\tt false}
$$
\returnType{Type: Boolean}
\spadcommand{(aa1 = a2) :: Boolean }
$$
{\tt false}
$$
\returnType{Type: Boolean}
\spadcommand{(aa1 = a3) :: Boolean }
$$
{\tt true}
$$
\returnType{Type: Boolean}
\spadcommand{(aa1 = a4) :: Boolean }
$$
{\tt false}
$$
\returnType{Type: Boolean}
\spadcommand{(aa1 = a5) :: Boolean }
$$
{\tt false}
$$
\returnType{Type: Boolean}
Proceeding in this fashion, you can find the values of
$aa2,...aa5$. You have represented the automorphism $beta > bb$ as a
permutation of the roots $a1,...,a5$. If you wish, you can repeat
this computation for all the roots of $r(x)$ and represent the Galois
group of $p(x)$ as a subgroup of the symmetric group on five letters.
Here are two other problems that you may attack in a similar fashion:
\begin{enumerate}
\item Show that the Galois group of
$p(x) = x^4 + 2 x^3  2 x^2  3 x + 1$
is the dihedral group of order eight. \index{group!dihedral}
(The splitting field of this polynomial is the Hilbert class field
\index{Hilbert class field} of \index{field!Hilbert class} the quadratic field
${\bf Q}(\sqrt{145})$.)
\item Show that the Galois group of
$p(x) = x^6 + 108$
has order 6 and is isomorphic to $S_3,$ the symmetric group on three letters.
\index{group!symmetric} (The splitting field of this polynomial is the
splitting field of $x^3  2$.)
\end{enumerate}
\section{NonAssociative Algebras and Modelling Genetic Laws}
\label{ugProblemGenetic}
Many algebraic structures of mathematics and Axiom have a
multiplication operation {\tt *} that satisfies the associativity law
\index{associativity law} $a*(b*c) = (a*b)*c$ for all $a$, $b$ and
$c$. The octonions are a well known exception. There are many other
interesting nonassociative structures, such as the class of
\index{Lie algebra} Lie algebras.\footnote{Two Axiom implementations
of Lie algebras are {\tt LieSquareMatrix} and {\tt FreeNilpotentLie}.}
Lie algebras can be used, for example, to analyse Lie symmetry
algebras of \index{symmetry} partial differential \index{differential
equation!partial} equations. \index{partial differential equation} In
this section we show a different application of nonassociative
algebras, \index{nonassociative algebra} the modelling of genetic
laws. \index{algebra!nonassociative}
The Axiom library contains several constructors for creating
nonassoc\i\a\tive structures, ranging from the categories
{\tt Monad}, {\tt NonAssociativeRng}, and {\tt FramedNonAssociativeAlgebra},
to the domains {\tt AlgebraGivenByStructuralConstants} and
{\tt GenericNonAssociativeAlgebra}. Furthermore, the package
{\tt AlgebraPackage} provides operations for analysing the structure of
such algebras.\footnote{% The interested reader can learn more about
these aspects of the Axiom library from the paper ``Computations in
Algebras of Finite Rank,'' by Johannes Grabmeier and Robert Wisbauer,
Technical Report, IBM Heidelberg Scientific Center, 1992.}
Mendel's genetic laws are often written in a form like
$$Aa \times Aa = {1\over 4}AA + {1\over 2}Aa + {1\over 4}aa$$
The implementation of general algebras in Axiom allows us to
\index{Mendel's genetic laws} use this as the definition for
multiplication in an algebra. \index{genetics} Hence, it is possible
to study questions of genetic inheritance using Axiom. To demonstrate
this more precisely, we discuss one example from a monograph of
A. W\"orzBusekros, where you can also find a general setting of this
theory.\footnote{% W\"{o}rzBusekros, A., {\it Algebras in Genetics},
Springer Lectures Notes in Biomathematics 36, Berlin e.a. (1980). In
particular, see example 1.3.}
We assume that there is an infinitely large random mating population.
Random mating of two gametes $a_i$ and $a_j$ gives zygotes
\index{zygote} $a_ia_j$, which produce new gametes. \index{gamete} In
classical Mendelian segregation we have $a_ia_j = {1 \over 2}a_i+{1
\over 2}a_j$. In general, we have
$$a_ia_j = \sum_{k=1}^n \gamma_{i,j}^k\ a_k.$$
%{$ai aj = gammaij1 a1 + gammaij2 a2 + ... + gammaijn an$}
The segregation rates $\gamma_{i,j}$ are the structural constants of
an $n$dimensional algebra. This is provided in Axiom by the
constructor {\tt AlgebraGivenByStructuralConstants} (abbreviation
{\tt ALGSC}).
Consider two coupled autosomal loci with alleles $A$, $a$, $B$, and
$b$, building four different gametes $a_1 = AB, a_2 = Ab, a_3 = aB,$
and $a_4 = ab$ {$a1 := AB, a2 := Ab, a3 := aB,$ and $a4 := ab$}. The
zygotes $a_ia_j$ produce gametes $a_i$ and $a_j$ with classical
Mendelian segregation. Zygote $a_1a_4$ undergoes transition to
$a_2a_3$ and vice versa with probability
$0 \le \theta \le {1\over2}$.
Define a list $[(\gamma_{i,j}^k) 1 \le k \le 4]$ of four fourbyfour
matrices giving the segregation rates. We use the value $1/10$ for
$\theta$.
\spadcommand{segregationRates : List SquareMatrix(4,FRAC INT) := [matrix [ [1, 1/2, 1/2, 9/20], [1/2, 0, 1/20, 0], [1/2, 1/20, 0, 0], [9/20, 0, 0, 0] ], matrix [ [0, 1/2, 0, 1/20], [1/2, 1, 9/20, 1/2], [0, 9/20, 0, 0], [1/20, 1/2, 0, 0] ], matrix [ [0, 0, 1/2, 1/20], [0, 0, 9/20, 0], [1/2, 9/20, 1, 1/2], [1/20, 0, 1/2, 0] ], matrix [ [0, 0, 0, 9/20], [0, 0, 1/20, 1/2], [0, 1/20, 0, 1/2], [9/20, 1/2, 1/2, 1] ] ] }
$$
\begin{array}{@{}l}
\left[
{\left[
\begin{array}{cccc}
1 & {1 \over 2} & {1 \over 2} & {9 \over {20}} \\
{1 \over 2} & 0 & {1 \over {20}} & 0 \\
{1 \over 2} & {1 \over {20}} & 0 & 0 \\
{9 \over {20}} & 0 & 0 & 0
\end{array}
\right]},
{\left[
\begin{array}{cccc}
0 & {1 \over 2} & 0 & {1 \over {20}} \\
{1 \over 2} & 1 & {9 \over {20}} & {1 \over 2} \\
0 & {9 \over {20}} & 0 & 0 \\
{1 \over {20}} & {1 \over 2} & 0 & 0
\end{array}
\right]},
\right.
\\
\\
\displaystyle
\left.
{\left[
\begin{array}{cccc}
0 & 0 & {1 \over 2} & {1 \over {20}} \\
0 & 0 & {9 \over {20}} & 0 \\
{1 \over 2} & {9 \over {20}} & 1 & {1 \over 2} \\
{1 \over {20}} & 0 & {1 \over 2} & 0
\end{array}
\right]},
{\left[
\begin{array}{cccc}
0 & 0 & 0 & {9 \over {20}} \\
0 & 0 & {1 \over {20}} & {1 \over 2} \\
0 & {1 \over {20}} & 0 & {1 \over 2} \\
{9 \over {20}} & {1 \over 2} & {1 \over 2} & 1
\end{array}
\right]}
\right]
\end{array}
$$
\returnType{Type: List SquareMatrix(4,Fraction Integer)}
Choose the appropriate symbols for the basis of gametes,
\spadcommand{gametes := ['AB,'Ab,'aB,'ab] }
$$
\left[
AB, Ab, aB, ab
\right]
$$
\returnType{Type: List OrderedVariableList [AB,Ab,aB,ab]}
Define the algebra.
\spadcommand{A := ALGSC(FRAC INT, 4, gametes, segregationRates)}
$$
\begin{array}{@{}l}
{\rm AlgebraGivenByStructuralConstants(Fraction Integer, 4, }
\\
\displaystyle
{\rm [AB,Ab,aB,ab], [MATRIX,MATRIX,MATRIX,MATRIX])}
\end{array}
$$
\returnType{Type: Domain}
What are the probabilities for zygote $a_1a_4$ to produce the
different gametes?
\spadcommand{a := basis()\$A}
$$
\left[
AB, Ab, aB, ab
\right]
$$
\returnType{Type: Vector
AlgebraGivenByStructuralConstants(Fraction Integer,4,[AB,Ab,aB,ab],
[MATRIX,MATRIX,MATRIX,MATRIX])}
\spadcommand{a.1*a.4}
$$
{{9 \over {20}} \ ab}+
{{1 \over {20}} \ aB}+
{{1 \over {20}} \ Ab}+
{{9 \over {20}} \ AB}
$$
\returnType{Type:
AlgebraGivenByStructuralConstants(Fraction Integer,4,[AB,Ab,aB,ab],
[MATRIX,MATRIX,MATRIX,MATRIX])}
Elements in this algebra whose coefficients sum to one play a
distinguished role. They represent a population with the distribution
of gametes reflected by the coefficients with respect to the basis of
gametes.
Random mating of different populations $x$ and $y$ is described by
their product $x*y$.
This product is commutative only if the gametes are not sexdependent,
as in our example.
\spadcommand{commutative?()\$A }
$$
{\tt true}
$$
\returnType{Type: Boolean}
In general, it is not associative.
\spadcommand{associative?()\$A }
$$
{\tt false}
$$
\returnType{Type: Boolean}
Random mating within a population $x$ is described by $x*x$. The next
generation is $(x*x)*(x*x)$.
Use decimal numbers to compare the distributions more easily.
\spadcommand{x : ALGSC(DECIMAL, 4, gametes, segregationRates) := convert [3/10, 1/5, 1/10, 2/5]}
$$
{{0.4} \ ab}+{{0.1} \ aB}+{{0.2} \ Ab}+{{0.3} \ AB}
$$
\returnType{Type:
AlgebraGivenByStructuralConstants(DecimalExpansion,4,[AB,Ab,aB,ab],
[MATRIX,MATRIX,MATRIX,MATRIX])}
To compute directly the gametic distribution in the fifth generation,
we use {\bf plenaryPower}.
\spadcommand{plenaryPower(x,5) }
$$
{{0.{36561}} \ ab}+{{0.{13439}} \ aB}+{{0.{23439}} \ Ab}+{{0.{26561}} \
AB}
$$
\returnType{Type:
AlgebraGivenByStructuralConstants(DecimalExpansion,4,[AB,Ab,aB,ab],
[MATRIX,MATRIX,MATRIX,MATRIX])}
We now ask two questions: Does this distribution converge to an
equilibrium state? What are the distributions that are stable?
This is an invariant of the algebra and it is used to answer the first
question. The new indeterminates describe a symbolic distribution.
\spadcommand{q := leftRankPolynomial()\$GCNAALG(FRAC INT, 4, gametes, segregationRates) :: UP(Y, POLY FRAC INT)}
$$
\begin{array}{@{}l}
{Y \sp 3}+
{{\left(
{{{29} \over {20}} \ \%x4} 
{{{29} \over {20}} \ \%x3} 
{{{29} \over {20}} \ \%x2} 
{{{29} \over {20}} \ \%x1}
\right)}\ {Y \sp 2}}+
\\
\\
\displaystyle
{
\left(
\begin{array}{@{}l}
\left( {{9 \over {20}} \ { \%x4 \sp 2}}+
{{\left(
{{9 \over {10}} \ \%x3}+
{{9 \over {10}} \ \%x2}+
{{9 \over {10}} \ \%x1}
\right)}\ \%x4}+
\right.
\\
\\
\displaystyle
{{9 \over {20}} \ { \%x3 \sp 2}}+
{{\left( {{9 \over {10}} \ \%x2}+{{9 \over {10}} \ \%x1} \right)}\ \%x3}+
{{9 \over {20}} \ { \%x2 \sp 2}}+
\\
\\
\displaystyle
\left.
{{9 \over {10}} \ \%x1 \ \%x2}+
{{9 \over {20}} \ { \%x1 \sp 2}}
\right)
\end{array}
\right)
\ Y}
\end{array}
$$
\returnType{Type: UnivariatePolynomial(Y,Polynomial Fraction Integer)}
Because the coefficient ${9 \over 20}$ has absolute value less than 1,
all distributions do converge, by a theorem of this theory.
\spadcommand{factor(q :: POLY FRAC INT) }
$$
\begin{array}{@{}l}
{\left( Y  \%x4  \%x3  \%x2  \%x1 \right)} *
\\
\\
\displaystyle
{\left(
Y 
{{9 \over {20}} \ \%x4} 
{{9 \over {20}} \ \%x3} 
{{9 \over {20}} \ \%x2} 
{{9 \over {20}} \ \%x1}
\right)}
\ Y
\end{array}
$$
\returnType{Type: Factored Polynomial Fraction Integer}
The second question is answered by searching for idempotents in the algebra.
\spadcommand{cI := conditionsForIdempotents()\$GCNAALG(FRAC INT, 4, gametes, segregationRates) }
$$
\begin{array}{@{}l}
\left[
{{{9 \over {10}} \ \%x1 \ \%x4}+
{{\left( {{1 \over {10}} \ \%x2}+ \%x1 \right)}\ \%x3}+
{ \%x1 \ \%x2}+
{ \%x1 \sp 2} 
\%x1},
\right.
\\
\\
\displaystyle
{{{\left( \%x2+{{1 \over {10}} \ \%x1} \right)}\ \%x4}+
{{9 \over {10}} \ \%x2 \ \%x3}+
{ \%x2 \sp 2}+
{{\left( \%x1 1 \right)}\ \%x2}},
\\
\\
\displaystyle
{{{\left( \%x3+{{1 \over {10}} \ \%x1} \right)}\ \%x4}+
{ \%x3 \sp 2}+
{{\left( {{9 \over {10}} \ \%x2}+ \%x1 1 \right)}\ \%x3}},
\\
\\
\displaystyle
\left.
{{ \%x4 \sp 2}+
{{\left( \%x3+ \%x2+{{9 \over {10}} \ \%x1} 1 \right)}\ \%x4}+
{{1 \over {10}} \ \%x2 \ \%x3}}
\right]
\end{array}
$$
\returnType{Type: List Polynomial Fraction Integer}
Solve these equations and look at the first solution.
\spadcommand{gbs:= groebnerFactorize cI}
$$
\begin{array}{@{}l}
\left[
\begin{array}{@{}l}
\left[ { \%x4+ \%x3+ \%x2+ \%x1 1},
\right.
\\
\displaystyle
\left.
\ \ {{{\left( \%x2+ \%x1 \right)}\ \%x3}+
{ \%x1 \ \%x2}+{ \%x1 \sp 2}  \%x1}
\right],
\end{array}
\right.
\\
\\
\displaystyle
{\left[ 1 \right]},
{\left[ { \%x4+ \%x3 1}, \%x2, \%x1 \right]},
\\
\\
\displaystyle
{\left[ { \%x4+ \%x2 1}, \%x3, \%x1 \right]},
{\left[ \%x4, \%x3, \%x2, \%x1 \right]},
\\
\\
\displaystyle
\left.
{\left[ { \%x4 1}, \%x3, \%x2, \%x1 \right]},
{\left[ { \%x4 {1 \over 2}}, { \%x3 {1 \over 2}}, \%x2, \%x1 \right]}
\right]
\end{array}
$$
\returnType{Type: List List Polynomial Fraction Integer}
\spadcommand{gbs.1}
$$
\begin{array}{@{}l}
\left[
{ \%x4+ \%x3+ \%x2+ \%x1 1},
\right.
\\
\displaystyle
\left.
{{{\left( \%x2+ \%x1 \right)}\ \%x3}+{ \%x1 \ \%x2}+{ \%x1 \sp 2}  \%x1}
\right]
\end{array}
$$
\returnType{Type: List Polynomial Fraction Integer}
Further analysis using the package {\tt PolynomialIdeals} shows that
there is a twodimensional variety of equilibrium states and all other
solutions are contained in it.
Choose one equilibrium state by setting two indeterminates to concrete
values.
\spadcommand{sol := solve concat(gbs.1,[\%x11/10,\%x21/10]) }
$$
\left[
{\left[
{ \%x4={2 \over 5}},
{ \%x3={2 \over 5}},
{ \%x2={1 \over {10}}},
{ \%x1={1 \over {10}}}
\right]}
\right]
$$
\returnType{Type: List List Equation Fraction Polynomial Integer}
\spadcommand{e : A := represents reverse (map(rhs, sol.1) :: List FRAC INT) }
$$
{{2 \over 5} \ ab}+
{{2 \over 5} \ aB}+
{{1 \over {10}} \ Ab}+
{{1 \over {10}} \ AB}
$$
\returnType{Type:
AlgebraGivenByStructuralConstants(Fraction Integer,4,[AB,Ab,aB,ab],
[MATRIX,MATRIX,MATRIX,MATRIX])}
Verify the result.
\spadcommand{e*ee }
$$
0
$$
\returnType{Type:
AlgebraGivenByStructuralConstants(Fraction Integer,4,[AB,Ab,aB,ab],
[MATRIX,MATRIX,MATRIX,MATRIX])}
%\setcounter{chapter}{5} % Chapter 10
\setcounter{chapter}{5} % Appendix F
\chapter{Programs for AXIOM Images}
\label{ugAppGraphics}
%
This appendix contains the Axiom programs used to generate
the images in the gallery color insert of this book.
All these input files are included
with the Axiom system.
To produce the images
on page 6 of the gallery insert, for example, issue the command:
\begin{verbatim}
)read images6
\end{verbatim}
These images were produced on an IBM RS/6000 model 530 with a
standard color graphics adapter. The smooth shaded images
were made from X Window System screen dumps.
The remaining images were produced with Axiomgenerated
PostScript output. The images were reproduced from slides made on an Agfa
ChromaScript PostScript interpreter with a Matrix Instruments QCR camera.
\section{images1.input}
\label{ugFimagesOne}
\begin{verbatim}
)read tknot Read torus knot program
torusKnot(15,17, 0.1, 6, 700) A (15,17) torus knot
\end{verbatim}
\index{torus knot}
\newpage
\section{images2.input}
\label{ugFimagesTwo}
These images illustrate how Newton's method converges when computing the
\index{Newton iteration}
complex cube roots of 2. Each point in the $(x,y)$plane represents the
complex number $x + iy,$ which is given as a starting point for Newton's
method. The poles in these images represent bad starting values.
The flat areas are the regions of convergence to the three roots.
\begin{verbatim}
)read newton Read the programs from
)read vectors Chapter 10
f := newtonStep(x**3  2) Create a Newton's iteration
function for $x^3 = 2$
\end{verbatim}
The function $f^n$ computes $n$ steps of Newton's method.
\begin{verbatim}
clipValue := 4 Clip values with magnitude > 4
drawComplexVectorField(f**3, 3..3, 3..3) The vector field for $f^3$
drawComplex(f**3, 3..3, 3..3) The surface for $f^3$
drawComplex(f**4, 3..3, 3..3) The surface for $f^4$
\end{verbatim}
\section{images3.input}
\label{ugFimagesThree}
\begin{verbatim}
)r tknot
for i in 0..4 repeat torusKnot(2, 2 + i/4, 0.5, 25, 250)
\end{verbatim}
\section{images5.input}
\label{ugFimagesFive}
The parameterization of the Etruscan Venus is due to George Frances.
\index{Etruscan Venus}
\begin{verbatim}
venus(a,r,steps) ==
surf := (u:DFLOAT, v:DFLOAT): Point DFLOAT +>
cv := cos(v)
sv := sin(v)
cu := cos(u)
su := sin(u)
x := r * cos(2*u) * cv + sv * cu
y := r * sin(2*u) * cv  sv * su
z := a * cv
point [x,y,z]
draw(surf, 0..\%pi, \%pi..\%pi, var1Steps==steps,
var2Steps==steps, title == "Etruscan Venus")
venus(5/2, 13/10, 50) The Etruscan Venus
\end{verbatim}
The Figure8 Klein Bottle
\index{Klein bottle}
parameterization is from
``Differential Geometry and Computer Graphics'' by Thomas Banchoff,
in {\it Perspectives in Mathematics,} Anniversary of Oberwolfasch 1984,
Birkh\"{a}userVerlag, Basel, pp. 4360.
\begin{verbatim}
klein(x,y) ==
cx := cos(x)
cy := cos(y)
sx := sin(x)
sy := sin(y)
sx2 := sin(x/2)
cx2 := cos(x/2)
sq2 := sqrt(2.0@DFLOAT)
point [cx * (cx2 * (sq2 + cy) + (sx2 * sy * cy)), \_
sx * (cx2 * (sq2 + cy) + (sx2 * sy * cy)), \_
sx2 * (sq2 + cy) + cx2 * sy * cy]
draw(klein, 0..4*\%pi, 0..2*\%pi, var1Steps==50, Figure8 Klein bottle
var2Steps==50,title=="Figure Eight Klein Bottle")
\end{verbatim}
The next two images are examples of generalized tubes.
\begin{verbatim}
)read ntube
rotateBy(p, theta) == Rotate a point $p$ by
c := cos(theta) $\theta$ around the origin
s := sin(theta)
point [p.1*c  p.2*s, p.1*s + p.2*c]
bcircle t == A circle in threespace
point [3*cos t, 3*sin t, 0]
twist(u, t) == An ellipse that twists
theta := 4*t around four times as
p := point [sin u, cos(u)/2] $t$ revolves once
rotateBy(p, theta)
ntubeDrawOpt(bcircle, twist, 0..2*\%pi, 0..2*\%pi, Twisted Torus
var1Steps == 70, var2Steps == 250)
twist2(u, t) == Create a twisting circle
theta := t
p := point [sin u, cos(u)]
rotateBy(p, theta)
cf(u,v) == sin(21*u) Color function with $21$ stripes
ntubeDrawOpt(bcircle, twist2, 0..2*\%pi, 0..2*\%pi, Striped Torus
colorFunction == cf, var1Steps == 168,
var2Steps == 126)
\end{verbatim}
\section{images6.input}
\label{ugFimagesSix}
\begin{verbatim}
gam(x,y) == The height and color are the
g := Gamma complex(x,y) real and argument parts
point [x,y,max(min(real g, 4), 4), argument g] of the Gamma function,
respectively.
draw(gam, \%pi..\%pi, \%pi..\%pi, The Gamma Function
title == "Gamma(x + \%i*y)", \_
var1Steps == 100, var2Steps == 100)
b(x,y) == Beta(x,y)
draw(b, 3.1..3, 3.1 .. 3, title == "Beta(x,y)") The Beta Function
atf(x,y) ==
a := atan complex(x,y)
point [x,y,real a, argument a]
draw(atf, 3.0..\%pi, 3.0..\%pi) The Arctangent function
\end{verbatim}
\index{function!Gamma}
\index{function!Euler Beta}
\index{Euler!Beta function}
\section{images7.input}
\label{ugFimagesSeven}
First we look at the conformal
\index{conformal map}
map $z \mapsto z + 1/z$.
\begin{verbatim}
)read conformal Read program for drawing
conformal maps
f z == z The coordinate grid for the
complex plane
conformalDraw(f, 2..2, 2..2, 9, 9, "cartesian") Mapping 1: Source
f z == z + 1/z The map $z \mapsto z + 1/z$
conformalDraw(f, 2..2, 2..2, 9, 9, "cartesian") Mapping 1: Target
\end{verbatim}
The map $z \mapsto (z+1)/(z1)$ maps
the unit disk to the right halfplane, as shown
\index{Riemann!sphere}
on the Riemann sphere.
\begin{verbatim}
f z == z The unit disk
riemannConformalDraw(f,0.1..0.99,0..2*\%pi,7,11,"polar") Mapping 2: Source
f z == (z+1)/(z1) The map $x \mapsto (z+1)/(z1)$
riemannConformalDraw(f,0.1..0.99,0..2*\%pi,7,11,"polar") Mapping 2: Target
riemannSphereDraw(4..4, 4..4, 7, 7, "cartesian") Riemann Sphere Mapping
\end{verbatim}
\section{images8.input}
\label{ugFimagesEight}
\begin{verbatim}
)read dhtri
)read tetra
drawPyramid 4 Sierpinsky's Tetrahedron
Sierpinsky's Tetrahedron
)read antoine
drawRings 2 Antoine's Necklace
Aintoine's Necklace
)read scherk
drawScherk(3,3) Scherk's Minimal Surface
)read ribbonsNew
drawRibbons([x**i for i in 1..5], x=1..1, y=0..2) Ribbon Plot
\end{verbatim}
\index{Scherk's minimal surface}
%\input{gallery/conformal.htex}
\section{conformal.input}
\label{ugFconformal}
%
The functions in this section draw conformal maps both on the
\index{conformal map}
plane and on the Riemann sphere.
\index{Riemann!sphere}
% Compile, don't interpret functions.
%\xmpLine{)set fun comp on}{}
\begin{verbatim}
C := Complex DoubleFloat Complex Numbers
S := Segment DoubleFloat Draw ranges
R3 := Point DFLOAT Points in 3space
\end{verbatim}
{\bf conformalDraw}{\it (f, rRange, tRange, rSteps, tSteps, coord)}
draws the image of the coordinate grid under {\it f} in the complex plane.
The grid may be given in either polar or Cartesian coordinates.
Argument {\it f} is the function to draw;
{\it rRange} is the range of the radius (in polar) or real (in Cartesian);
{\it tRange} is the range of $\theta$ (in polar) or imaginary (in Cartesian);
{\it tSteps, rSteps}, are the number of intervals in the {\it r} and
$\theta$ directions; and
{\it coord} is the coordinate system to use (either {\tt "polar"} or
{\tt "cartesian"}).
\begin{verbatim}
conformalDraw: (C > C, S, S, PI, PI, String) > VIEW3D
conformalDraw(f,rRange,tRange,rSteps,tSteps,coord) ==
transformC := Function for changing an $(x,y)$
coord = "polar" => polar2Complex pair into a complex number
cartesian2Complex
cm := makeConformalMap(f, transformC)
sp := createThreeSpace() Create a fresh space
adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) Plot the coordinate lines
makeViewport3D(sp, "Conformal Map") Draw the image
\end{verbatim}
{\bf riemannConformalDraw}{\it (f, rRange, tRange, rSteps, tSteps, coord)}
draws the image of the coordinate grid under {\it f} on the Riemann sphere.
The grid may be given in either polar or Cartesian coordinates.
Its arguments are the same as those for {\bf conformalDraw}.
\begin{verbatim}
riemannConformalDraw:(C>C,S,S,PI,PI,String)>VIEW3D
riemannConformalDraw(f, rRange, tRange,
rSteps, tSteps, coord) ==
transformC := Function for changing an $(x,y)$
coord = "polar" => polar2Complex pair into a complex number
cartesian2Complex
sp := createThreeSpace() Create a fresh space
cm := makeRiemannConformalMap(f, transformC)
adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) Plot the coordinate lines
curve(sp,[point [0,0,2.0@DFLOAT,0],point [0,0,2.0@DFLOAT,0] ])
Add an invisible point at
makeViewport3D(sp,"Map on the Riemann Sphere") the north pole for scaling
adaptGrid(sp, f, uRange, vRange, uSteps, vSteps) == Plot the coordinate grid
delU := (hi(uRange)  lo(uRange))/uSteps using adaptive plotting for
delV := (hi(vRange)  lo(vRange))/vSteps coordinate lines, and draw
uSteps := uSteps + 1; vSteps := vSteps + 1 tubes around the lines
u := lo uRange
for i in 1..uSteps repeat Draw coordinate lines in the $v$
c := curryLeft(f,u) direction; curve $c$ fixes the
cf := (t:DFLOAT):DFLOAT +> 0 current value of $u$
makeObject(c,vRange::SEG Float,colorFunction==cf,
Draw the $v$ coordinate line
space == sp, tubeRadius == .02, tubePoints == 6)
u := u + delU
v := lo vRange
for i in 1..vSteps repeat Draw coodinate lines in the $u$
c := curryRight(f,v) direction; curve $c$ fixes the
cf := (t:DFLOAT):DFLOAT +> 1 current value of $v$
makeObject(c,uRange::SEG Float,colorFunction==cf,
Draw the $u$ coordinate line
space == sp, tubeRadius == .02, tubePoints == 6)
v := v + delV
void()
riemannTransform(z) == Map a point in the complex
r := sqrt norm z plane to the Riemann sphere
cosTheta := (real z)/r
sinTheta := (imag z)/r
cp := 4*r/(4+r**2)
sp := sqrt(1cp*cp)
if r>2 then sp := sp
point [cosTheta*cp, sinTheta*cp, sp + 1]
cartesian2Complex(r:DFLOAT, i:DFLOAT):C == Convert Cartesian coordinates to
complex(r, i) complex Cartesian form
polar2Complex(r:DFLOAT, th:DFLOAT):C == Convert polar coordinates to
complex(r*cos(th), r*sin(th)) complex Cartesian form
makeConformalMap(f, transformC) == Convert complex function $f$
(u:DFLOAT,v:DFLOAT):R3 +> to a mapping:
(DFLOAT,DFLOAT) $mapsto$ R3
z := f transformC(u, v) in the complex plane
point [real z, imag z, 0.0@DFLOAT]
makeRiemannConformalMap(f, transformC) == Convert a complex function $f$
(u:DFLOAT, v:DFLOAT):R3 +> to a mapping:
(DFLOAT,DFLOAT) $\mapsto$ R3
riemannTransform f transformC(u, v) on the Riemann sphere
riemannSphereDraw: (S, S, PI, PI, String) > VIEW3D
Draw a picture of the mapping
of the complex plane to
the Riemann sphere
riemannSphereDraw(rRange,tRange,rSteps,tSteps,coord) ==
transformC :=
coord = "polar" => polar2Complex
cartesian2Complex
grid := (u:DFLOAT, v:DFLOAT): R3 +> Coordinate grid function
z1 := transformC(u, v)
point [real z1, imag z1, 0]
sp := createThreeSpace() Create a fresh space
adaptGrid(sp, grid, rRange, tRange, rSteps, tSteps) Draw the flat grid
connectingLines(sp,grid,rRange,tRange,rSteps,tSteps)
makeObject(riemannSphere,0..2*\%pi,0..\%pi,space==sp) Draw the sphere
f := (z:C):C +> z
cm := makeRiemannConformalMap(f, transformC)
adaptGrid(sp, cm, rRange, tRange, rSteps, tSteps) Draw the sphere grid
makeViewport3D(sp, "Riemann Sphere")
connectingLines(sp,f,uRange,vRange,uSteps,vSteps) ==
Draw the lines that connect
delU := (hi(uRange)  lo(uRange))/uSteps the points in the complex
delV := (hi(vRange)  lo(vRange))/vSteps plane to the north pole
uSteps := uSteps + 1; vSteps := vSteps + 1 of the Riemann sphere
u := lo uRange
for i in 1..uSteps repeat For each u
v := lo vRange
for j in 1..vSteps repeat For each v
p1 := f(u,v)
p2 := riemannTransform complex(p1.1, p1.2) Project p1 onto the sphere
fun := lineFromTo(p1,p2) Create a line function
cf := (t:DFLOAT):DFLOAT +> 3
makeObject(fun, 0..1,space==sp,tubePoints==4, Draw the connecting line
tubeRadius==0.01,colorFunction==cf)
v := v + delV
u := u + delU
void()
riemannSphere(u,v) == A sphere sitting on the
sv := sin(v) complex plane, with radius 1
0.99@DFLOAT*(point [cos(u)*sv,sin(u)*sv,cos(v),0.0@DFLOAT])+
point [0.0@DFLOAT, 0.0@DFLOAT, 1.0@DFLOAT, 4.0@DFLOAT]
lineFromTo(p1, p2) == Create a line function
d := p2  p1 that goes from p1 to p2
(t:DFLOAT):Point DFLOAT +>
p1 + t*d
\end{verbatim}
%\input{gallery/tknot.htex}
\section{tknot.input}
\label{ugFtknot}
%
Create a $(p,q)$ torusknot with radius $r$ around the curve.
The formula was derived by Larry Lambe.
\begin{verbatim}
)read ntube
torusKnot: (DFLOAT, DFLOAT, DFLOAT, PI, PI) > VIEW3D
torusKnot(p, q ,r, uSteps, tSteps) ==
knot := (t:DFLOAT):Point DFLOAT +> Function for the torus knot
fac := 4/(2.2@DFLOATsin(q*t))
fac * point [cos(p*t), sin(p*t), cos(q*t)]
circle := (u:DFLOAT, t:DFLOAT): Point DFLOAT +> The cross section
r * point [cos u, sin u]
ntubeDrawOpt(knot, circle, 0..2*\%pi, 0..2*\%pi,
Draw the circle around the knot
var1Steps == uSteps, var2Steps == tSteps)
\end{verbatim}
%\input{gallery/ntube.htex}
\section{ntube.input}
\label{ugFntube}
%
The functions in this file create generalized tubes (also known as generalized
cylinders).
These functions draw a 2d curve in the normal
planes around a 3d curve.
\begin{verbatim}
R3 := Point DFLOAT Points in 3Space
R2 := Point DFLOAT Points in 2Space
S := Segment Float Draw ranges
Introduce types for functions for:
ThreeCurve := DFLOAT > R3 the space curve function
TwoCurve := (DFLOAT, DFLOAT) > R2 the plane curve function
Surface := (DFLOAT, DFLOAT) > R3 the surface function
Frenet frames define a
FrenetFrame := coordinate system around a
Record(value:R3,tangent:R3,normal:R3,binormal:R3)
point on a space curve
frame: FrenetFrame The current Frenet frame
for a point on a curve
\end{verbatim}
{\bf ntubeDraw}{\it (spaceCurve, planeCurve,}
$u_0 .. u_1,$ $t_0 .. t_1)$
draws {\it planeCurve} in the normal planes of {\it spaceCurve.}
The parameter $u_0 .. u_1$ specifies
the parameter range for {\it planeCurve}
and $t_0 .. t_1$ specifies the parameter range for {\it spaceCurve}.
Additionally, the plane curve function takes
a second parameter: the current parameter of {\it spaceCurve}.
This allows the plane curve to change shape
as it goes around the space curve.
See \ref{ugFimagesFive} for an example of this.
%
\begin{verbatim}
ntubeDraw: (ThreeCurve,TwoCurve,S,S) > VIEW3D
ntubeDraw(spaceCurve,planeCurve,uRange,tRange) ==
ntubeDrawOpt(spaceCurve, planeCurve, uRange, \_
tRange, []\$List DROPT)
ntubeDrawOpt: (ThreeCurve,TwoCurve,S,S,List DROPT)
> VIEW3D
ntubeDrawOpt(spaceCurve,planeCurve,uRange,tRange,l) ==
This function is similar
to ntubeDraw, but takes
delT:DFLOAT := (hi(tRange)  lo(tRange))/10000 optional parameters that it
oldT:DFLOAT := lo(tRange)  1 passes to the draw command
fun := ngeneralTube(spaceCurve,planeCurve,delT,oldT)
draw(fun, uRange, tRange, l)
\end{verbatim}
{\bf nfrenetFrame}{\it (c, t, delT)}
numerically computes the Frenet frame
about the curve {\it c} at {\it t}.
Parameter {\it delT} is a small number used to
compute derivatives.
\begin{verbatim}
nfrenetFrame(c, t, delT) ==
f0 := c(t)
f1 := c(t+delT)
t0 := f1  f0 The tangent
n0 := f1 + f0
b := cross(t0, n0) The binormal
n := cross(b,t0) The normal
ln := length n
lb := length b
ln = 0 or lb = 0 =>
error "Frenet Frame not well defined"
n := (1/ln)*n Make into unit length vectors
b := (1/lb)*b
[f0, t0, n, b]\$FrenetFrame
\end{verbatim}
{\bf ngeneralTube}{\it (spaceCurve, planeCurve,}{\it delT, oltT)}
creates a function that can be passed to the system axiomFun{draw} command.
The function is a parameterized surface for the general tube
around {\it spaceCurve}. {\it delT} is a small number used to compute
derivatives. {\it oldT} is used to hold the current value of the
{\it t} parameter for {\it spaceCurve.} This is an efficiency measure
to ensure that frames are only computed once for each value of {\it t}.
\begin{verbatim}
ngeneralTube: (ThreeCurve, TwoCurve, DFLOAT, DFLOAT) > Surface
ngeneralTube(spaceCurve, planeCurve, delT, oldT) ==
free frame Indicate that $frame$ is global
(v:DFLOAT, t: DFLOAT): R3 +>
if (t $\sim$= oldT) then If not already computed
frame := nfrenetFrame(spaceCurve, t, delT) compute new frame
oldT := t
p := planeCurve(v, t)
frame.value + p.1*frame.normal + p.2*frame.binormal
Project $p$ into the normal plane
\end{verbatim}
%\input{gallery/dhtri.htex}
\section{dhtri.input}
\label{ugFdhtri}
%
Create affine transformations (DH matrices) that transform
a given triangle into another.
\begin{verbatim}
tri2tri: (List Point DFLOAT, List Point DFLOAT) > DHMATRIX(DFLOAT)
Compute a DHMATRIX that
tri2tri(t1, t2) == transforms $t1$ to $t2,$ where
n1 := triangleNormal(t1) $t1$ and $t2$ are the vertices
n2 := triangleNormal(t2) of two triangles in 3space
tet2tet(concat(t1, n1), concat(t2, n2))
tet2tet: (List Point DFLOAT, List Point DFLOAT) > DHMATRIX(DFLOAT)
Compute a DHMATRIX that
tet2tet(t1, t2) == transforms $t1$ to $t2,$
m1 := makeColumnMatrix t1 where $t1$ and $t2$ are the
m2 := makeColumnMatrix t2 vertices of two tetrahedrons
m2 * inverse(m1) in 3space
makeColumnMatrix(t) == Put the vertices of a tetra
m := new(4,4,0)\$DHMATRIX(DFLOAT) hedron into matrix form
for x in t for i in 1..repeat
for j in 1..3 repeat
m(j,i) := x.j
m(4,i) := 1
m
triangleNormal(t) == Compute a vector normal to
a := triangleArea t the given triangle, whose
p1 := t.2  t.1 length is the square root
p2 := t.3  t.2 of the area of the triangle
c := cross(p1, p2)
len := length(c)
len = 0 => error "degenerate triangle!"
c := (1/len)*c
t.1 + sqrt(a) * c
triangleArea t == Compute the area of a
a := length(t.2  t.1) triangle using Heron's
b := length(t.3  t.2) formula
c := length(t.1  t.3)
s := (a+b+c)/2
sqrt(s*(sa)*(sb)*(sc))
\end{verbatim}
\section{tetra.input}
\label{ugFtetra}
%
%\input{gallery/tetra.htex}
%\outdent{Sierpinsky's Tetrahedron}
\begin{verbatim}
)set expose add con DenavitHartenbergMatrix Bring DH matrices into the
environment
x1:DFLOAT := sqrt(2.0@DFLOAT/3.0@DFLOAT) Set up the coordinates of the
x2:DFLOAT := sqrt(3.0@DFLOAT)/6 corners of the tetrahedron.
p1 := point [0.5@DFLOAT, x2, 0.0@DFLOAT] Some needed points
p2 := point [0.5@DFLOAT, x2, 0.0@DFLOAT]
p3 := point [0.0@DFLOAT, 2*x2, 0.0@DFLOAT]
p4 := point [0.0@DFLOAT, 0.0@DFLOAT, x1]
baseTriangle := [p2, p1, p3] The base of the tetrahedron
mt := [0.5@DFLOAT*(p2+p1), 0.5@DFLOAT*(p1+p3), 0.5@DFLOAT*(p3+p2)]
The middle triangle inscribed
in the base of the tetrahedron
bt1 := [mt.1, p1, mt.2] The bases of the triangles of
bt2 := [p2, mt.1, mt.3] the subdivided tetrahedron
bt3 := [mt.2, p3, mt.3]
bt4 := [0.5@DFLOAT*(p2+p4), 0.5@DFLOAT*(p1+p4), 0.5@DFLOAT*(p3+p4)]
tt1 := tri2tri(baseTriangle, bt1) Create the transformations
tt2 := tri2tri(baseTriangle, bt2) that bring the base of the
tt3 := tri2tri(baseTriangle, bt3) tetrahedron to the bases of
tt4 := tri2tri(baseTriangle, bt4) the subdivided tetrahedron
drawPyramid(n) == Draw a Sierpinsky tetrahedron
s := createThreeSpace() with $n$ levels of recursive
dh := rotatex(0.0@DFLOAT) subdivision
drawPyramidInner(s, n, dh)
makeViewport3D(s, "Sierpinsky Tetrahedron")
drawPyramidInner(s, n, dh) == Recursively draw a Sierpinsky
n = 0 => makeTetrahedron(s, dh, n) tetrahedron
drawPyramidInner(s, n1, dh * tt1) Draw the 4 recursive pyramids
drawPyramidInner(s, n1, dh * tt2)
drawPyramidInner(s, n1, dh * tt3)
drawPyramidInner(s, n1, dh * tt4)
makeTetrahedron(sp, dh, color) == Draw a tetrahedron into the
w1 := dh*p1 given space with the given
w2 := dh*p2 color, transforming it by
w3 := dh*p3 the given DH matrix
w4 := dh*p4
polygon(sp, [w1, w2, w4])
polygon(sp, [w1, w3, w4])
polygon(sp, [w2, w3, w4])
void()
\end{verbatim}
\index{Sierpinsky's Tetrahedron}
%\input{gallery/antoine.htex}
\section{antoine.input}
\label{ugFantoine}
%
Draw Antoine's Necklace.
\index{Antoine's Necklace}
Thank you to Matthew Grayson at IBM's T.J Watson Research Center for the idea.
\begin{verbatim}
)set expose add con DenavitHartenbergMatrix Bring DH matrices into
the environment
torusRot: DHMATRIX(DFLOAT) The transformation for
drawing a sub ring
drawRings(n) == Draw Antoine's Necklace with $n$
s := createThreeSpace() levels of recursive subdivision
dh:DHMATRIX(DFLOAT) := identity() The number of subrings is $10^n$
drawRingsInner(s, n, dh) Do the real work
makeViewport3D(s, "Antoine's Necklace")
\end{verbatim}
In order to draw Antoine rings, we take one ring, scale it down to
a smaller size, rotate it around its central axis, translate it
to the edge of the larger ring and rotate it around the edge to
a point corresponding to its count (there are 10 positions around
the edge of the larger ring). For each of these new rings we
recursively perform the operations, each ring becoming 10 smaller
rings. Notice how the {\bf DHMATRIX} operations are used to build up
the proper matrix composing all these transformations.
\begin{verbatim}
drawRingsInner(s, n, dh) == Recursively draw Antoine's
n = 0 => Necklace
drawRing(s, dh)
void()
t := 0.0@DFLOAT Angle around ring
p := 0.0@DFLOAT Angle of subring from plane
tr := 1.0@DFLOAT Amount to translate subring
inc := 0.1@DFLOAT The translation increment
for i in 1..10 repeat Subdivide into 10 linked rings
tr := tr + inc
inc := inc
dh' := dh*rotatez(t)*translate(tr,0.0@DFLOAT,0.0@DFLOAT)*
Transform ring in center
to a link
rotatey(p)*scale(0.35@DFLOAT, 0.48@DFLOAT, 0.4@DFLOAT)
drawRingsInner(s, n1, dh')
t := t + 36.0@DFLOAT
p := p + 90.0@DFLOAT
void()
drawRing(s, dh) == Draw a single ring into
free torusRot the given subspace,
torusRot := dh transformed by the given
DHMATRIX
makeObject(torus, 0..2*\%pi, 0..2*\%pi, var1Steps == 6,
space == s, var2Steps == 15)
torus(u ,v) == Parameterization of a torus,
cu := cos(u)/6 transformed by the
DHMATRIX in $torusRot.$
torusRot*point [(1+cu)*cos(v),(1+cu)*sin(v),(sin u)/6]
\end{verbatim}
%\input{gallery/scherk.htex}
\section{scherk.input}
\label{ugFscherk}
%
Scherk's minimal surface, defined by:
\index{Scherk's minimal surface}
$e^z \cos(x) = \cos(y)$.
See: {\it A Comprehensive Introduction to Differential Geometry,} Vol. 3,
by Michael Spivak, Publish Or Perish, Berkeley, 1979, pp. 249252.
\begin{verbatim}
(xOffset, yOffset):DFLOAT Offsets for a single piece
of Scherk's minimal surface
drawScherk(m,n) == Draw Scherk's minimal surface
free xOffset, yOffset on an $m$ by $n$ patch
space := createThreeSpace()
for i in 0..m1 repeat
xOffset := i*\%pi
for j in 0 .. n1 repeat
rem(i+j, 2) = 0 => 'iter Draw only odd patches
yOffset := j*\%pi
drawOneScherk(space) Draw a patch
makeViewport3D(space, "Scherk's Minimal Surface")
scherk1(u,v) == The first patch that makes
x := cos(u)/exp(v) up a single piece of
point [xOffset + acos(x), yOffset + u, v, abs(v)] Scherk's minimal surface
scherk2(u,v) == The second patch
x := cos(u)/exp(v)
point [xOffset  acos(x), yOffset + u, v, abs(v)]
scherk3(u,v) == The third patch
x := exp(v) * cos(u)
point [xOffset + u, yOffset + acos(x), v, abs(v)]
scherk4(u,v) == The fourth patch
x := exp(v) * cos(u)
point [xOffset + u, yOffset  acos(x), v, abs(v)]
drawOneScherk(s) == Draw the surface by
breaking it into four
patches and then drawing
the patches
makeObject(scherk1,\%pi/2..\%pi/2,0..\%pi/2,space==s,
var1Steps == 28, var2Steps == 28)
makeObject(scherk2,\%pi/2..\%pi/2,0..\%pi/2,space==s,
var1Steps == 28, var2Steps == 28)
makeObject(scherk3,\%pi/2..\%pi/2,\%pi/2..0,space==s,
var1Steps == 28, var2Steps == 28)
makeObject(scherk4,\%pi/2..\%pi/2,\%pi/2..0,space==s,
var1Steps == 28, var2Steps == 28)
void()
\end{verbatim}
\chapter{IDEAS TO BE INTEGRATED}
\section{email 1}
\begin{verbatim}
Re: [Axiomdeveloper] Axiom domains and Aldor return types
From: William Sit
Subject: Re: [Axiomdeveloper] Axiom domains and Aldor return types
Date: Mon, 17 Jan 2005 00:56:39 0500
Steve:
Stephen Wilson wrote:
> First, let me thank you for your analysis! I am finding the questions
> raised here very interesting. But I'm still on the other side of the
> fence for the moment :)
I have no problem with that :) If you read my toss and turn part, I know what
your reasons are and certainly respect that point of view as well. In some
sense, I am playing devil's advocate.
> > (I) The algorithm, which is really for S, is now an algorithm for R.
> > It hides the existence of S completely. It also hides the relevance
> > of p:P.
>
> The algorithm never needs to know S explicitly. If anything, the
> algorithm involves `something' with satisfies C(R,p). However, the
> meaning of a call to bar(p:R, ...)$Foo will in general carry a level
> of meaning all its own, which need not communicate a dependence on S
> (or C(R,p)). I dont see how this level of semantics involves the
> problems we are discussing.
On the contrary, it has a lot to do! Let me recap your Foo package here for
discussion:

Foo(R: ModularComputation): with { ... } == add {
bar(r: R, p:R): R == {
elem : ResidueClassRing(R, p) :=
modularRep(r)$residueClassRing(p)
 hairy computation...
canonicalPreImage(elem)
} }

Two comments: (1) Axiom can also hide S as you prefer:
Foo(R,p): T == C where
R: ModularCategory
p: Ideal(R)
Q ==> any domain constructed from R, p
T == with
bar: R > Q
C == add
S:= SomeConstructionForResidueClassRing(R,p)
import S
bar(r)==
elem:S:=modularRep(r)$S
 hairy computations
q:Q:= ...
Calling sequence in some other package, assuming R, p are already
defined:
bar(r)$Foo(R,p)
But notice that in such case, S is fixed (hardwired), much like your
residueClassRing(p) is fixed because of encapsulation in ModularComputation. The
original way, with S as a parameter, allows easy changes of representation of S
(hey, except for signature, bar(r)$Foo(R,p,S) is really a function of 4
parameters). The Aldor way would need to replace R by R1, which is another
wrapper around the base ring R. On the other hand, the original way, Q can
depend on S and now it cannot. If Aldor allows signatures like:
bar:(r:R, p:Ideal(R)) > BAE(R, p, residueClassRing(p))
that would be more general. But I worry about the efficiency here: each
evaluation of bar would require a new instantiation of
residueClassRing(p) even if p is fixed! I doubt very much the compiler will
optimize the code for this special, but perhaps common situation. In the Axiom
version, because bar does not depend on p (or rather p is fixed with respect to
bar), only one instantiation will be done.
In a recent message,
[Axiomdeveloper] A terrible bug: romberg+simplify/expand: slowdown of
125/300 times
Vladimir gave an example where Axiom does repeatedly invoke a map function from
EF for each of the 2049 evaluations of the function in:
romberg(z+>simplify(%i^2), 0, 1, 0.1, 0.1, 10, 12)
(use ")set mess bot on" to see the 2049 selections pass you by), even after the
function z+>simplify(%i^2) is compiled as in
g: (Complex Integer, Integer)>Integer
The interpreter somehow invokes a lift from Complex Integer>Integer
to work over EXPR COMPLEX INT > EXPR INT simply because %i was used.
But I agree that if you want to hide p, then Axiom cannot handle this because
the signature for bar would not be available.
(2) If you push your argument further, we can say that everything we compute
only depends on what we know about the integers. We can say there is no need to
communicate a dependence on say a polynomial ring over the integers because all
algorithms only work on the integers (the exponents of the monomials are also
integer vectors). But the way mathematics is developed is to create new objects.
If the algorithm is really for the new object (residue class ring or the
polynomial ring) then it should be reflected in the signature of the code. If
you think the algorithm is only for R, sure you can hide the new object even if
you need it for computation. Of course, one can, like algebraic geometer, take
the view of Spec R which encapsulates all its local rings, but that would be
fine if you have algorithms on sheaves. On the other hand, I think at these high
level of abstractions, it is important to distinguish data structure for an
object, and algorithms for it or its derived objects and not to mix them up.
That is the reason for package constructors in Axiom, to be separated from
domain constructors. They are like two "independent" branches of government.
> > (II) For each R:A for which a method to construct S for p:P exist, we
> > must *retroactively* make R:ComputationMethod.
>
> Again, true. However, I fail to see why this is a issue. When one
> writes the algebra, decisions made during initial design will always
> be rethought. I dont think this is an argument against the
> residueClassRing example as much as it is a proof that `hindsight is
> 20/20'.
I am not arguing against residueClassRing, but more generally and that is why I
abstracted the example. We will never be able to envision all the possible
structures that can be put on a mathematical object at its first implementation.
The Integer domain is a prime example. But there are many other too. For
example, we have trees implemented, but tree domains can also have a Hopf
algebra structure. That is not what most would think of when implementing trees.
So that structure, when needed, say doing renormalization with Feymann graphs in
quantum field theory, would have to be added on later. Whether one wants to add
this directly to the initial construction or not is matter of choice. But in the
end, as my abstract example shows, there is no inherent gain of computation
power or even convenience, and the two calling sequences:
bar(...)$Algorithm(R,p, Method1(R,p))
bar(p:P, ...)$Algorithm(R)
(the second should more correctly be written
bar(p:P, ...)$Algorithm(R1) )
are not that much different. So in Aldor, you can choose whichever you like:
encapsulating more structure into R, or separating the residueClassRing
construction (and I indicated that there is more freedom of expression in
Aldor). In the analogous example I gave, there are many representations
(different data structure, different term ordering) for the polynomial ring, and
it would be crazy to encapsulate such structure into the coefficient domain R.
Can you tell me structurally, both in terms of mathematics and coding, any
difference between the polynomial ring example and the residue class ring
example? Why should one be treated differently than the other in the matter of
encapsulation?
(Remember, the P for residue class rings is Ideal(R), not R and so it is an
externally defined domain much like the P for polynomial ring is List Symbol,
external to R.)
> > (III) Now if R has several methods, then we must *rename* R using
> > three different names in (II), even though R is still the same object
> > in category A. This would be very undesirable if R is Integer.
>
> For Integer we might say
>
> 
> residueClassRing(p:%):ResidueClassRing(%, p) ==
> if p < 2^32 then
> ZechPrimeField(p)
> else
> IntegerMod(%,p);
> 
But this can also be done in Axiom in the domain constructor for the
ResidueClassRing.

ResidueClassRingForInteger(p) ==
if p < 2^32 then
ZechPrimeField(p)
else
IntegerMod(%,p);

The only difference is you called the domain constructor by a uniform name (but
has to rename the ring R for each separate data structure for the residue class
ring S in making R into ModularComputation).
[Remark: it would be harder if you implement residue class ring more generally,
using ideals insteads of numbers, but I am going along with your version for
now.]
But as a style of programming, I would not inline the two segments of code as
above (the thenpart and the elsepart will be separated by many lines of code).
So in the end, one would still separately have two constructors (notice that if
not inlined, two names are used: ZechPrimeField and IntegerMod, and
ResidueClassRingForInteger, or residueClassRing are both wrappers, in addition
to the extra level ModularComputation wrapper). What I am saying is, this extra
wrapped level ("push" direction) is not necessary in Aldor (just as wrapping a
function with dependent signature into a package is not necessary in Aldor, but
in Axiom, that is the unavoidable "lift" direction.)
> If for a given situation we need more information than just what R:A
> and p:P can provide, then variants on the name of a domain constructor
> is an option, but not the only one (or the best one). We could just as
> easily add a second residueClassRing(p, moreInformation) to
> ModularComputation's list of exports to express the dependency on such
> information explicitly. We could alternatively write
> ModularComputation2 with the extra signature. In short, we let the
> structure of the algebra communicate the interrelations as much as
> possible rather than relying on naming conventions alone. This is a
> problem of design, and one which dependently typed functions provide
> an elegant solution.
You may have missed my point. By creating more categories, such as
ModularComputation or ModularComputation2, you REQUIRE the domain R to be
declared as such in any actual computation. If R is a new domain, fine. If R
already exists, this has to be wrapped into new domains, using new names. But in
any case, R is now tied to the residueClassRing map that makes it a
ModularComputation domain, its identity as the original commutative ring is
suppressed, and R splits into many versions depending on the way
residueClassRing is implemented.
I would much prefer that the new names refer to the methods to construct
residueClassRing, than to tie it to the ring R, because one method may work for
many R, and yet your ModularComputation works only for ONE R. An example would
be when R is a polynomial ring over some field k. We can construct residue class
rings uniformly not just for prime polynomial ideals, but for all coefficient
field and for all choices of indeterminates. In your set up, each would need a
separate residueClassRing map. Unless convinced otherwise, I think overloading
(or polymorphic) is best used for operations and not domain constructions.
There is a big difference between mathematics objects and computation objects.
In mathematics, one may argue that all the residue class rings are part of the
ring R (each residue class ring is uniquely defined). So there is still just one
mathematical object when all its residue class rings are included.
Computationally, however, one has to consider both data structure representation
of the residue class rings AND the algorithmic aspect of operations and other
problem solving techniques for the residue class rings. We cannot lump all these
into the same domain R. Each must be separately identified. That is the reason
for so many polynomial categories, even for a fixed coefficient domain and a
fixed set of variables. Pushing these domain constructors into the level of a
function (with dependent signature) may look neat, but it does not eliminate the
bifurcation in computation objects.
>
> > (IV) The "advantage" at first glance, seems to be operator
> > overloading: using one single name "method" to refer to all the
> > Method[i] in constructions of S. But as (II) shows, this "powerful"
> > and categorical construction is nothing but a wrapper, which is the
> > the reverse of what I proposed for Martin's example: instead of
> > lifting a function g(n,k) to the level of a package, where the
> > dependence on parameters in the signature belongs, the construction of
> > ComputationMethod pushed the level of a domain constructor (which is
> > what each Method[i] is) to the level of a function. I don't think
> > that is a convincing example of the need for allowing dependence on
> > parameters for functions.
>
> But this act of `pushing' a domain constructor to a level of a
> function is what allows one to communicate the structure of the algebra
> by *using the structure itself*. I'll say more below.
If you treat creating more abstract categories when it is not absolutely needed
and hiding the existence of the residue class rings as *using the structure
itself*, then I do not agree. But if what you are trying to do is an initial
step towards the idea of sheaves, that is different and in that case, perhaps
you should start with the category of sheaves.
>
> > The power of that construction in Aldor, as I pointed out in another
> > email, is allowing such dependence in functions on the SOURCE side,
> > not on the TARGET side of the map. In short notation:
> >
> > F(a:A, b:B(a), c:C(a,b)):D(a,b,c)
> > ...
>
> I do not argue these points at all. Note that in some languages, like
> ocaml, the signature for a function like this would take the form
> (more or less):
>
> F: (a:A) > (b: B(a)) > (c: C(a,b)) > D(a,b,c).
>
> And calling F x, would return a function F': B(a) > C(a,b) >
> D(a,b,c), etc.
> Depending on your point of view, a function with multiple, dependently
> typed arguments is just notation to express a chain of functions where
> the only dependence is in the type of the result. I find this
> interpretation quite satisfying.
This is indeed a nice way to define recursively the signatures, but I won't call
these "functions".
> Your comments on `lifting' the aldor example is perfect in that this
> is the probably the best way to write such things in axiom today. I'll
> just recap the result:
>
> > Foo(R,p,S): T == C where
> > R: ModularCategory
> > p: Ideal(R)
> > S: ResidueClassRing(R,p)
> > Q ==> any domain constructed from R, p, S
> > T == with
> > bar: R > Q
> > C == add
> > bar(r)==
> > elem:S:=modularRep(r)$S
> >  hairy computations
> > q:Q:= ...
> >
> > Calling sequence in some other package, assuming R, p, S are already
> > defined:
> >
> > bar(r)$Foo(R,p,S)
> >
> > If you want to use the default implementation when R is a domain in
> > IntegerCategory, you can use:
> >
> > if R has IntegerCategory then
> > S:=IntegerMod(R,p)
> > bar(r)$Foo(R,p,S)
>
> The last part is the kicker for me, asking `if R has IntegerCategory
> then ...' is where the two approaches diverge. I claimed that I
> doubted one could write an equivalent Foo without the use of some
> hypothetical RESCLASS package/domain which made use of copious `if R
> has ..' constructs. Although the model I had in mind of how this
> would look in Axiom is different from your solution, the main point is
> still there. The questions are being asked, just at a different level
>  either code which uses Foo needs to provide an answer, or a user
> typing into the interpreter.
Well, I was only using the "if R has IntegerCategory" because you defined a
default implementation (which actually does not work for all R:IntegerCategory).
The Axiom implementation allows you to put ANY RESCLASS domain for the parameter
S and there is no need for "if R has ...". In Axiom, I am not aware of any
default construction for domains (all constructions are "equal opportunity"
employed), only default implementation for operations (for example ** in
monoid).
> The crux issue in my mind is that the aldor example illustrates how
> one can encapsulate questions like `if R has ..' into the structure of
> the algebra itself. residueClassRing() is more than just a wrapper. It
> communicates a relationship between R, p, and C(r,p). The axiom
> solution you propose communicates a relationship between R, p, and
> S:C(R,p). The problem of needing to know S is removed in the aldor
> example, as questions regarding it are not raised ( clearly for given
> R and p there *is* a relationship to S:C(R,p).
There is only syntactical difference and not semantical. The S in the Foo
package is only a symbol needed to do a package call. It is the equivalent to
the symbol method(p) (or residueClassRing(p)) to make the same package call. In
either case, the actual knowledge of S or method(p) is not needed, only the
categorical properties as defined in C(R,p) are. In Aldor, you need to use
method(p) and in Axiom, you need to use S, both for package call. If you hide S
(as given above), you hardwired S into R and make it less convenient to change
S.
I fail to see the connection between this hiding and the "if R has ..." and I
already commented on that. You are correct that SOME "if R has ..." may be
eliminated by the signatures F(a:A, b:B(a), c:C(a,b)):D(a,b,c) (recall that I
proposed the converse to implement these signatures in Axiom *using* "if R has
...". In other words, "if R has ..." is more general (or powerful) construct
than the signatures. Even if (in 30 years?) Axiom or Aldor is integrated with
theorem proving, there will still be "if R has ..." that cannot be verified by
the theorem provers and need a mathematician to declare it (if only for
efficiency). To quote a cliche: who is going to prove the theoremprovers?
> But this relationship
> is expressed in code at the domain level, where it `belongs'. The
> domains are just implementing the requirements of their exports).
Absolutely. That's what Axiom (and Aldor) both do. What's the difference?
You push construction of domains (residue class rings) to the function level
(like hidden domains within a domain, second class citizen?). Surely, you don't
think residue class rings do not deserve their own domain?
> There are other reasons to consider dependent types in a function
> target. If we are interested in future integration with a proof engine
> like ACL2, then we will want to consider the role such functions can
> play in such a setting. Some of the leading proof assistants, like
> LEGO and COQ, make explicit use of dependent type information.
I don't argue against the usefulness of dependent types. Surely, they are more
convenient to use, but that does not mean they must be used. I do not totally
object to your construction of ModularComputation. In Axiom, there is at least
one example similar: EuclideanDomain, where we absorb the Euclidean algorithm as
part of the domain. But there is a difference, the functions that are added do
not construct domains, they only implement algorithms. So this is "pushing"
packages into new domains, while your example is "pushing" domains to functions.
Maybe someone will pick up this discussion and explore all the pushing and
lifting possible among categories, domains, packages and "functions" and
determine some general guidelines of what should be done under what
circumstances. That might be a good master thesis.
This discussion started with whether Axiom can simulate dependent signature and
I believe you now agree that it can.
William
\end{verbatim}
\section{email 2}
\begin{verbatim}
First, let me thank you for your analysis! I am finding the questions
raised here very interesting. But I'm still on the other side of the
fence for the moment :)
> (I) The algorithm, which is really for S, is now an algorithm for R.
> It hides the existence of S completely. It also hides the relevance
> of p:P.
The algorithm never needs to know S explicitly. If anything, the
algorithm involves `something' with satisfies C(R,p). However, the
meaning of a call to bar(p:R, ...)$Foo will in general carry a level
of meaning all its own, which need not communicate a dependence on S
(or C(R,p)). I dont see how this level of semantics involves the
problems we are discussing.
> (II) For each R:A for which a method to construct S for p:P exist, we
> must *retroactively* make R:ComputationMethod.
Again, true. However, I fail to see why this is a issue. When one
writes the algebra, decisions made during initial design will always
be rethought. I dont think this is an argument against the
residueClassRing example as much as it is a proof that `hindsight is
20/20'.
> (III) Now if R has several methods, then we must *rename* R using
> three different names in (II), even though R is still the same object
> in category A. This would be very undesirable if R is Integer.
For Integer we might say

residueClassRing(p:%):ResidueClassRing(%, p) ==
if p < 2^32 then
ZechPrimeField(p)
else
IntegerMod(%,p);

If for a given situation we need more information than just what R:A
and p:P can provide, then variants on the name of a domain constructor
is an option, but not the only one (or the best one). We could just as
easily add a second residueClassRing(p, moreInformation) to
ModularComputation's list of exports to express the dependency on such
information explicitly. We could alternatively write
ModularComputation2 with the extra signature. In short, we let the
structure of the algebra communicate the interrelations as much as
possible rather than relying on naming conventions alone. This is a
problem of design, and one which dependently typed functions provide
an elegant solution.
> (IV) The "advantage" at first glance, seems to be operator
> overloading: using one single name "method" to refer to all the
> Method[i] in constructions of S. But as (II) shows, this "powerful"
> and categorical construction is nothing but a wrapper, which is the
> the reverse of what I proposed for Martin's example: instead of
> lifting a function g(n,k) to the level of a package, where the
> dependence on parameters in the signature belongs, the construction of
> ComputationMethod pushed the level of a domain constructor (which is
> what each Method[i] is) to the level of a function. I don't think
> that is a convincing example of the need for allowing dependence on
> parameters for functions.
But this act of `pushing' a domain constructor to a level of a
function is what allows one to communicate the structure of the algebra
by *using the structure itself*. I'll say more below.
> The power of that construction in Aldor, as I pointed out in another
> email, is allowing such dependence in functions on the SOURCE side,
> not on the TARGET side of the map. In short notation:
>
> F(a:A, b:B(a), c:C(a,b)):D(a,b,c)
> ...
I do not argue these points at all. Note that in some languages, like
ocaml, the signature for a function like this would take the form
(more or less):
F: (a:A) > (b: B(a)) > (c: C(a,b)) > D(a,b,c).
And calling F x, would return a function F': B(a) > C(a,b) >
D(a,b,c), etc.
Depending on your point of view, a function with multiple, dependently
typed arguments is just notation to express a chain of functions where
the only dependence is in the type of the result. I find this
interpretation quite satisfying.
Your comments on `lifting' the aldor example is perfect in that this
is the probably the best way to write such things in axiom today. I'll
just recap the result:
> Foo(R,p,S): T == C where
> R: ModularCategory
> p: Ideal(R)
> S: ResidueClassRing(R,p)
> Q ==> any domain constructed from R, p, S
> T == with
> bar: R > Q
> C == add
> bar(r)==
> elem:S:=modularRep(r)$S
>  hairy computations
> q:Q:= ...
>
> Calling sequence in some other package, assuming R, p, S are already
> defined:
>
> bar(r)$Foo(R,p,S)
>
> If you want to use the default implementation when R is a domain in
> IntegerCategory, you can use:
>
> if R has IntegerCategory then
> S:=IntegerMod(R,p)
> bar(r)$Foo(R,p,S)
The last part is the kicker for me, asking `if R has IntegerCategory
then ...' is where the two approaches diverge. I claimed that I
doubted one could write an equivalent Foo without the use of some
hypothetical RESCLASS package/domain which made use of copious `if R
has ..' constructs. Although the model I had in mind of how this
would look in Axiom is different from your solution, the main point is
still there. The questions are being asked, just at a different level
 either code which uses Foo needs to provide an answer, or a user
typing into the interpreter.
The crux issue in my mind is that the aldor example illustrates how
one can encapsulate questions like `if R has ..' into the structure of
the algebra itself. residueClassRing() is more than just a wrapper. It
communicates a relationship between R, p, and C(r,p). The axiom
solution you propose communicates a relationship between R, p, and
S:C(R,p). The problem of needing to know S is removed in the aldor
example, as questions regarding it are not raised ( clearly for given
R and p there *is* a relationship to S:C(R,p). But this relationship
is expressed in code at the domain level, where it `belongs'. The
domains are just implementing the requirements of their exports).
There are other reasons to consider dependent types in a function
target. If we are interested in future integration with a proof engine
like ACL2, then we will want to consider the role such functions can
play in such a setting. Some of the leading proof assistants, like
LEGO and COQ, make explicit use of dependent type information.
Sincerely,
Steve
On Sat, Jan 15, 2005 at 03:30:40PM 0500, William Sit wrote:
> It appears that the previous file may have some display alignment problems (in
> the code indentations). So here is hopefully a better version. My apologies
> for
> duplicates.
>
> William
> 
>
>
> Hi Steve:
>
> Your example is very interesting and it took me quite some time to
> understand it (I am slow in learning and I tossed and turned several
> times between endorsing it to rejecting it). My tentative short
> answers are that (1) Yes, this can be implemented in current Axiom and
> (2) There are big hidden problems (see (II, III) below) in
> implementing the Aldor version!
>
> But: there is no such thing as a simple explanation.
>
> So please bear with me. To avoid getting into residue class rings,
> let me simplify and abstract the hypothesis under which the example
> makes sense. If you do want the analysis for residue class ring (and
> on how I arrive at the above conclusions), just keep reading.
>
> Given a certain domain R of category A, and another domain P of
> category B, let's assume that there is at least one uniform way of
> constructing, for each p:P, a new domain S (belonging to some category
> C that depends on R and p). For a given R, there may be several such
> uniform methods to construct the same mathematical object S; and
> certainly for different R's, there would be other ways of constructing
> S. For example, if R' (of category A', which is a subcategory of A)
> has some special properties, the construction may be different. In
> Axiom, each construction of S requires a domain constructor:
>
> Method1(R:A, p:P)==S:C(R,p)
> Method2(R:A, p:P)==S:C(R,p)
> Method3(R':A, p:P)==S:C(R',p)
> Method4(R':A', p:P)==S:C(R',p)
>
> In Axiom, because the signatures of the first three methods would be
> the same, the domain constructors need different names.
>
> Now suppose we want to implement an algorithm for S and this is to be
> done categorically, independent of the actual construction of S, but
> depend on a function foo which is defined for all domains in the
> category C(R,p). Currently, in Axiom, this would be a package:
>
> Algorithm(R:A, p:P, S:C(R,p)) == add
> bar(...) == ... foo(...)$S ...
>
> and a typical calling sequence would be:
>
> bar(...)$Algorithm(R,p, Method1(R,p))
>
> Now let's see how we may do the same thing a la Steve's example in
> Aldor. We would create a new category to encapsulate the various
> methods for constructing S.
>
> ComputationMethod: Category == Join(...) with
> method:(p:P) > C(%,p)
>
> and the algorithm for S would be in a package:
>
> Algorithm(R:Join(A,ComputationMethod)) ==
> add { bar(p:P, ...)== ... foo(...)$method(p) ...}
>
> and a typical calling sequence would be:
>
> bar(p:P, ...)$Algorithm(R)
>
> There are several problems:
>
> (I) The algorithm, which is really for S, is now an algorithm for R.
> It hides the existence of S completely. It also hides the relevance
> of p:P.
>
> (II) For each R:A for which a method to construct S for p:P exist, we
> must *retroactively* make R:ComputationMethod. This requires
> modifying the original construction of R. If the construction of R is
> from a domain constructor T, say R := T(...) where
>
> T(...):A == ...
>
> and if Method1 is used to construct S, we must now modify this to
>
> T'(...):Join(A, ComputationMethod) == T(...) add
> method(p:P) == Method1(%,p)
>
> We must create a new constructor T' and not modify T because not every
> T(...) is to become a domain in ComputationMethod. So even though we
> eliminated one domain constructor (Method1, assuming this is inlined),
> we need one new domain constructor to "wrap" it. If T is actually the
> construction of R from scratch (that is, R is T, and (...) is empty;
> such as Integer), then inlining retroactively Method1 would require
> recompiling the whole world.
>
> (III) Now if R has several methods, then we must *rename* R using
> three different names in (II), even though R is still the same object
> in category A. This would be very undesirable if R is Integer.
>
> [Remark: It seems to me the original algebra developers in Axiom
> avoided at all cost to modify existing domains because recompiling the
> world took a long time in those days. They typically added packages
> and extended domains to cover any shortcoming in the original
> implementations.]
>
> (IV) The "advantage" at first glance, seems to be operator
> overloading: using one single name "method" to refer to all the
> Method[i] in constructions of S. But as (II) shows, this "powerful"
> and categorical construction is nothing but a wrapper, which is the
> the reverse of what I proposed for Martin's example: instead of
> lifting a function g(n,k) to the level of a package, where the
> dependence on parameters in the signature belongs, the construction of
> ComputationMethod pushed the level of a domain constructor (which is
> what each Method[i] is) to the level of a function. I don't think
> that is a convincing example of the need for allowing dependence on
> parameters for functions.
>
> *************************************************************
> * It is clear that the two set ups are equivalent and
> * the translation is bidirectional. The Axiom implementation
> * is more natural and does not have the disadvantages.
> *************************************************************
> The power of that construction in Aldor, as I pointed out in another
> email, is allowing such dependence in functions on the SOURCE side,
> not on the TARGET side of the map. In short notation:
>
> F(a:A, b:B(a), c:C(a,b)):D(a,b,c)
>
> is a powerful signature, not because the a, b, c appears on the Target
> D, but because they appear in other parameters on the Source side. If
> A, B, C represent three axes in 3space, then F is analogous to an
> iterated triple integral over a nonrectangular region in 3space,
> whereas
>
> F(a:A, b:B, c:C):D(a,b,c)
>
> is like the same over a rectangular region (a cuboid) in 3space.
>
> If we may borrow the way Matlab does these computation (Matlab, for
> Matrix Laboratory, is constrained in these numerical triple
> integration computations because it must define grid points in 3space
> in a 3dimensional matrix), we have to "zero" out the complement of
> the conditionals b:B(a) and c:C(a,b). This would be difficult without
> an over category B' and C' of which B(a) and C(a,b) are subcategories.
> But we can always create such over categories and it would not be
> difficult then to restrict the inputs by using "if b has B(a)" and "if
> c has C(a,b)". In fact, Axiom does this all the time with
> nonparametrized conditionals like "if R has CharacteristicZero".
> Even though I can't recall any attributes being parametrized, there is
> no reason why Axiom cannot support such. If I understand correctly,
> attributes are defined as Categories. Let me leave that as an
> exercise for someone to find out. :). I am more convinced now that
> the signature limitation in Axiom does not actually limit its power,
> but does restrict its freedom of expression in some situations.
>
> > How could one write the bar()$Foo above with the current axiom
> > language? All you can do is write a package/domain parameterize
> > by a commutative ring R and a representative of R, and write the
> > exports dependently on R's type via `if R has ...' constructs.
> > This is what I meant in the previous email about having a
> > RESCLASS package/domain which needed to know too much about the
> > algebra.
>
> In Axiom, as well as in Aldor, the conditional "if R has ..." is never
> meant to be algorithmic. It is a declarative that a domain has a
> certain attribute. Such a declarative is never verified by code. It
> is one of the "trust me" situations. We do NOT need to know about
> every ring when we use these conditionals, because for whatever actual
> domain R is inputted, the *programmer* will have to declare his/her
> knowledge about these conditionals in the domain constructor for R, as
> in, for example, "Join(CharacteristicZero, ..." There is no algorithm
> to test if an arbitrary ring has characteristic zero. One just knows
> from the mathematics of particular rings. You used these conditionals
> also in defining the ResidueClassRing(R,p) category and it does not
> mean you know which commutative ring R has SourceOfPrimes or has
> implemented prime?(p). But for the rings R for which you do know, you
> declare them to have SourceOfPrimes, and you implement prime?(p) in
> the domain constructor that gives R.
>
> Below, I'll give more explanation how I arrive at my conclusion above.
> Stanzas marked between ==== and **** are mine (and those lines between
> **** and ==== are Steve's). In each stanza, I put down a paraphrase
> of Steve's code (in a combination of code, math and English, with
> added background information), and an analog taken from Axiom (which
> helped me notice what the map residueClassRing really is  it became
> obvious only after such analysis). The way to follow my analysis
> would be to read the paraphrase from top down, then read the analogy
> from bottom up (if you don't, you may find some notations not yet
> defined). Then read the above abstract discussion again.
>
> I skipped the Axiom constructions for all the constructors in Steve's
> example, except for Foo. I think it is clear from the more general
> discussion above how to complete the conversion.
>
> By the way, the analogy would fit the abstract situation above too. R
> is a ring, P is List Symbol, S is the polynomial ring R[p], and the
> Algorithm is GroebnerBasis. The methods are DMP, HDMP, GDMP.
>
> William
> 
> Steve Wilson wrote:
>
> The following is an example with a view towards generic modular
> computations. Aldor has a category (approximately):
>
> 
> ModularComputation: Category == CommutativeRing with {
> residueClassRing: (p: %) > ResidueClassRing(%,p);
> ....
> }
> 
> ============
>
> Paraphrase:
>
> A ModularComputation domain R is a commutative ring with a map
>
> residueClassRing: R > ResidueClassRing category
>
> In such a domain R, there is an algorithm to construct the residue
> class ring for any prime ideal p in R. Mathematically, the residue
> class ring of R with respect to a prime ideal p is (R_p)/(p R_p),
> where R_p is the localization of R at the prime ideal p. When lifted
> to R_p, the prime ideal p becomes p R_p, the unique maximal ideal of
> R_p (which is called a local ring). The residue class ring is then
> formed by the "modding out" the maximal ideal.
>
> The notation p:% above is technically incorrect and should be
> something like p: Ideals(%), and for R in the IntegerCategory
> (below), there is a coercion from a prime integer p to the prime ideal
> (p), at least in the envisioned situation. There are other rings,
> typically polynomial rings, where there is an algorithm to detect
> prime ideals (using a primary decomposition algorithm and for these
> rings, the residue class ring can also be constructed).
>
> Analogy:
>
> PolynomialComputation: Category == CommutativeRing with {
>
> polyomialRing: (v:List Symbol) > POLYCAT(v, %)
>
> There is really no need for the map polynomialRing because it
> encapsulates a domain constructor, which must be implemented for each
> instance of v and R. Examples of this map polynomialRing in action
> are:
>
> DMP(v,R): POLYCAT(v,R)
> HDMP(v,R): POLYCAT(v,R)
>
> Each of these domain constructor is equivalent to an instance of the
> map polynomialRing and therefore, a domain of the category
> PolynomialComputation.
>
> ************
>
>
> So any domain satisfying Modular computation is a CommutativeRing R,
> which exports a function which takes a representative p of R and
> returns something which satisfies ResidueClassRing(R,p).
>
> 
> ResidueClassRing(R: CommutativeRing, p: R): Category ==
> CommutativeRing with {
> modularRep: R > %;
> canonicalPreImage: % > R;
> if R has EuclideanDomain then {
> symmetricPreImage: % > R;
> if R has SourceOfPrimes and prime?(p)
> then Field;
> } }
> 
> =========
>
> Paraphrase:
>
> A ResideClassRing S is constructed from a base commutative ring R and
> a prime ideal p of R. It is a commutative ring with these operations:
>
> modularRep : R > S
> canonicalPreImage: S > R
> if R is a Euclidean domain, then there are more operations:
> symmetricPreImage: S > R
> if we know the prime ideals of R, and p is a prime ideal,
> then S is a field
>
> ResidueClassRing is a category constructor because there may be
> several representations of S, given one R and one prime ideal p of R.
> In order to perform this construction, we would need to have
> constructed already Ideal(R), the domain of ideals of R, and a
> function that can decide whether a given ideal is prime or not. The
> localization construction is already in Axiom (the FRAC constructor is
> a special case where the prime ideal is (0)). The modulo operation is
> available for polynomial rings using Groebner basis method (in
> PolynomialIdeal), and of course also for Integer using plain old
> division. These two are the most important examples. For this
> discussion, the ifclauses are not relevant.
>
> Analogy:
>
> POLYCAT(v: List Symbol, R: CommutativeRing):Category ==
> CommutativeRing with {
> coerce: R > %;
> retract: % > R;
> ...
> }
>
> **********
>
>
> Here we use the notion of SourceOfPrimes until someone figures out a
> meaningful way to represent a MaximalIdeal generally:).
>
> Aldor has an IntegerCategory, roughly:
>
> 
> IntegerCategory: Category ==
> Join(IntegerType, CharacteristicZero, EuclideanDomain,
> ModularComputation, SourceOfPrimes,
> GeneralExponentCategory, Specializable,
> Parsable) with {
> ...
> default {
> residueClassRing(p:%):ResidueClassRing(%, p) ==
> IntegerMod(%,p);
> ...
> } }
> 
> =========
>
> Paraphrase
>
> A domain R of category IntegerCategory is a Euclidean domain of
> characteristic zero, etc., where we know the prime ideals, and we know
> how to construct a ResidueClassRing S given any prime ideal p in R.
>
> A default way to construct S is via IntegerMod(R, p) when R is an
> IntegerCategory domain. The construction IntegerMod(R, p) is assumed
> known and efficient. This default construction does not really apply
> always, for example, when R is a polynomial ring. But this is outside
> the scope of the current discussion.
>
> Analogy:
>
> PolynomialConstructable: Category ==
> Join( ...) with {
> default {
> polynomialRing(v:List Symbol): POLYCAT(v,%) == DMP(v, %);
> ...
> } }
>
>
> **********
>
> And IntegerMod is an efficient implementation:
>
> 
> IntegerMod(Z:IntegerCategory, p:Z):ResidueClassRing(Z, p) == add {
> ... }
> 
>
> =========
> Paraphrase:
>
> IntegerMod is a domain constructor that is actually implementable
> because we supposedly know how to construct the residue class ring for
> a domain R (or Z) of the IntegerCategory and a prime ideal p of R.
> IntegerMod represents ONE way of construction for S:= (R_p)/(p R_p).
>
> Analogy:
>
> DMP (DistributedMultivariatePolynomial) is a domain constructor in
> Axiom that implements a polynomial ring with coefficient ring R and a
> list of indeterminates v. It uses the pure lexicographic ordering on
> monomials.
>
> DMP(v:List Symbol, R: Ring): POLYCAT(v,R) == Join(...) add ...
>
> It may serve as the default constructor. Other constructors use other
> term orderings, for example HDMP or GDMP.
>
> Here POLYCAT(v,R) is a specialization of an actual category
> constructor from Axiom, except I have abbreviated the parameter set in
> this analogy. The full macro expansion is
>
> POLYCAT(v,R) ==> PolynomialCategory(R,_
> Direct Product(#(v),NonNegativeInteger),_
> OrderedVariableList(v))
>
>
> Axiom Version:
>
> IntegerMod(R, p): T == C where
> R: IntegerCategory
> p: Ideal(R)
> T == ResidueClassRing(R, p)
> C == add { ... }
>
> *********
>
> Assuming this type of stuff is implemented in the library where it is
> needed we can write very generic functions:
>
> 
> Foo(R: ModularComputation): with { ... } == add {
> bar(r: R, p:R): R == {
>
> elem : ResidueClassRing(R, p) :=
> modularRep(r)$residueClassRing(p)
>
>  hairy computation...
>
> canonicalPreImage(elem)
> } }
> 
> ========
>
> Paraphrase:
>
> Foo is a package for a ModularComputation domain R, with a function
> bar: (R, R) > R and the function bar is implemented as:
>
> bar(r,p) ==
> compute the elem:= modularRep(r) in S
>  S is the ResidueClassRing for R and p.
> compute some other things
>  (which may or may not change elem, but
>  presumably elem remains in S
> return canonicalPreImage(elem) in R
>
> or the function bar may be bar: (R, p:R) > S(p) if it returns elem.
>
>
> Analogy:
>
> The function bar is just a suppedup version of Martin's example:
>
> g(n,k) == (k mod n):PrimeField(n)  assuming n is prime
>
> so it can be implemented in Axiom. The mod function is the coerce
> function in PrimeField(n)
>
> coerce: PositiveInteger > PrimeField(n)
>
> So similarly, the modularRep(r) function is a function in S
>
> modularRep: R > S
>
> is similar to a coercion from R to S and the canonicalPreImage is a
> function from S to R similar to a retract:S > R.
>
>
> Axiom version:
>
> Foo(R,p,S): T == C where
> R: ModularCategory
> p: Ideal(R)
> S: ResidueClassRing(R,p)
> Q ==> any domain constructed from R, p, S
> T == with
> bar: R > Q
> C == add
> bar(r)==
> elem:S:=modularRep(r)$S
>  hairy computations
> q:Q:= ...
>
> Calling sequence in some other package, assuming R, p, S are already
> defined:
>
> bar(r)$Foo(R,p,S)
>
> If you want to use the default implementation when R is a domain in
> IntegerCategory, you can use:
>
> if R has IntegerCategory then
> S:=IntegerMod(R,p)
> bar(r)$Foo(R,p,S)
>
> Below are just some random notes (my tosses and turns):
>
> Note here S is typically defined using one of the constructors. If
> the map residueClassRing(p) exists, then there will be a corresponding
> domain constructor in Axiom. The advantage of using residueClassRing
> is that we can use ONE name for all the constructors for ALL rings R,
> even if these constructions depend on R (but uniform on p).
> OVERLOADING and S does not have to appear as a parameter because we
> don't care how S is constructed. It is cleaner and corresponds to the
> mathematics by ignoring the data representation or implementation. On
> the other hand, by tagging S along in the package, we can use special
> features in the construction of S in the computation (not really, S is
> given categorically: Example, in GroebnerBasis, we tag along S, the
> Dpol, but since Dpol is just PolynomialCategory based on the other
> parameters, we don't know more. However, in actual computation,
> calling groebner for example, the implementation of Dpol will come
> into action. It makes no difference to let R be a ModularComputation
> because then the implementation is residueClassRing(R,p), so by
> specifying R: ModularComputation, we are singling out the
> implementation, just like when we input Dpol. So ModularComputation
> is only a wrapper. In Steve's example, each time you need functions
> from S, you have to make a function call to residueClassRing(R,p),
> unless, you assign S to it. So it is only a wrapper!
>
> ********
>
> All of this depends on the fact that we can express a dependently
> typed function residueClassRing(p:R), which can be implemented by any
> given domain as appropriate. The Foo package knows all it needs to,
> the Ring, and an element of the ring to get at the the quotient ring.
> Of course, the bar function above could be more complex and return an
> element of ResidueClassRing(R,p), etc.
>
> How could one write the bar()$Foo above with the current axiom
> language? All you can do is write a package/domain parameterized by a
> commutative ring R and a representative of R, and write the exports
> dependently on R's type via `if R has ...' constructs. This is what I
> meant in the previous email about having a RESCLASS package/domain
> which needed to know too much about the algebra.
>
> =======
>
> see discussion on top of email
>
>
> *******
\end{verbatim}
\section{email 3}
\begin{verbatim}
On Friday, January 14, 2005 4:04 PM William Sit wrote:
> ...
> I think something like F(a:A)==F(a):B(a) should simply be
> called a program or routine! It is neither a function nor
> a functor in the strict mathematical sense.
I agree.
>
> > Is there a way that this "Aldor function" can be written
> > in Aldor that syntactically respects the same distinction?
> > If so, then perhaps we should just consider the way Aldor
> > allows this to be written as a kind of abbreviation that
> > happens to look like the notation for a function.
>
> I think Aldor treats the two levels equally, that is, domain
> constructors and "function" are the treated the same. Axiom
> does not and restricts "function" to a real mathematical
> function while leaving domain (or even category and package)
> constructors a bit more general by allowing dependent signatures.
I have argued that this is a good thing because allowing dependent
"signatures" is really better represented mathematically as a
functor, i.e. something that provides new objects as well as
operations (functions) on these objects. I think it is correct
to think of an Axiom domain constructor as a functor (of a specific
kind) in the sense of category theory. I continue this view in
response to another comment below.
> This allowed dependence is even more general than F(a:A)==F(a):B(a),
> for example, one can have F(a:A,b:B(a),c:C(a,b))==F(a,b,c):D(a,b,c).
> Such dependence is not allowed for functions in Axiom but allowed
> in Aldor. In other words, the source does not have to be "rectangular"
> but can be any "area" (or "solid") with bounding "curves" ("surfaces").
> Metaphorically, Aldor allows integration over any solid, Axiom only
> over a cuboid. If you think about this calculus analogy, you can see
> that Aldor is a much more powerful language.
>From a category theory perspective this is like allow "partial
functions", i.e. functions defined only over a subset of its domain.
This is possible but it turns out not to be a "more powerful
language". Sometimes a language can be more powerful because of
it's restrictions rather than it's apparent flexibility. Generality
can compromise expressiveness. So in the category SET (actually
a specific type of category called a topos) the morphisms (functions)
are taken to be total. But that is a very long story and maybe
you already know it or we can talk more about it later.
>
> > BTW, chapters 11 Packages, 12 Categories and 13 Domains of the
> > Axiom book are very useful but I find the orientation rather
> > confusing  perhaps it is just the "age" of the terminology
> > that is used in these chapters that makes reading a little hard.
> > I think it would be great if these could be rewritten in a
> > more modern "categorical" manner similar to the way you wrote
> > your previous message. Are there any papers that you could
> > reference that attempt to do this? Is there some corresponding
> > part of the Aldor documentation that would be useful for me
> > to reread?
>
> Well, I tried to look up something from the web for my email
> on functors, and I got a nice one for you:
>
http://math.ucr.edu/home/baez/categories.html
Well, this article by Baez seems to be just about category theory.
What I was looking for was some documentation about the specific
use of the word "functor" in the context of Aldor (and possibily
Axiom). I am aware that this usage differs (to greater or lesser
extent) from the normal usage in category theory per se.
> Actually, I was attempting to explain why something like Integer
> is a category and I remembered that category theorist think of a
> group as a category but forgot how. The above article explains
> that. But applying the same to Axiom does not work! Try it.
I am not sure exactly what you mean by it "does not work".
I agree however that what Axiom calls a "category" is not quite
the same thing as what category theory calls a category. This
is an unfortunate confusion of terminology of course given that
Axiom is specifically intended to be a tool to implement in computer
form much of the mathematics that is now routinely formalized using
the methods of category theory. One reason of course is that the
development of Axiom occurred more or less in parallel with modern
category theory so there are many ideas in common but also
many differences as ideas once implement by computer become
somewhat more permanent than ideas freely expressed by creative
mathematicians.
There are other newer programming languages, such as Haskel and
Ocaml which specifically take an approach which is more in line
with modern category theory than is Axiom. My impression was
that Aldor also may have attempted to move in this direction.
That is why I was asking about the use of the word functor in
Aldor.
Some previous discussion of these issues on the axiomdeveloper
email list:
http://lists.gnu.org/archive/html/axiommath/200310/msg00020.html
http://lists.gnu.org/archive/html/axiomdeveloper/200310/msg00110.html
http://lists.gnu.org/archive/html/axiomdeveloper/200310/msg00108.html
> From: Bill Page
> Subject: RE: [Axiomdeveloper] categorical design
> Date: Thu, 9 Oct 2003 22:54:30 0400
>
> BTW, if I haven't already mentioned it here (or even if
> I have ... ) I would like to recommend a good and
> easily available book on category theory and type systems.
> See the book
>
> Categories Types and Structures
> by Asperti and Longo
> MIT Press, 1991
>
> Now available for download at:
>
> http://www.di.ens.fr/users/longo/download.html
>
> Cheers,
> Bill Page.
http://lists.gnu.org/archive/html/axiomdeveloper/200408/msg00022.html
And about Axiom and category theory elsewhere
http://www.math.unm.edu/ACA/1996/skeletons/Johnson.html
The Axiom computer algebra system applied to computational category theory
Ronald Brown
(joint work with W. Dreckmann(Bangor and Stockholm))
Date: July 18th (Thursday)
Time: 16:2516:45
Abstract
The Axiom language is based on what are called: (Axiom) categories,
domains, packages, objects. An `Axiom category' consists essentially
of a signature. The representation of objects, implementation of
operations, and expression as output form, is carried out in the
domain constructors. The advantages of the Axiom language and system
are discussed, and illustrated in terms of the code for directed graphs,
free categories, and the category of finite sets. It is argued that
this type of system allows for the development of code for the
interaction of examples and abstract algebraic systems, and code which
is relatively easily modified, and sufficiently general to cope with
new examples. That is, the code approximates more than is usual to
the standard ways of writing mathematics.

http://physics.bu.edu/~youssef/homepage/talks/categories/categories.html
And a relatively new paper by Saul Youssef specifically about Aldor
and category theory:
http://atlas.bu.edu/~youssef/papers/math/aldor/aldor.pdf
Prospects for Category Theory in Aldor
Saul Youssef
Center for Computational Science
Boston University
address@bogus.example.com
October 16, 2004
Abstract
Ways of encorporating category theory constructions and results
into the Aldor language are discussed. The main features of Aldor
which make this possible are identied, examples of categorical
construtions are provided and a suggestion is made for a foundation
for rigorous results.
\end{verbatim}
\section{email 4}
\begin{verbatim}
It appears that the previous file may have some display alignment problems (in
the code indentations). So here is hopefully a better version. My apologies for
duplicates.
William

Hi Steve:
Your example is very interesting and it took me quite some time to
understand it (I am slow in learning and I tossed and turned several
times between endorsing it to rejecting it). My tentative short
answers are that (1) Yes, this can be implemented in current Axiom and
(2) There are big hidden problems (see (II, III) below) in
implementing the Aldor version!
But: there is no such thing as a simple explanation.
So please bear with me. To avoid getting into residue class rings,
let me simplify and abstract the hypothesis under which the example
makes sense. If you do want the analysis for residue class ring (and
on how I arrive at the above conclusions), just keep reading.
Given a certain domain R of category A, and another domain P of
category B, let's assume that there is at least one uniform way of
constructing, for each p:P, a new domain S (belonging to some category
C that depends on R and p). For a given R, there may be several such
uniform methods to construct the same mathematical object S; and
certainly for different R's, there would be other ways of constructing
S. For example, if R' (of category A', which is a subcategory of A)
has some special properties, the construction may be different. In
Axiom, each construction of S requires a domain constructor:
Method1(R:A, p:P)==S:C(R,p)
Method2(R:A, p:P)==S:C(R,p)
Method3(R':A, p:P)==S:C(R',p)
Method4(R':A', p:P)==S:C(R',p)
In Axiom, because the signatures of the first three methods would be
the same, the domain constructors need different names.
Now suppose we want to implement an algorithm for S and this is to be
done categorically, independent of the actual construction of S, but
depend on a function foo which is defined for all domains in the
category C(R,p). Currently, in Axiom, this would be a package:
Algorithm(R:A, p:P, S:C(R,p)) == add
bar(...) == ... foo(...)$S ...
and a typical calling sequence would be:
bar(...)$Algorithm(R,p, Method1(R,p))
Now let's see how we may do the same thing a la Steve's example in
Aldor. We would create a new category to encapsulate the various
methods for constructing S.
ComputationMethod: Category == Join(...) with
method:(p:P) > C(%,p)
and the algorithm for S would be in a package:
Algorithm(R:Join(A,ComputationMethod)) ==
add { bar(p:P, ...)== ... foo(...)$method(p) ...}
and a typical calling sequence would be:
bar(p:P, ...)$Algorithm(R)
There are several problems:
(I) The algorithm, which is really for S, is now an algorithm for R.
It hides the existence of S completely. It also hides the relevance
of p:P.
(II) For each R:A for which a method to construct S for p:P exist, we
must *retroactively* make R:ComputationMethod. This requires
modifying the original construction of R. If the construction of R is
from a domain constructor T, say R := T(...) where
T(...):A == ...
and if Method1 is used to construct S, we must now modify this to
T'(...):Join(A, ComputationMethod) == T(...) add
method(p:P) == Method1(%,p)
We must create a new constructor T' and not modify T because not every
T(...) is to become a domain in ComputationMethod. So even though we
eliminated one domain constructor (Method1, assuming this is inlined),
we need one new domain constructor to "wrap" it. If T is actually the
construction of R from scratch (that is, R is T, and (...) is empty;
such as Integer), then inlining retroactively Method1 would require
recompiling the whole world.
(III) Now if R has several methods, then we must *rename* R using
three different names in (II), even though R is still the same object
in category A. This would be very undesirable if R is Integer.
[Remark: It seems to me the original algebra developers in Axiom
avoided at all cost to modify existing domains because recompiling the
world took a long time in those days. They typically added packages
and extended domains to cover any shortcoming in the original
implementations.]
(IV) The "advantage" at first glance, seems to be operator
overloading: using one single name "method" to refer to all the
Method[i] in constructions of S. But as (II) shows, this "powerful"
and categorical construction is nothing but a wrapper, which is the
the reverse of what I proposed for Martin's example: instead of
lifting a function g(n,k) to the level of a package, where the
dependence on parameters in the signature belongs, the construction of
ComputationMethod pushed the level of a domain constructor (which is
what each Method[i] is) to the level of a function. I don't think
that is a convincing example of the need for allowing dependence on
parameters for functions.
*************************************************************
* It is clear that the two set ups are equivalent and
* the translation is bidirectional. The Axiom implementation
* is more natural and does not have the disadvantages.
*************************************************************
The power of that construction in Aldor, as I pointed out in another
email, is allowing such dependence in functions on the SOURCE side,
not on the TARGET side of the map. In short notation:
F(a:A, b:B(a), c:C(a,b)):D(a,b,c)
is a powerful signature, not because the a, b, c appears on the Target
D, but because they appear in other parameters on the Source side. If
A, B, C represent three axes in 3space, then F is analogous to an
iterated triple integral over a nonrectangular region in 3space,
whereas
F(a:A, b:B, c:C):D(a,b,c)
is like the same over a rectangular region (a cuboid) in 3space.
If we may borrow the way Matlab does these computation (Matlab, for
Matrix Laboratory, is constrained in these numerical triple
integration computations because it must define grid points in 3space
in a 3dimensional matrix), we have to "zero" out the complement of
the conditionals b:B(a) and c:C(a,b). This would be difficult without
an over category B' and C' of which B(a) and C(a,b) are subcategories.
But we can always create such over categories and it would not be
difficult then to restrict the inputs by using "if b has B(a)" and "if
c has C(a,b)". In fact, Axiom does this all the time with
nonparametrized conditionals like "if R has CharacteristicZero".
Even though I can't recall any attributes being parametrized, there is
no reason why Axiom cannot support such. If I understand correctly,
attributes are defined as Categories. Let me leave that as an
exercise for someone to find out. :). I am more convinced now that
the signature limitation in Axiom does not actually limit its power,
but does restrict its freedom of expression in some situations.
> How could one write the bar()$Foo above with the current axiom
> language? All you can do is write a package/domain parameterize
> by a commutative ring R and a representative of R, and write the
> exports dependently on R's type via `if R has ...' constructs.
> This is what I meant in the previous email about having a
> RESCLASS package/domain which needed to know too much about the
> algebra.
In Axiom, as well as in Aldor, the conditional "if R has ..." is never
meant to be algorithmic. It is a declarative that a domain has a
certain attribute. Such a declarative is never verified by code. It
is one of the "trust me" situations. We do NOT need to know about
every ring when we use these conditionals, because for whatever actual
domain R is inputted, the *programmer* will have to declare his/her
knowledge about these conditionals in the domain constructor for R, as
in, for example, "Join(CharacteristicZero, ..." There is no algorithm
to test if an arbitrary ring has characteristic zero. One just knows
from the mathematics of particular rings. You used these conditionals
also in defining the ResidueClassRing(R,p) category and it does not
mean you know which commutative ring R has SourceOfPrimes or has
implemented prime?(p). But for the rings R for which you do know, you
declare them to have SourceOfPrimes, and you implement prime?(p) in
the domain constructor that gives R.
Below, I'll give more explanation how I arrive at my conclusion above.
Stanzas marked between ==== and **** are mine (and those lines between
**** and ==== are Steve's). In each stanza, I put down a paraphrase
of Steve's code (in a combination of code, math and English, with
added background information), and an analog taken from Axiom (which
helped me notice what the map residueClassRing really is  it became
obvious only after such analysis). The way to follow my analysis
would be to read the paraphrase from top down, then read the analogy
from bottom up (if you don't, you may find some notations not yet
defined). Then read the above abstract discussion again.
I skipped the Axiom constructions for all the constructors in Steve's
example, except for Foo. I think it is clear from the more general
discussion above how to complete the conversion.
By the way, the analogy would fit the abstract situation above too. R
is a ring, P is List Symbol, S is the polynomial ring R[p], and the
Algorithm is GroebnerBasis. The methods are DMP, HDMP, GDMP.
William

Steve Wilson wrote:
The following is an example with a view towards generic modular
computations. Aldor has a category (approximately):

ModularComputation: Category == CommutativeRing with {
residueClassRing: (p: %) > ResidueClassRing(%,p);
....
}

============
Paraphrase:
A ModularComputation domain R is a commutative ring with a map
residueClassRing: R > ResidueClassRing category
In such a domain R, there is an algorithm to construct the residue
class ring for any prime ideal p in R. Mathematically, the residue
class ring of R with respect to a prime ideal p is (R_p)/(p R_p),
where R_p is the localization of R at the prime ideal p. When lifted
to R_p, the prime ideal p becomes p R_p, the unique maximal ideal of
R_p (which is called a local ring). The residue class ring is then
formed by the "modding out" the maximal ideal.
The notation p:% above is technically incorrect and should be
something like p: Ideals(%), and for R in the IntegerCategory
(below), there is a coercion from a prime integer p to the prime ideal
(p), at least in the envisioned situation. There are other rings,
typically polynomial rings, where there is an algorithm to detect
prime ideals (using a primary decomposition algorithm and for these
rings, the residue class ring can also be constructed).
Analogy:
PolynomialComputation: Category == CommutativeRing with {
polyomialRing: (v:List Symbol) > POLYCAT(v, %)
There is really no need for the map polynomialRing because it
encapsulates a domain constructor, which must be implemented for each
instance of v and R. Examples of this map polynomialRing in action
are:
DMP(v,R): POLYCAT(v,R)
HDMP(v,R): POLYCAT(v,R)
Each of these domain constructor is equivalent to an instance of the
map polynomialRing and therefore, a domain of the category
PolynomialComputation.
************
So any domain satisfying Modular computation is a CommutativeRing R,
which exports a function which takes a representative p of R and
returns something which satisfies ResidueClassRing(R,p).

ResidueClassRing(R: CommutativeRing, p: R): Category ==
CommutativeRing with {
modularRep: R > %;
canonicalPreImage: % > R;
if R has EuclideanDomain then {
symmetricPreImage: % > R;
if R has SourceOfPrimes and prime?(p)
then Field;
} }

=========
Paraphrase:
A ResideClassRing S is constructed from a base commutative ring R and
a prime ideal p of R. It is a commutative ring with these operations:
modularRep : R > S
canonicalPreImage: S > R
if R is a Euclidean domain, then there are more operations:
symmetricPreImage: S > R
if we know the prime ideals of R, and p is a prime ideal,
then S is a field
ResidueClassRing is a category constructor because there may be
several representations of S, given one R and one prime ideal p of R.
In order to perform this construction, we would need to have
constructed already Ideal(R), the domain of ideals of R, and a
function that can decide whether a given ideal is prime or not. The
localization construction is already in Axiom (the FRAC constructor is
a special case where the prime ideal is (0)). The modulo operation is
available for polynomial rings using Groebner basis method (in
PolynomialIdeal), and of course also for Integer using plain old
division. These two are the most important examples. For this
discussion, the ifclauses are not relevant.
Analogy:
POLYCAT(v: List Symbol, R: CommutativeRing):Category ==
CommutativeRing with {
coerce: R > %;
retract: % > R;
...
}
**********
Here we use the notion of SourceOfPrimes until someone figures out a
meaningful way to represent a MaximalIdeal generally:).
Aldor has an IntegerCategory, roughly:

IntegerCategory: Category ==
Join(IntegerType, CharacteristicZero, EuclideanDomain,
ModularComputation, SourceOfPrimes,
GeneralExponentCategory, Specializable,
Parsable) with {
...
default {
residueClassRing(p:%):ResidueClassRing(%, p) ==
IntegerMod(%,p);
...
} }

=========
Paraphrase
A domain R of category IntegerCategory is a Euclidean domain of
characteristic zero, etc., where we know the prime ideals, and we know
how to construct a ResidueClassRing S given any prime ideal p in R.
A default way to construct S is via IntegerMod(R, p) when R is an
IntegerCategory domain. The construction IntegerMod(R, p) is assumed
known and efficient. This default construction does not really apply
always, for example, when R is a polynomial ring. But this is outside
the scope of the current discussion.
Analogy:
PolynomialConstructable: Category ==
Join( ...) with {
default {
polynomialRing(v:List Symbol): POLYCAT(v,%) == DMP(v, %);
...
} }
**********
And IntegerMod is an efficient implementation:

IntegerMod(Z:IntegerCategory, p:Z):ResidueClassRing(Z, p) == add {
... }

=========
Paraphrase:
IntegerMod is a domain constructor that is actually implementable
because we supposedly know how to construct the residue class ring for
a domain R (or Z) of the IntegerCategory and a prime ideal p of R.
IntegerMod represents ONE way of construction for S:= (R_p)/(p R_p).
Analogy:
DMP (DistributedMultivariatePolynomial) is a domain constructor in
Axiom that implements a polynomial ring with coefficient ring R and a
list of indeterminates v. It uses the pure lexicographic ordering on
monomials.
DMP(v:List Symbol, R: Ring): POLYCAT(v,R) == Join(...) add ...
It may serve as the default constructor. Other constructors use other
term orderings, for example HDMP or GDMP.
Here POLYCAT(v,R) is a specialization of an actual category
constructor from Axiom, except I have abbreviated the parameter set in
this analogy. The full macro expansion is
POLYCAT(v,R) ==> PolynomialCategory(R,_
Direct Product(#(v),NonNegativeInteger),_
OrderedVariableList(v))
Axiom Version:
IntegerMod(R, p): T == C where
R: IntegerCategory
p: Ideal(R)
T == ResidueClassRing(R, p)
C == add { ... }
*********
Assuming this type of stuff is implemented in the library where it is
needed we can write very generic functions:

Foo(R: ModularComputation): with { ... } == add {
bar(r: R, p:R): R == {
elem : ResidueClassRing(R, p) :=
modularRep(r)$residueClassRing(p)
 hairy computation...
canonicalPreImage(elem)
} }

========
Paraphrase:
Foo is a package for a ModularComputation domain R, with a function
bar: (R, R) > R and the function bar is implemented as:
bar(r,p) ==
compute the elem:= modularRep(r) in S
 S is the ResidueClassRing for R and p.
compute some other things
 (which may or may not change elem, but
 presumably elem remains in S
return canonicalPreImage(elem) in R
or the function bar may be bar: (R, p:R) > S(p) if it returns elem.
Analogy:
The function bar is just a suppedup version of Martin's example:
g(n,k) == (k mod n):PrimeField(n)  assuming n is prime
so it can be implemented in Axiom. The mod function is the coerce
function in PrimeField(n)
coerce: PositiveInteger > PrimeField(n)
So similarly, the modularRep(r) function is a function in S
modularRep: R > S
is similar to a coercion from R to S and the canonicalPreImage is a
function from S to R similar to a retract:S > R.
Axiom version:
Foo(R,p,S): T == C where
R: ModularCategory
p: Ideal(R)
S: ResidueClassRing(R,p)
Q ==> any domain constructed from R, p, S
T == with
bar: R > Q
C == add
bar(r)==
elem:S:=modularRep(r)$S
 hairy computations
q:Q:= ...
Calling sequence in some other package, assuming R, p, S are already
defined:
bar(r)$Foo(R,p,S)
If you want to use the default implementation when R is a domain in
IntegerCategory, you can use:
if R has IntegerCategory then
S:=IntegerMod(R,p)
bar(r)$Foo(R,p,S)
Below are just some random notes (my tosses and turns):
Note here S is typically defined using one of the constructors. If
the map residueClassRing(p) exists, then there will be a corresponding
domain constructor in Axiom. The advantage of using residueClassRing
is that we can use ONE name for all the constructors for ALL rings R,
even if these constructions depend on R (but uniform on p).
OVERLOADING and S does not have to appear as a parameter because we
don't care how S is constructed. It is cleaner and corresponds to the
mathematics by ignoring the data representation or implementation. On
the other hand, by tagging S along in the package, we can use special
features in the construction of S in the computation (not really, S is
given categorically: Example, in GroebnerBasis, we tag along S, the
Dpol, but since Dpol is just PolynomialCategory based on the other
parameters, we don't know more. However, in actual computation,
calling groebner for example, the implementation of Dpol will come
into action. It makes no difference to let R be a ModularComputation
because then the implementation is residueClassRing(R,p), so by
specifying R: ModularComputation, we are singling out the
implementation, just like when we input Dpol. So ModularComputation
is only a wrapper. In Steve's example, each time you need functions
from S, you have to make a function call to residueClassRing(R,p),
unless, you assign S to it. So it is only a wrapper!
********
All of this depends on the fact that we can express a dependently
typed function residueClassRing(p:R), which can be implemented by any
given domain as appropriate. The Foo package knows all it needs to,
the Ring, and an element of the ring to get at the the quotient ring.
Of course, the bar function above could be more complex and return an
element of ResidueClassRing(R,p), etc.
How could one write the bar()$Foo above with the current axiom
language? All you can do is write a package/domain parameterized by a
commutative ring R and a representative of R, and write the exports
dependently on R's type via `if R has ...' constructs. This is what I
meant in the previous email about having a RESCLASS package/domain
which needed to know too much about the algebra.
=======
see discussion on top of email
*******
\end{verbatim}
\section{email 5}
\begin{verbatim}
> Just to be clear on my criticism: I am *not* against the use
> of dependent types as such. I just think that we should not
> call something that has dependent types a *function*. I think
> the Aldor notation risks confusion on a very fundamental
> mathematical issue. Axiom's spad language design make it clear
> that what Martin wants is really a *functor* (as you explained
> very clearly in your previous message  thank you!) Functors
> have a description (I dare not call it a "signature") which
> is more complex than a function. I think it is natural that
> Axiom's notation makes a clear distinction.
I think something like F(a:A)==F(a):B(a) should simply be called a program or
routine! It is neither a function nor a functor in the strict mathematical
sense.
> Is there a way that this "Aldor function" can be written
> in Aldor that syntactically respects the same distinction?
> If so, then perhaps we should just consider the way Aldor
> allows this to be written as a kind of abbreviation that
> happens to look like the notation for a function.
I think Aldor treats the two levels equally, that is, domain constructors and
"function" are the treated the same. Axiom does not and restricts "function" to
a real mathematical function while leaving domain (or even category and package)
constructors a bit more general by allowing dependent signatures. This allowed
dependence is even more general than F(a:A)==F(a):B(a), for example, one can
have F(a:A,b:B(a),c:C(a,b))==F(a,b,c):D(a,b,c). Such dependence is not allowed
for functions in Axiom but allowed in Aldor. In other words, the source does not
have to be "rectangular" but can be any "area" (or "solid") with bounding
"curves" ("surfaces"). Metaphorically, Aldor allows integration over any solid,
Axiom only over a cuboid. If you think about this calculus analogy, you can see
that Aldor is a much more powerful language.
> BTW, chapters 11 Packages, 12 Categories and 13 Domains of the
> Axiom book are very useful but I find the orientation rather
> confusing  perhaps it is just the "age" of the terminology
> that is used in these chapters that makes reading a little hard.
> I think it would be great if these could be rewritten in a
> more modern "categorical" manner similar to the way you wrote
> your previous message. Are there any papers that you could
> reference that attempt to do this? Is there some corresponding
> part of the Aldor documentation that would be useful for me
> to reread?
Well, I tried to look up something from the web for my email on functors, and I
got a nice one for you:
http://math.ucr.edu/home/baez/categories.html
Actually, I was attempting to explain why something like Integer is a category
and I remembered that category theorist think of a group as a category but
forgot how. The above article explains that. But applying the same to Axiom
does not work! Try it.
\end{verbatim}
\section{email 6}
\begin{verbatim}
There is something called the "addchain formed by domain
extensions" which is described in the Glossary of the Axiom
book:
"addchain
a hierarchy formed by domain extensions. If domain A extends
domain B and domain B extends domain C, then A has addchain
BC."
and
"domain extension
a domain constructor A is said to extend a domain constructor B
if A's definition has the form A == Badd.... This intuitively
means "functions not defined by A are assumed to come from B."
Successive domain extensions form addchains affecting the
search order for functions not implemented directly by the
domain during dynamic lookup.
"dynamic lookup
In Axiom, a domain may or may not explicitly provide function
definitions for all its exported operations. These definitions
may instead come from domains in the addchain or from default
packages. When a function call is made for an operation in the
domain, up to five steps are carried out.
1. If the domain itself implements a function for the operation,
that function is returned.
2. Each of the domains in the addchain are searched; if one
of these domains implements the function, that function is
returned.
3. Each of the default packages for the domain are searched in
order of the lineage. If any of the default packages implements
the function, the first one found is returned.
4. Each of the default packages for each of the domains in the
addchain are searched in the order of their lineage. If any
of the default packages implements the function, the first
one found is returned.
5. If all of the above steps fail, an error message is reported.

\end{verbatim}
\section{email 7}
\begin{verbatim}
Bill Page wrote:
>
> William,
>
> I think these are great examples with which to examine
> some fundamental ideas in Axiom!
You are absolutely correct that we need to analyse these ideas. In trying to
explain below these fundamental ideas, I discover how vague my "understanding"
was (and probably still is). You raised many good questions. This will be a
rather long analysis.
> On Thursday, January 13, 2005 2:56 AM you wrote:
> >...
>
> > %PointedPrimeField
> > )abbrev domain PPF PointedPrimeField
> > PointedPrimeField(n:PositiveInteger):Cat==Dog where
> > Cat == FiniteFieldCategory with
> > foo:PositiveInteger>PrimeField(n)
> > Dog == PrimeField(n) add
> > foo(k)==k::Integer::PrimeField(n)
> >
> > After compiling, define in the interpreter
> >
> > g(n,k)==foo(k)$PPF(n)
> >
> > Compiling g is still a problem in Axiom due to signature
> > limitation. At least this way, inlining a complicated
> > function is almost like a function call.
> >
>
> From a mathematical point of view I think this "signature
> limitation" in Axiom is natural and that Aldor goes too
> far in allowing a construction like
>
> g(n:Integer,k:Integer):PrimeField(n)
>
> when defining functions. The reason is that I do not see
> how it is possible to interpret PrimeField(n) as a domain
> in the normal ("categorical") sense, in this context where
> the value of n is not known.
Martin Rubey wrote:
\ I agree that the limitation looks natural. However, if you
\ look closer at Aldors design, it couldn't be clearer.
I'll argue that the limitation is not natural.
If all objects are first class (whatever that means), then there is not much
difference (syntactically speaking, except on a different level) between the two
*signatures*:
g(n:Integer,k:Integer):PrimeField(n)
and
DMP(v:List Symbol, R: Ring):_
PolynomialCategory(R,_
Direct Product(#(v),NonNegativeInteger),_
OrderedVariableList(v))
The returned type in each case depends on the parameter(s). In each case, the
target category (we'll see how later) depends on input parameters (not just the
constructed object): for DMP, the target category depends on R, v and for g, it
depends on n. So it is entirely logical to allow the signature of g in Aldor.
But these do not spell out the codomain (target) in the sense of a mathematical
function. Both would present a problem. On first glance, it seems the
*signature* of PPF is
PPF(n:PositiveInteger):FiniteFieldCategory
and its codomain does not depend on parameters and so as a mathematical
function,
PPF: PositiveInteger > FiniteFieldCategory
is ok. But actually, the correct *signature* of PPF is
PPF(n:PositiveInteger):FiniteFieldCategory with_
foo: PositiveInteger > PrimeField(n)
so, it too, has a problem. All the functions (exports in Axiom jargon) in
PolynomialCategory are simply hidden in its category definition. We did not
create one for FiniteFieldCategory with foo. If we did, we would come up with
the same dependency.
So in what sense are domain constructors and functions functors?
A functor must describe two things: how to map the objects, and how to map the
morphisms, of the source category. So the first question is: what are the
objects and morphisms in Axiom "categories"?
Take the source of DMP (DMP is a typical domain constructor). It is a direct
product of an Axiom domain: List Symbol, and an Axiom category: Ring. DMP maps
an element (v,R) in this direct product to another Axiom domain which belongs to
the Axiom category POLYCAT (used here to stand for the longer, parametrized,
category PolynomialCategory). So, is (v,R) an object of some category, or is it
a morphism? It would seem that it should be an object and indeed I believe it
is. The source of DMP is a category whose objects are pairs (v,R) and whose
morphisms are pairs of maps (f,h), where f:v >v' is a set map, and h: R > R' a
ring homorphism. There is a (more general) package called
PolynomialCategoryLifting, with a function named map that, when applied to the
DMP situation, would take a morphism
(f,g): (v,R) > (v', R')
and "lift" this to a morphism of DMP(v,R) > DMP(v',R'), thus providing the
mapping of DMP on morphisms.
Now what about the function g above? How is it a functor?
The source of g is the direct product
PositiveInteger x PositiveInteger.
If its objects are pairs (n,k) of positive integers, then what are the morphisms
between them? It would seem that there is exactly one obvious "morphism" between
two pairs. The map g takes (n,k) to an element in PrimeField(n). So we must
treat PrimeField(n) itself as a category. Its objects would be numbers modulo n
(elements of the prime field) and again, there is only one obvious morphism
between two objects. But notice that this is only on the set level. The
algebraic structure of PrimeField(n) is totally neglected when we viewed it as a
category this way. Given this setting, g((n,k)) = k mod n, and g((n,k)>(n',k'))
= (k mod n)>(k' mod n').
But are these really functors in the mathematical sense? Not yet. The problem is
in the target category. In mathematics, a functor has the form F: A > B or
F(a:A)==F(a):B, where both A and B are categories, and B does not depend on any
particular object of A. A functor consists of a bunch of mathematical set
mappings (objects of A to objects of B, Hom(X,Y) to
Hom(F(X),F(Y))). In Axiom's functors, B may depend (and often does) on the
parameters from A. So it has the form
F(a:A)==F(a):B(a). You may say this generalizes the usual notion of a functor.
But that neglects the morphisms! In axiom, F seldom explicitly says what
F(a>a') is, because, it would have to be a morphism in a category between F(a)
and
F(a'). But F(a) and F(a') belong to two different categories
B(a) and B(a'), respectively, and you really cannot talk about morphisms between
objects in different categories except in very special cases when both
categories B(a) and B(a') are subcategories of a category C.
So back to my previous analysis on DMP. There, I actually made a mistake by
being careless (I deliberately left it the way it was). I should have used
POLYCAT(v,R) (not in correct Axiom syntax, but used to stand for the longer,
parametrized, category PolynomialCategory based on v and R given in the
*signature* of DMP above) instead of POLYCAT. Then I would have noticed that we
need to put the Ralgebra
DMP(v,R) and the R'algebra DMP(v',R') into one category.
This can be done if all R:Ring are of the same characteristic, say zero. We can
then consider these as Zalgebras (Z = Ring of integers) and the map
DMP(v,R)>DMP(v',R') would be a Zalgebra morphism. But DMP(v,R) has more
structure, for example, it is an Ralgebra, and in fact the lift map is an
Ralgebra homomorphism too (via the map h:R>R', R' becomes an
Ralgebra). So, just as in the case of the function g, where we forget about
some structure of PrimeField(n), we must forget about the some algebraic
structures of DMP(v,R).
Conclusion, if my analysis is correct: In Axiom, domain constructors are
functors into the category Set, and perhaps subcategories in some cases. Viewed
this way, there is no dependence on input parameters in the target category.
Computationally, we of course want to keep track of which subcategory the
domains are and it would be nice to allow that in the signature, not just of
domain constructors, but for functions.
To paraphrase a famous quote: There is no such thing as a simple explanation.
> Of course from a programming point of view we do know how
> to interpret the Aldor construction and apparently Aldor
> knows how to compile it. But I do not think that this
> necessarily makes it desirable in a language that is
> primarily intended to be efficient and accurate in the
> definition of mathematical concepts.
> > The idea is: Since in creating domains, we are in effect
> > creating a function (the domain constructor PPF is a
> > function of sort, or functor) and the compiler can
> > take dependent types in its signature, structurally:
> > PPF(n:PositiveInteger)==PrimeField(n) with foo so it
> > should be able to compile something like g by lifting
> > it to the package level.
>
> Yes! I think you are exactly right. And it is politically
> correct from the Axiom perspective to refer to this
> construction as a "functor". I think it is a *good thing*
> that Axiom's syntax encourages one to make this distinction.
See above.
Martin Rubey wrote:
\ Well, if it would be only encouragement... However, there
\ is no way to do it differently! I'm sure it is not too
\ difficult to come up with an example where the solution
\ above won't work.
In terms of the function computations, I think both the domain version and the
package version would suffice  not as convenient as it would be, but these
will work. The only situation I can think of that will be a problem is where the
signature of the function is actually needed (meaning, written down). An example
would indeed be interesting.
\ There is another, different point I'd like to make:
\
\ Aldor has been designed to be "cleaner" than Axioms internal
\ language. Not that much has changed, it seems that they were
\ very careful, and it's quite certain that these were very
\ clever people. I think it would be wiser to adopt Aldor
\ (which won't break much) rather than to try to extend Axioms
\ own language and let the two languages diverge. I simply
\ don't see the point.
The problem is that Aldor has implemented only a small fraction of the algebra
code in Axiom. Didn't someone just mentioned that PositiveInteger is not in
Aldor? (May be that is good, trust the programmers and get rid of a lot of
needless coercions).
> >
> > So here is another way using package.
> >
> > %Foo
> > )abbrev package FOO Foo
> > Foo(n:PositiveInteger, k:PositiveInteger):T==C where
> > T == with
> > point:()>PrimeField(n)
> > C == add
> > point()==k::Integer::PrimeField(n)
> >
> > After compiling, we can use
> >
> > point()$Foo(n,k)
> >
> > in any computation in compiler code (and in interpreter).
> > Still can't call this g(n,k) unless you use a macro
> > expansion:
> >
> > g(n,k)==>point()$Foo(n,k)
> >
>
> The use of a macro is ok because no signature is implied.
The above macro is not that good, because you cannot replace n or k by
expressions.
> I think I prefer your first construction to the latter
> because it is nice to think conceptually of foo(k) as
> belonging to each of the PPF(n) domains, i.e. for each n.
> Thinking of Foo(n,k) as a collection of "domains"
> parameterized by n and k; and point() as belonging to
> each such domain seems a little unnatural. Well I guess,
> because Foo is a package ... Packages are for convenient
> programming, not mathematical relationships.
Isn't it nice to have two ways? :)
But I think the package version mirrors the original function g(n,k) better
because it use the same syntax, except that g is replaced by point()$Foo, and
one can replace n and k by expressions. I was avoiding the macro
g ==> point()$Foo
and used
bar ==> point()$Foo
to avoid replacing all "g" in a program!
Bill Page wrote:
> See
>
> http://page.axiomdeveloper.org/zope/mathaction/DynamicFunctionDomains#msg20
> address@bogus.example.com
>
> but notice that your use of the macro near the end produces
> and error.
>
> > bar ==>point()$Foo
> >
> > Type: Void
> >bar(4,7)
> > Although Foo is the name of a constructor, a full type
> >must be specified in the context you have used it. Issue
> >)show Foo for more information.
>
> It appears to be trying to evaluate bar before concatonation
> with `(4,7)'.
You are right. The same happens with the compiler.
bar(4,7)
would be parsed as
((elt Foo point)) n k
but should be
((elt (Foo n k) point))
Anyway, there is little saving to use a macro except that it looks more like the
original function. So the following works:
)abbrev package BARTEST Bartest
Bartest: T==C where
T == with
barrun: () > Void
C == add
import FOO
barrun() ==
for k in 4..5 repeat
for n in [1,2,4,6]::List PositiveInteger repeat
print(point()$Foo(n+1,k)::OutputForm$PrintPackage
barrun()
The point is, it is compilable.
> I suppose what I am trying to say is that in the design
> of the Axiom language we should be aware not only of
> programming issues but also conceptual mathematical issues.
Agreed with no reservations.
\end{verbatim}
\section{email 8}
\begin{verbatim}
On Fri, Jan 14, 2005 at 12:10:45PM +0100, Martin Rubey wrote:
> Bill Page writes:
>
> > From a mathematical point of view I think this "signature limitation" in
> > Axiom is natural and that Aldor goes too far in allowing a construction
> like
> >
> > g(n:Integer,k:Integer):PrimeField(n)
> >
> > when defining functions. The reason is that I do not see how it is possible
> > to interpret PrimeField(n) as a domain in the normal ("categorical") sense,
> > in this context where the value of n is not known.
>
> I agree that the limitation looks natural. However, if you look closer at
> Aldors design, it couldn't be clearer.
I agree here with Martin. In my experience with aldor, the use of
dependent typing is very practical, very `close' to the math. It is
essential in many algorithms to move from one computational domain to
another which depends upon a result calculated at runtime. If you cant
write foo(n:INT):PrimeField(n), then programmers will define functions
like mod_+(arg1:INT,arg2:INT,modulus:INT):INT and throw away the
mathematical meaning of their types. Might as well be programming in
C ( almost :).
> > > should be able to compile something like g by lifting it to the package
> > > level.
>
>
> > Yes! I think you are exactly right. And it is politically correct from the
> > Axiom perspective to refer to this construction as a "functor". I think it
> > is a *good thing* that Axiom's syntax encourages one to make this
> > distinction.
Lifting everything to the package level is an example of how one will
rapidly diverge from the math. For example, what if instead of a
functor `PPF(n:PositiveInteger)==PrimeField(n) with ...' we want
something more general, like, say, given any commutative ring R and a
maximal ideal M in R we want the quotient field R/M. In a package
like:
RESCLASS(R: CommutativeRing, M: MaximalIdeal(R)): Field with ...
RESCLASS is going to need to know about *every* commutative ring in
the algebra. If R is the integers, and M a prime < 2^32, then it needs
to know the field can be represented as machine integers, for example.
But with dependent typing one can achieve this generality, since the
required function is a categorical export, which each individual
domain satisfies in its own way. It becomes possible to write
extraordinarily generic algorithms given such a language facility.
> Aldor has been designed to be "cleaner" than Axioms internal language. Not
> that
> much has changed, it seems that they were very careful, and it's quite certain
> that these were very clever people. I think it would be wiser to adopt Aldor
> (which won't break much) rather than to try to extend Axioms own language and
> let the two languages diverge. I simply don't see the point.
>
> A different issue is whether we can live with the fact, that Aldor does not
> seem to be entirely free. I don't know how to get it's source. Therefore I'd
> argue to make changes to Axioms compiler in a way that makes it *more*
> compatible with Aldor. In fact, for the time being, I wouldn't make any
> changes, however, I could imagine to post a challenge to comp.lang.lisp to
> extend Axioms compiler to become Aldor  in common lisp. There are very
> clever
> people out there, maybe we can get them interested.
Personally, the issue of aldors licence is a show stopper. Trying to
make axioms spad compiler compatible with a closed system will be
futile. Maintaining compatibility with a moving target is always hard,
let alone one you cant see.
I do think a new compiler/language is something the Axiom project
should aim for, but as a long term goal. I believe we should be trying
to lift all of the things which both spad and aldor can teach us, and
think about how we can incorporate more modern ideas in programming
language design. Integration with theorem provers will likely demand
compiler support. `indeterminate objects' have been discussed before,
and we can probably learn a lot about how to implement such structures
by studying the work which has been done in `lazy evaluation'. The
very design of axioms algebra seems to demand a language which
supports recursive structures. None of these things exist in spad or
aldor.
A new compiler will likely take years to write. We should not forget
the spad compiler. We should learn as much as we can from it  and in
the process help maintain, improve, and document it.
\end{verbatim}
\section{email 9}
\begin{verbatim}
I think these are great examples with which to examine
some fundamental ideas in Axiom!
On Thursday, January 13, 2005 2:56 AM you wrote:
>...
> %PointedPrimeField
> )abbrev domain PPF PointedPrimeField
> PointedPrimeField(n:PositiveInteger):Cat==Dog where
> Cat == FiniteFieldCategory with
> foo:PositiveInteger>PrimeField(n)
> Dog == PrimeField(n) add
> foo(k)==k::Integer::PrimeField(n)
>
> After compiling, define in the interpreter
>
> g(n,k)==foo(k)$PPF(n)
>
> Compiling g is still a problem in Axiom due to signature
> limitation. At least this way, inlininga complicated
> function is almost like a function call.
>
>From a mathematical point of view I think this "signature
limitation" in Axiom is natural and that Aldor goes too
far in allowing a construction like
g(n:Integer,k:Integer):PrimeField(n)
when defining functions. The reason is that I do not see
how it is possible to interpret PrimeField(n) as a domain
in the normal ("categorical") sense, in this context where
the value of n is not known.
Of course from a programming point of view we do know how
to interpret the Aldor construction and apparently Aldor
knows how to compile it. But I do not think that this
necessarily makes it desirable in a language that is
primarily intended to be efficient and accurate in the
definition of mathematical concepts.
>
> The idea is: Since in creating domains, we are in effect
> creating a function (the domain constructor PPF is a
> function of sort, or functor) and the compiler can
> take dependent types in its signature, structurally:
> PPF(n:PositiveInteger)==PrimeField(n) with foo so it
> should be able to compile something like g by lifting
> it to the package level.
Yes! I think you are exactly right. And it is politically
correct from the Axiom perspective to refer to this
construction as a "functor". I think it is a *good thing*
that Axiom's syntax encourages one to make this distinction.
>
> So here is another way using package.
>
> %Foo
> )abbrev package FOO Foo
> Foo(n:PositiveInteger, k:PositiveInteger):T==C where
> T == with
> point:()>PrimeField(n)
> C == add
> point()==k::Integer::PrimeField(n)
>
> After compiling, we can use
>
> point()$Foo(n,k)
>
> in any computation in compiler code (and in interpreter).
> Still can't call this g(n,k) unless you use a macro
> expansion:
>
> g(n,k)==>point()$Foo(n,k)
>
The use of a macro is ok because no signature is implied.
I think I prefer your first construction to the latter
because it is nice to think conceptually of foo(k) as
belonging to each of the PPF(n) domains, i.e. for each n.
Thinking of Foo(n,k) as a collection of "domains"
parameterized by n and k; and point() as belonging to
each such domain seems a little unnatural. Well I guess,
because Foo is a package ... Packages are for convenient
programming, not mathematical relationships.
I suppose what I am trying to say is that in the design
of the Axiom language we should be aware not only of
programming issues but also conceptual mathematical issues.
\end{verbatim}
\section{email 10}
\begin{verbatim}
> %PointedPrimeField
> )abbrev domain PPF PointedPrimeField
> PointedPrimeField(n:PositiveInteger):Cat==Dog where
> Cat == FiniteFieldCategory with
> foo:PositiveInteger>PrimeField(n)
> Dog == PrimeField(n) add
> foo(k)==k::Integer::PrimeField(n)
>
> After compiling, define in the interpreter
>
> g(n,k)==foo(k)$PPF(n)
>
> and it works (in Axiom)! (Do not declare the types for g because n is not
> defined).
I meant in the interpreter. Compiling g is still a problem in Axiom due to
signature limitation. At least this way, inlining a complicated function is
almost like a function call.
The idea is: Since in creating domains, we are in effect creating a function(the
domain constructor PPF is a function of sort, or functor) and the compiler can
take dependent types in its signature, structurally:
PPF(n:PositiveInteger)==PrimeField(n) with foo
so it should be able to compile something like g by lifting it to the package
level.
So here is another way using package.
%Foo
)abbrev package FOO Foo
Foo(n:PositiveInteger, k:PositiveInteger):T==C where
T == with
point:()>PrimeField(n)
C == add
point()==k::Integer::PrimeField(n)
After compiling, we can use
point()$Foo(n,k)
in any computation in compiler code (and in interpreter). Still can't call this
g(n,k) unless you use a macro expansion:
g(n,k)==>point()$Foo(n,k)
\end{verbatim}
\section{email 11}
\begin{verbatim}
> Ralf,
>
> On Tuesday, January 18, 2005 12:22 PM you wrote:
> >
> > Do you find the attached file relevant?
> >
>
> 
>
> #include "aldor"
> #include "aldorio"
>
> define Parity: Category == with {
> parity: Integer > Boolean;
> }
>
> Odd: Parity == add {
> parity(n:Integer): Boolean == {
> (n>0) => parity(n1)$Even;
> (n<0) => parity(n+1)$Even;
> false;
> }
> }
>
> Even: Parity == add {
> parity(n: Integer): Boolean == {
> n>0 => parity(n1)$Odd;
> n<0 => parity(n+1)$Odd;
> true;
> }
> }
>
> main(): () == {
> import from Integer;
> stdout @<< "parity( 10)$Even=" @<< parity( 10)$Even @<< newline;
> stdout @<< "parity( 8)$Odd =" @<< parity( 8)$Odd @<< newline;
> stdout @<< "parity(1111)$Odd =" @<< parity(111)$Odd @<< newline;
> }
>
> main();
>
> 
>
> Yes I do find it very relevant. Thank you!
>
> I have tried for about 1/2 an hour without success to write
> this same category in Axiom. Perhaps someone with more
> experience with the Axiom compiler can help?
>
> > It actually compiles with Aldor 1.0.2 and runs with the output
> >
> > aldor grun laldor EvenOdd.as
> > parity( 10)$Even=T
> > parity( 8)$Odd =F
> > parity(1111)$Odd =T
> >
> > I wonder how the Aldor compiler handles such mutual recursive
> > structures. Perhaps Peter Broadbery knows.
>
> I would also like to know.
[Disclaimer: I'm not an expert on the type checking bit  and if you
want info, it is nicer to ask]
The key is that they are in the same file. Otherwise the compiler (at
least back in '9x) will complain that it does not know about the other
domain. The compiler will first determine the exports of mutually
referencing types, then compile the bodies  the aldor language is a bit
more careful than spad about what types are in scope (via import, etc)
so it can determine mutual references fairly easily. Within a file,
types are compiled in an order determined by the types each one uses,
not the textual order. Various langauge constructs (nested domains,
conditionals) make this a bit tricker, but apparently doable.
If you have a situation with mutually referencing domains in separate
files, then you have to use the extend keyword, and build the defn. up
in steps  there may well be an example or two of this in the aldor
library sources shipped with the compiler.
The problem then shifts to the cateogory level, which can't be
extended.
> >
> > Maybe this example is easy, because both domains are in the
> > same file> Do you know a good example where it makes sense
> > to put the domains much more away from each other?
>
> I can not give a simple example right now but I suspect that
> this happens very frequently in Axiom's algebra.
>
All over  try OutputForm as an example.
\end{verbatim}
\section{email 12}
\begin{verbatim}
\end{verbatim}
\end{document}