]>
Welcome to the world of Axiom. We call Axiom a scientific computation system: a self-contained toolbox designed to meet your scientific programming needs, from symbolics, to numerics, to graphics.
This introduction is a quick overview of what Axiom offers.
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 we would enter this into Axiom as:
which would give the result:
Axiom provides state-of-the-art algebraic machinery to handle your most advanced symbolic problems. For example, Axiom's integrator gives you the answer when an answer exists. If one does not, it provides a proof that there is no answer. Integration is just one of a multitude of symbolic operations that Axiom provides.
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 to 49 digits of accuracy. First we need to change the default output length of numbers:
and then we execute the command:
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 to the -th power in base ?
returns:
FMM3O955CSEIV0ILKH820CN3I7PICQU0OQMDOFV6TP000000000000000000
The AXIOM numerical library can be enhanced with a substantial number of functions from the NAG library of numerical and statistical algorithms. These functions will provide coverage of a wide range of areas including roots of functions, Fourier transforms, quadrature, differential equations, data approximation, non-linear optimization, linear algebra, basic statistics, step-wise regression, analysis of variance, time series analysis, mathematical programming, and special functions. Contact the Numerical Algorithms Group Limited, Oxford, England.
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 for .
Graphs in Axiom are interactive objects you can manipulate with your mouse. Just click on the graph, and a control panel pops up. Using this mouse and the control panel, you can translate, rotate, zoom, change the coloring, lighting, shading, and perspective on the picture. You can also generate a PostScript copy of your graph to produce hard-copy output.
HyperDoc presents you windows on the world of Axiom, offering on-line help, examples, tutorials, a browser, and reference material. HyperDoc gives you on-line access to this document in a ``hypertext'' format. Words that appear in a different font (for example, Matrix, factor, and category) are generally mouse-active; if you click on one with your mouse, HyperDoc shows you a new window for that word.
As another example of a HyperDoc facility, suppose that you want to compute the roots of 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 fig-intro-br and the specified mouse clicks, you and HyperDoc generate the correct command to issue to compute the answer.
Axiom's interactive programming language lets you define your own functions. A simple example of a user-defined function is one that computes the successive Legendre polynomials. Axiom lets you define these polynomials in a piece-wise way.
The first Legendre polynomial.
The second Legendre polynomial.
The -th Legendre polynomial for .
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 do no computation---they simply tell Axiom how to compute for some positive integer .
To actually get a value of a Legendre polynomial, you ask for it. Legendre polynomials
What is the tenth Legendre polynomial?
Axiom applies the above pieces for to obtain the value of . But it does more: it creates an optimized, compiled function for . The function is formed by putting the pieces together into a single piece of code. By compiled, we mean that the function is translated into basic machine-code. By optimized, we mean that certain transformations are performed on that code to make it run faster. For , 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 in ?
In general, a user function is type-analyzed and compiled on first use. Later, if you use it with a different kind of object, the function is recompiled if necessary.
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.
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 about ?
Series and streams make no attempt to compute all their elements! Rather, they stand ready to deliver elements on demand.
What is the coefficient of the -th term of this series?
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.
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.
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 command to describe the transformation rules you rule need. Then give the rules a name and apply that name as a function to your trigonometric expression.
Introduce two rewrite rules.
Apply the rules to a simple trigonometric expression.
Using input files, you can create your own library of transformation rules relevant to your applications, then selectively apply the rules you need.
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 .
Solve the system using rational number arithmetic and 30 digits of accuracy.
Solve with the solutions expressed in radicals.
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.
Users and system developers alike can augment the Axiom library, all using one common language. Library code, like interpreter code, is compiled into machine binary code for run-time efficiency.
Using this language, you can create new computational types and new algorithmic packages. All library code is polymorphic, described in terms of a database of algebraic properties. By following the language protocols, there is an automatic, guaranteed interaction between your code and that of colleagues and system implementers.
Axiom has both an interactive language for user interactions and a programming language for building library modules. Like Modula 2, Modula 2 PASCAL, PASCAL FORTRAN, FORTRAN and Ada, Ada the programming language emphasizes strict type-checking. Unlike these languages, types in Axiom are dynamic objects: they are created at run-time in response to user commands.
Here is the idea of the Axiom programming language in a nutshell. Axiom types range from algebraic ones (like polynomials, matrices, and power series) to data structures (like lists, dictionaries, and input files). Types combine in any meaningful way. You can build polynomials of matrices, matrices of polynomials of power series, hash tables with symbolic keys and rational function entries, and so on.
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 any field. Likewise a greatest common divisor can compute the ``gcd'' of two elements from any Euclidean domain. Categories foil attempts to compute meaningless ``gcds'', for example, of two hashtables. Categories also enable algorithms to be compiled into machine code that can be run with arbitrary types.
The Axiom interactive language is oriented towards ease-of-use. The Axiom interpreter uses type-inferencing to deduce the type of an object from user input. Type declarations can generally be omitted for common types in the interactive language.
So much for the nutshell. Here are these basic ideas described by ten design principles:
Basic types are called domains of computation, or, simply, domains. domain Domains are defined by Axiom programs of the form:
Each domain has a capitalized Name that is used to refer to the class of its members. For example, Integer denotes ``the class of integers,'' Float, ``the class of floating point numbers,'' and String, ``the class of strings.''
The ``...'' part following Name lists zero or more parameters to the constructor. Some basic ones like Integer take no parameters. Others, like Matrix, Polynomial and List, take a single parameter that again must be a domain. For example, Matrix(Integer) denotes ``matrices over the integers,'' Polynomial (Float) denotes ``polynomial with floating point coefficients,'' and 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 Exports part specifies operations for creating and manipulating objects of the domain. For example, type Integer exports constants and , and operations +, -, and *. While these operations are common, others such as odd?odd?Integer and bit?bit?Integer are not. In addition the Exports section can contain symbols that represent properties that can be tested. For example, the Category EntireRing has the symbol noZeroDivisors which asserts that if a product is zero then one of the factors must be zero.
The Implementation part defines functions that implement the exported operations of the domain. These functions are frequently described in terms of another lower-level domain used to represent the objects of the domain. Thus the operation of adding two vectors of real numbers can be described and implemented using the addition operation from Float.
Every Axiom object belongs to a unique domain. The domain of an object is also called its type. Thus the integer has type Integer and the string "daniel" has type String.
The type of an object, however, is not unique. The type of integer is not only Integer but NonNegativeInteger, PositiveInteger, and possibly, in general, any other ``subdomain'' of the domain Integer. A subdomain subdomain is a domain with a ``membership predicate''. PositiveInteger is a subdomain of Integer with the predicate ``is the integer ?''.
Subdomains with names are defined by abstract datatype programs similar to those for domains. The Export part of a subdomain, however, must list a subset of the exports of the domain. The Implementation part optionally gives special definitions for subdomain objects.
Domain and subdomains in Axiom are themselves objects that have types. The type of a domain or subdomain is called a category. category Categories are described by programs of the form:
The type of every category is the distinguished symbol Category. The category Name is used to designate the class of domains of that type. For example, category Ring designates the class of all rings. Like domains, categories can take zero or more parameters as indicated by the ``...'' part following Name. Two examples are Module(R) and MatrixCategory(R,Row,Col).
The Exports part defines a set of operations. For example, Ring exports the operations 0, 1, +, -, and *. Many algebraic domains such as Integer and Polynomial (Float) are rings. String and List (R) (for any domain ) are not.
Categories serve to ensure the type-correctness. The definition of matrices states Matrix(R: Ring) requiring its single parameter 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.
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 :
Line 1 declares the symbol to be a ring. Line 2 declares the type of in terms of . From the definition on line 3, produces 9 for and Integer. Also, produces for and Float. however fails since has type String which is not a ring.
Using symbolic domains, algorithms can be defined in their most natural or general setting.
Categories form hierarchies (technically, directed-acyclic graphs). A simplified hierarchical world of algebraic categories is shown below. At the top of this world is SetCategory, the class of algebraic sets. The notions of parents, ancestors, and descendants is clear. Thus ordered sets (domains of category 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.
Figure 1. A simplified category hierarchy.
A category designates a class of domains. Which domains? You might think that Ring designates the class of all domains that export , , +, -, and *. But this is not so. Each domain must assert which categories it belongs to.
The Export part of the definition for Integer reads, for example:
This definition asserts that Integer is both an ordered set and an integral domain. In fact, Integer does not explicitly export constants and and operations +, - and * at all: it inherits them all from ! Since IntegralDomain is a descendant of , Integer is therefore also a ring.
Assertions can be conditional. For example, Complex(R) defines its exports by:
Thus Complex(Float) is a field but Complex(Integer) is not since 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, 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 < might be used to denote lexicographic-comparison in an algorithm. However, it is wrong to use the same < with this definition of absolute-value: Such a definition for abs in Axiom is protected by context: argument is required to be a member of a domain of category OrderedSet.
In Axiom, facilities for symbolic integration, solution of equations, and the like are placed in ``packages''. A package 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 , you can do so with a package of the form:
where Exports specifies the solve operations you wish to export from the domain and the Implementation defines functions for implementing your algorithms. Once Axiom has compiled your package, your algorithms can then be used for any F: floating-point numbers, rational numbers, complex rational functions, and power series, to name a few.
The Axiom interpreter reads user input then builds whatever types it needs to perform the indicated computations. For example, to create the matrix using the command:
the interpreter first loads the modules Matrix, Polynomial, Fraction, and Integer from the library, then builds the domain tower ``matrices of polynomials of rational numbers (i.e. fractions of integers)''.
You can watch the loading process by first typing
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 * from Matrix is passed the matrix to compute . The function is also passed an environment containing that, in this case, is Polynomial (Fraction (Integer)). This results in the successive calling of the * operations from Polynomial, then from Fraction, and then finally from Integer.
Categories play a policing role in the building of domains. Because the argument of Matrix is required to be a Ring, Axiom will not build nonsensical types such as ``matrices of input files''.
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:
Users and system implementers alike use the Axiom language to add facilities to the Axiom library. The entire Axiom library is in fact written in the Axiom source code and available for user modification and/or extension.
Axiom's use of abstract datatypes clearly separates the exports of a domain (what operations are defined) from its implementation (how the objects are represented and operations are defined). Users of a domain can thus only create and manipulate objects through these exported operations. This allows implementers to ``remove and replace'' parts of the library safely by newly upgraded (and, we hope, correct) implementations without consequence to its users.
Categories protect names by context, making the same names available for use in other contexts. Categories also provide for code-economy. Algorithms can be parameterized categorically to characterize their correct and most general context. Once compiled, the same machine code is applicable in all such contexts.
Finally, Axiom provides an automatic, guaranteed interaction between new and old code. For example:
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.
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 sin, cos, etc).
An example of this might be to calculate the cosine of 2.45 (in radians). To do this one would type:
Before proceeding any further it would be best to explain the previous three lines. Firstly the text ``(1) -> '' 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 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 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:
but integer division isn't quite so obvious. For example, if one types:
a fractional result is obtained. The function used to display fractions attempts to produce the most readable answer. In the example:
the result is stored as the fraction 2/1 but is displayed as the integer 2. This fraction could be converted to type Integer with no loss of informatin but Axiom will not do so automatically.
To obtain the floating point value of a fraction one must convert ( conversions are applied by the user and coercions are applied automatically by the interpreter) the result to type Float using the ``::'' operator as follows:
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:
where ``%'' represents the previous result (not the calculation).
Although Axiom has the ability to work with floating-point numbers to a very high precision it must be remembered that calculations with these numbers are 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 round and 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 floating point number. To extract the fractional part of a floating point number use the function fractionPart but note that the sign of the result depends on the sign of the argument. Axiom obtains the fractional partof using :
To obtain the absolute value of a number the 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 sign function which rturns , , or depending on the sign of the argument.
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:
Some other functions that are quite useful for manipulating numerical values are:
Some simple infix and prefix operators:
Some useful Axiom macros:
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).
Expressions involving symbols are entered just as they are written down, for example:
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 Polynomial Integer which is used to represent polynomials with integer coefficients. Some other examples along similar lines are:
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 eval function which takes an expression as its first argument followed by a list of assignments. For example, to evaluate the expressions XDummy and {xyDummy} resulting from their respective assignments above we type:
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 %i macro to represent the square root of . Thus expressions involving complex numbers are entered just like other expressions.
The real and imaginary parts of a complex number can be extracted using the real and imag functions and the complex conjugate of a number can be obtained using conjugate:
The function factor can also be applied to complex numbers but the results aren't quite so obvious as for factoring integer:
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 digits can be called. The result returned by this function is the previous setting. For example, to find the value of to 40 digits we type:
As can be seen in the example above, there is a gap after every ten digits. This can be changed using the 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 . Two other functions controlling the appearance of real numbers are outputFloating and outputFixed. The former causes Axiom to display floating-point values in exponent notation and the latter causes it to use fixed-point notation. For example:
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 radix is used. The first argument of this function is the expression to be displayed and the second is the base to be used.
Rational numbers can be represented as a repeated decimal expansion using the decimal function or as a continued fraction using continuedFraction. Any attempt to call these functions with irrational values will fail.
Finally, partial fractions in compact and expanded form are available via the functions partialFraction and 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 compactFraction does the reverse:
To extract parts of a partial fraction the function nthFractionalTerm is available and returns a partial fraction of one term. To decompose this further the numerator can be obtained using firstNumer and the denominator with firstDenom. The whole part of a partial fraction can be retrieved using wholePart and the number of fractional parts can be found using the function numberOf FractionalTerms:
By using the type constructor PrimeField it is possible to do arithmetic modulo some prime number. For example, arithmetic module can be performed as follows:
The first example should be read as:
Let be of type PrimeField(7) and assign to it the value
Note that it is only possible to invert non-zero values if the arithmetic is performed modulo a prime number. Thus arithmetic modulo a non-prime integer is possible but the reciprocal operation is undefined and will generate an error. Attempting to use the PrimeField type constructor with a non-prime argument will generate an error. An example of non-prime modulo arithmetic is:
Note that polynomials can be constructed in a similar way:
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):
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.
Although Axiom will quite happily accept expressions that are longer than the width of the screen (just keep typing without pressing the 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 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:
The underscore symbol is an escape character and its presence alters the meaning of the characters that follow it. As mentions above whitespace following an underscore is ignored (the 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:
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 )spool). A comment begins with two dashes ``- -'' and continues until the end of the line. Multi-line comments are only possible if each individual line begins with two dashes.
Descriptions are the same as comments except that the Axiom compiler will include them in the object files produced and make them availabe to the end user for documentation purposes.
A description is placed before a calculation begins with three ``+++'' signs and a description placed after a calculation begins with two plus symbols ``+''. The so-called ``plus plus'' comments are used within the algebra files and are processed by the compiler to add to the documentation. The so-called ``minus minus'' comments are ignored everywhere.
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:
tells Axiom to use the ``/'' operator from the Float package to evaluate the expression . This does 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 sign operator is taken from the Float package but the result is of 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.