Chapter 18: Using Aldor with AXIOM
18.1 Using Aldor from within AXIOM
18.2 Summary of changes for conversion to Aldor
18.3 Conversion example: two packages
18.4 Conversion example: a domain
18.5 Language changes for AXIOM version 2
18.6 Changes for version 2 regarding types and the library
18.7 Using the AXIOM-to-Aldor translator
18.8 Changes made ot the interpreter language
18.9 Using free functions with AXIOM
18.10 Efficiency
18.11 Details of system commands
18.12 Using Aldor outside AXIOM for AXIOM
18.13 Fine print
Aldor programs can provide new domains, categories and packages for use in AXIOM. These are fully interoperable with existing code in the AXIOM library which was compiled with the old (pre-version 2.0) system compiler. Aldor domains may be passed to AXIOM constructors and vice-versa, and Aldor programs can refer to anything in the AXIOM library.
In this chapter we describe how to use
the Aldor compiler to extend the AXIOM library,
and how to use these extensions interactively within AXIOM.
We describe how to convert a file written for the old
AXIOM system compiler to one written in Aldor.
We also note some of the changes made to the AXIOM library
for version 2.0 and contrast some features of the AXIOM and
Aldor base libraries.
18.1 : Using Aldor from withing AXIOM
This section describes how to create and use Aldor programs within the AXIOM environment. These are the basic steps involved:
)compile mycode.as
Figure 18.1: "matops.as" -- Extending the AXIOM library
#include "axiom.as" #pile MatrixSymmetry(R:Field): with symmetricPart : Matrix R -> Matrix R ++ `symmetricPart(M)' returns a symmetric ++ matrix `S', computed as `(M + transpose M)/2'. ++ The difference `M - S' is antisymmetric. antisymmetricPart : Matrix R -> Matrix R ++ `antisymmetricPart(M)' returns an antisymmetric ++ matrix `A', computed as `(M - transpose M)/2'. ++ The difference `M - A' is symmetric. == add import from R, Integer symmetricPart(m: Matrix R): Matrix R == mt := transpose m inv(2::R) * (m + mt) antisymmetricPart(m: Matrix R): Matrix R == mt := transpose m inv(2::R) * (m - mt) |
Note that you need not exit and re-enter AXIOM every time you need to edit your code. If possible, have an editing window available so that you can switch back and forth between AXIOM and the editor while you debug.
There are several differences between the Aldor language and the language used in AXIOM Version 1. See section 18.2 for a summary of the differences which are likely to affect AXIOM-style programs.
figure 18.1 shows a simple Aldor program using the AXIOM library. This program illustrates an important point:
When you write source code that is intended to make use of or extend the AXIOM library you should include in your program the line:
#include "axiom.as"instead of:
#include "aldor.as"
The commands to compile and use this program
from an AXIOM session are shown in Figure 18.2.
Figure 18.2: Compiling and using an Aldor program within AXIOM
It is possible to use compiled Aldor code in subsequent AXIOM sessions.
To do this, use the )library system command
which updates the databases in your AXIOM session and ensures that your code
is automatically loaded when it is needed.
Continuing our example above, the compiled form of
mycode.as could be used within AXIOM by issuing:
These steps are shown for the matops.as program in figure 18.3
Figure 18.3: A precompiled Aldor program in a later AXIOM session
A number of input files giving examples of using Aldor with AXIOM
are distributed with version 2.0 of the AXIOM system.
These files are located in the ``input'' directory and may be listed,
on Unix, using the command
These files show how to compile, load and use Aldor code.
These input files can be run using the )read system command
as follows:
Chapter 23 contains a more significant
example of a package written in Aldor to extend the AXIOM library.
This program computes Hilbert functions for monomial ideals
(see section 23.21).
There are several ways to learn about what is in the AXIOM
library but the best way is probably to use the HyperDoc Browser. The
Browser is described within the AXIOM system documentation.
Several things happen ``under the covers'' in the above basic steps.
Section 18.11 describes what is going on in more
detail and gives more information about the options which are available.
18.2 : Summary of changes for conversion to Aldor
We summarize the differences which are you are likely
to encounter when converting a file
written for the old AXIOM library compiler to Aldor.
For more details, please
see section 18.5 and section 18.6.
This section is intended for people who have used
the AXIOM Version 1 library compiler.
Here, we do not touch upon any aspects of Aldor which have
no counterpart in the old language. For this, please refer to
part II.
18.3 : Conversion example: two packages
% axiom
Startin the Axiom Computer Algebra System
AIX Version 3.2 for IBM Risc System/6000
...
(1) -> )compile matops.as
Compiling AXIOM source code from file /home/smwatt/matops.as using
A# compiler and options
-O -Fasy -Fao -Flsp -laxiom -Mno-ALDOR_W_WillObsolete -DAxiom
Use the system command )set axiomxl args to change these options.
Compiling Lisp ource code from file ./matops.lsp
Issuing )library command for matops
Reading /home/smwatt/matops.asy
MatrixSymmetry is now explicitly exposed in frame frame0
MatrixSymmetry will be automatically loaded when needed from
/home/smwatt/matops
(1) ->m := matrix[[1/2,1/3],[1/4,1/5]]
+1 1+
|- -|
|2 3|
(1) | |
|1 1|
|- -|
+4 5+
Type: Matrix Fraction Integer
(2) ->s := symmetricPart m
+1 7 +
|- --|
|2 24|
(2) | |
|7 1 |
|-- - |
+24 5 +
Type: Matrix Fraction Integer
(3) ->a := antisymmetricPart m
+ 1 +
| 0 --|
| 24|
(3) | |
| 1 |
|- -- 0 |
+ 24 +
Type: Matrix Fraction Integer
(4) -> )quit
)library mycode
If necessary, you can qualify the filename with a directory, as in
)library /u/jones/apps/mycode
% axiom
Starting the Axiom Computer Algebra System
AIX Version 3.2 for IBM Risc System/6000
...
(1) -> )library matops
Reading /home/smwatt/matops.asy
MatrixSymmetry is now explicitly exposed in frame frame0
MatrixSymmetry will be automatically loaded when needed from
/home/smwatt/matops
(1) ->m := matrix[[1,2],[3,4]]
+1 2+
(1) | |
+3 4+
Type: Matrix Integer
(2) ->symmetricPart m
+ 5+
|1 -|
| 2|
(2) | |
|5 |
|- 4|
+2 +
Type: Matrix Fraction Integer
(3) -> )quit
)sys ls $AXIOM/../../src/input/axl-eg*.input
)read axl-eg1.input
Here is an example of a small package from the AXIOM library source file pdecomp.spad:
1 -- AXIOIM code from "pdecomp.spad" 2 3 )abbrev package PDECOMP PolynomialDecomposition 4 5 PolynominalComposition(UP: UnivariatePolynomialCategory(R), R: Ring): with 6 compose: (UP, UP) -> UP 7 8 == add 9 compose(g, h) == 10 r: UP := 0 11 while g ^= 0 repeat 12 r := leadingCoefficient(g)*h**degree(g) + r 13 g := reductum g 14 r
To convert this to an Aldor file, we only need to change ``^''Equals to ``~''Equals and to add declarations to the inner function compose. In addition, the )abbreviate command is not supported by the Aldor compiler. Finally, we must place the lines
#include "axiom.as" #pile
at the start of the file.
Here is the converted code:
1 -- New code 2 3 #include "axiom.as" 4 #pile 5 PolynomialComposition(UP: UnivariatePolynomialCategory(R), R: Ring): with 6 compose: (UP, UP) -> UP 7 8 == add 9 compose(g:UP, h:UP):UP == 10 r: UP := 0 11 while g ~= 0 repeat 12 r := leadingCoefficient(g)*h**degree(g) + r 13 g := reductum g 14 r
Now we will begin converting the second package in pdecomp.spad:
1 --Most AXIOM code from "pdecomp.spad" 2 3 PolynomialDecomposition(UP, F): PDcat == PDdef where 4 F:Field 5 UP:UnivariatePolynomialCategory F 6 NNI ==> NonNegativeInteger 7 LR ==> Record(left: UP, right: UP) 8 9 PDcat == with 10 decompose: UP -> List UP 11 decompose: (UP, NNI, NNI) -> Union(LR, "failed") 12 leftFactor: (UP, UP) -> Union(UP, "failed) 13 rightFactorCandidate: (UP, NNI) -> UP 14 PDdef == add 15 leftFactor(f, h) == 16 g: UP := 0 17 for i in 0.. while f ^= 0 repeat 18 fr := divide(f, h) 19 f := fr.quotient; r := fr.remainder 20 degree r > 0 => return "failed" 21 g := g + r * monmial(1, i) 22 g 23 ...
The variable i on line 17 was intended to be a AXIOMTypeNonNegativeInteger, so we declare it and that brings NNI into scope. On line 18, the AXIOMFundivide returns a record type. By again declaring fr to be a record type, we cause this type to be imported and this makes the record extraction operations available.
Because untagged unions are no longer supported, we convert AXIOMTypeUnion(UP, "failed") to AXIOMTypeUnion(value1:UP, failed:'failed'), allowing us to create union values using [ ] and extract them using .value1.
Here is a conversion of the preceding code to Aldor:
1 -- More new code 2 3 #include "axiom.as" 4 #pile 5 6 PolynomialDecomposition(UP:UPC F, F:Field): PDcat == PDdef where 7 UPC ==> UnivariatePolynomialCategory 8 NNI ==> NonNegativeInteger 9 LR ==> Record(left: UP, right: UP) 10 11 PDcat ==> with 12 decompose: UP -> List UP 13 decompose: (UP, NNI, NNI) -> Union(value1:LR, failed:'failed') 14 leftFacot: (UP, UP) -> Union(value1:UP, failed:'failed') 15 rightFactorCandidate: (UP, NNI) -> UP 16 PDdef ==> add 17 18 leftFactor(f:UP, h:UP):Union(value1:UP, failed:'failed') == 19 g: UP := 0 20 for i:NNI in 0.. while f ~= 0 repeat 21 fr:Record(quotient:UP, remainder:UP) := divide(f, h) 22 f := fr.quotient 23 f := fr.remainder 24 degree r > 0 => return [failed] 25 g := g ++ r * monomial(1, i) 26 [g] 27 ...
Note the use of [ ] to create union values in lines 24 and 26.
18.4 : Conversion example: a domain
Here is an example of how to convert a domain from AXIOM to Aldor. It is a piece of the definition of AXIOMTypeQuaternion from quat.spad:
1 -- AXIOM code from "quat.spad" 2 3 Quaternion(R:CommutativeRing): QuaternionCategory(R) == add 4 Rep := Record(r:R,i:R,j:R,k:R) 5 6 0 == [0,0,0,0] 7 1 == [1,0,0,0] 8 9 a,b,c,d : R 10 x,y : $ 11 12 real x == x.r 13 imagI x == x.i 14 imagJ x == x.j 15 imagK x == x.k 16 17 quatern(a,b,c,d) == [a,b,c,d] 18 ...
In order to translate this to Aldor, the following changes must be made:
Here is the converted code:
1 -- New code 2 3 #include "axiom.as" 4 #pile 5 Quaternion (R: CommutativeRing): QuaternionCategrory R == add 6 Rep == Record(r: R,i: R,j: R,k: R) 7 import from Rep 8 import from R 9 10 0:% == per([0,0,0,0]) 11 1:% == per([1,0,0,0]) 12 13 default a,b,c,d: R 14 default x,y: % 15 16 real (x:%):R == (rep x).r 17 imagI (x:%):R == (rep x).i 18 imagJ (x:%):R == (rep x).j 19 imagK (x:%):R == (rep x).k 20 21 quatern(a:R,b:R,c:R,d:R):% == per [a,b,c,d] 22 ...
Note that the default variable declarations are introduced by the
keyword default, and that each function definition must have
its arguments and return type declared.
18.5 : Language changes for AXIOM version 2
A source of possible confusion is that there are now three similar but different programming languages associated with AXIOM:
The language supported by the Aldor compiler is more general and consistent than that supported by the old AXIOM compiler. Over ten years of experience with the older language helped us produce a tighter, more powerful, and more elegant programming language.
For those who know these languages, the difference between the old AXIOM language and Aldor is similar to the difference between MAC Lisp and Scheme: the syntaxes are very similar, but the semantics of the new language are more uniform.
This section discusses in more detail the language-related items of section 18.2. It covers those language aspects necessary to convert programs for the old AXIOM compiler to programs in Aldor.
The Aldor compiler uses % to refer to the domain or category being defined while the AXIOM compiler used $ before Version 2. The AXIOM compiler present in Version 2 also uses %.
A sequence is a series of expressions evaluated in the order in which they appear, except as modified by control expressions such as break, break return, return iterate, and by iterate if-then-else constructions. if The value of a sequence is the value of the expression last evaluated in that sequence.
A sequence can be constructed in two ways:
Almost all of the AXIOM library written for the old compiler uses piling to create sequences. The Aldor compiler does not use piling unless you include the By default, the compiler uses the semicolon/braces method for creating sequences. This is code written using piling:
#pile mult!(a: Rep, b: Rep): Rep == x := a.real * b.real - a.imag * b.imag y := a.real * b.imag + a.imag * b.real a.real := x a.imag := y a
This is the same code written using braces and semicolons. Indentation has no effect here, other than to make the code easier to read.
mult!(a: Rep, b: Rep): Rep == { x := a.real * b.real - a.imag * b.imag; y := a.real * b.imag + a.imag * b.real; a.real := x; a.imag := y; a }
The Aldor language uses the default keyword instead of default add when defining category defaults. Here is a sample using default:
default { empty(): % == [ ]; map (f: S -> S, a:%): % == [f x for x in a]; map (f: (S,S)->S, a: %, b: %): % == [f(x,y) for x in a for y in b]; }
Here is the same sample as it would have been written for the old compiler (translating the ``$'' to ``%''):
add empty(): % == [ ] map (f: S -> S, a:%): % == [f x for x in a] map (f: (S,S)->S, a: %, b: %): % == [f(x,y) for x in a for y in b]
In fact, the Aldor compiler allows multiple default statements:
default empty(): % == [ ]; default map (f: S -> S, a:%): % == [f x for x in a]; default map (f: (S,S)->S, a: %, b: %): % == [f(x,y) for x in a for y in b];
The default keyword can also now be used to set default type declarations for function parameters. However, be warned that in some AXIOM code defaults are omitted.
default i : Integer f(i) == i - g(i,2)
Macro definitions in the Aldor language can be written with a macro/== form or with ==>:
macro SI == SingleInteger; NNI ==> NonNegativeInteger;
Only the second form is supported by the old compiler. Macros can also now be parameterized:
macro f(x,y) == x^2 - 2*y^2
Aldor introduces several new keywords or extended uses for existing keywords. Please read the sections in this document about the following terms and keywords:
Chapters 11, 12, and 13 of the book AXIOM: The Scientific Computation System by Jenks and Sutor are now largely obsolete. Use the information in this Aldor document for writing and compiling domain and category constructors.
Comments that document constructors and operations are now created in a slightly different way. If a line starts with three or more plus signs (``++'') then the comment belongs to the declaration or definition following the comments. If a line starts with just two plus signs then the comment belongs to the preceding declaration or definition. (This allows documentation comments to follow the semicolon.)
+++ String is the type of character strings for natural +++ language text. +++ +++ Author: Aldor library +++ Date Created: 1992-94 +++ Keywords: string, text extend String: BasicType with { new: (SingleInteger, fill: Character == space) -> %; ++ `new(n, c)' creates a new string filled ++ with `c' characters. ...
The first comment block is associated with AXIOMTypeString whereas the second block is associated with AXIOMFunnew. These comments can be viewed, for example, from within the HyperDoc Browser.
To ease the chore of upgrading your .spad files (old .as files (Aldor compiler), the )compile command has been given a )translate option. This invokes a special version of the old compiler which parses and analyzes your old code and produces augmented code using the new syntax. Please be aware that the translation is not necessarily one hundred percent complete or correct. You should attempt to compile the output with the Aldor compiler and make any necessary corrections. Please see section 18.7 for an example and more information.
Also, if you have any private .spad files (that is, library files
that were not shipped with AXIOM), you will need to
recompile them with the old system compiler to use them with this
version of AXIOM. For example, if you wrote the file
regress.spad, then you should issue )compile regress.spad
before trying to use it.
18.6 : Changes for version 2 regarding types and the library
The biggest difference you will find in converting files to Aldor is that you must be very explicit about which types are imported into the compilation scope. The old AXIOM compiler would automatically import types as it encountered them during the compilation process. The Aldor compiler will only import types appearing in declarations or in explicit import statements. In the previous example the only type in scope during the compilation of compose was the type UP. In fact not even AXIOMTypeInteger is automatically brought into scope. In Aldor, types are brought into scope only by explicit import statements or by appearing on the right hand side of import declarations.
Untagged unions are not supported by Aldor, thus all unions must be converted to tagged unions. This means that Union(Integer, Float) needs to become something like AXIOMTypeUnion(i:Integer, f:Float). The case statement requires the tag as its first argument, case thus you write x case i instead of x case Integer. Converting to and from tagged unions is essentially the same as with AXIOMTypeRecord types. To create a union value from one of its branches, you wrap the value in square brackets, thus [3.3] converts the float value ``3.3'' to a union value. Similarly, if x has type AXIOMTypeUnion(i:Integer, f:Float), x.i converts x to an Integer value taking a runtime error if x was in the other branch of the union (for more information on unions in Aldor see part II). Partial functions in old AXIOM were often declared as returning AXIOMTypeUnion(%, "failed"); by convention this is represented in Aldor as AXIOMTypeUnion(value1:%, failed: 'failed') (recall that 'failed' is syntactic shorthand for AXIOMTypeEnumeration(failed)).
The old AXIOM type AXIOMTypeVoid is obsolete in Aldor. Instead of declaring that a function returns AXIOMTypeVoid to indicate that its values are never used, you can declare that the function returns zero values using (). For example:
output: String -> Voidbecomes:
output: String -> ()
The SmallFloat domain has been renamed AXIOMTypeDoubleFloat and SmallInteger has been renamed AXIOMTypeSingleInteger. The new abbreviations are AXIOMTypeDFLOAT and AXIOMTypeSINT, respectively. We have defined the macro SF, the old abbreviation for SmallFloat, to expand to AXIOMTypeDoubleFloat, and modified the documentation and input file examples to use the new names and abbreviations. You should do the same in any private AXIOM files you have.
The AXIOMTypeBasicType category has been added near the root
of the AXIOM category hierarchy for compatibility with
Aldor.
As now implemented, AXIOMTypeBasicType declares the
``=='' and
``1#1~''Equals operations for testing equality
and inequality respectively, and a AXIOMFunFromsampleBasicType operation
for obtaining a sample member of a domain. The
AXIOMTypeSetCategory category has changed since some of its
operations have been moved to AXIOMTypeBasicCategory. It now also
contains a AXIOMFunFromhashSetCategory operation for computing
a hash code for an object, and a AXIOMFunFromlatexSetCategory operation for
obtaining a LATEX representation of an object in a string.
18.7 : Using the AXIOM-to-Aldor translator
Version 2.0 of AXIOM contains an experimental translator that helps you to convert files from AXIOM to Aldor. This translator is still under development and is known to be incomplete, but can often provide a useful first approximation for the converted file. By convention, files with file extension .spad are intended for the old compiler, while files with file extension .as are processed by Aldor. The translator modifies the old compiler so that while compiling the source .spad file, it generates an equivalent .as file. To invoke the translator you add the )translate option to your )compile command.
The code produced by the translator does not use #pile: instead of being indentation sensitive it explicitly uses ; and {}. During the translation process - comments are currently dropped, so they need to be added by hand later. Note that ++ comments which are intended to precede the object they describe need +++ in Aldor. Here is some .spad source code which is a simplified version of fmod.spad
1 -- AXIOM code from "fmod.spad" 2 3 )abb domain ZMOD IntegerMod 4 5 --% IntegerMod 6 7 ++ IntegerMod(n) creates the ring of integers reduced modulo the integer 8 ++ n. 9 10 IntegerMod(p:PositiveInteger): 11 Join(CommutativeRing, Finite, ConvertibleTo Integer, StepThrough) == add 12 size() == p 13 characteristic() == p 14 lookup x == (zero? x => p; (convert(x)@Integer) :: PositiveInteger) 15 16 Rep:= Integer 17 18 convert(x:%):Integer == convert(x)$Rep 19 coerce(n:Integer):% == positiveRemainder(n::Rep, p) 20 coerce(x):OutputForm == coerce(x)$Rep 21 0 == 0$Rep 22 1 == 1$Rep 23 init == 0$Rep 24 nextItem(n) == 25 m:% :=n+1 26 m=0 => "failed" 27 m 28 x = y == x =$Rep y 29 x:% * y:% == mulmod(x, y, p) 30 n:Integer * x:% == mulmod(positiveRemainder(n::Rep, p), x, p) 31 x + y == addmod(x, y, p) 32 x - y == submod(x, y, p) 33 random() == random(p)$Rep 34 index a == positiveRemainder(a::Rep, p) 35 - x == (zero? x => 0; p -$Rep, p) 36 x:% ** n:NonNegativeInteger == powmod(x, n:;Rep, p) 37 38 recip x == 39 (c1, c2, g) := extendedEuclidean(x, p)$Rep 40 not one? g => "failed" 41 positiveRemainder(c1, p) 42
This was translated using the command:
)compile fmod2.spad )translate
The following is an edited version of the result of the translation:
1 -- New code 2 3 #include "axiom.as" 4 ZMOD ==> IntegerMod; 5 6 +++ IntegerMod(`n') creates the ring of integers reduced modulo the 7 +++ integer `n'. 8 9 MyIntegerMod (p: PositiveInteger): with { 10 CommutativeRing; 11 Finite; 12 ConvertibleTo Integer; 13 StepThrough; 14 } 15 == add { 16 Rep == Integer; 17 import from PositiveInteger; 18 import from Rep; 19 size():NonNegativeInteger == p::NonNegativeInteger; 20 characteristic():NonNegativeInteger == p::NonNegativeInteger; 21 lookup (x:%):PositiveInteger == { 22 import from NonNegativeInteger; 23 import from Integer; 24 zero? x => p; 25 convert x @ Integer::PositiveInteger; 26 } 27 28 convert (x:%):Integer == convert(rep(x))$Rep; 29 coerce (n:Integer):% == per(positiveRemainder(n::Rep,p::Rep)); 30 coerce (x:%):OutputForm == coerce(rep(x))$Rep; 31 0:% == per(0$Rep); 32 1:% == per(1$Rep); 33 init:% == per(0$Rep); 34 nextItem (n:%):Union(value1: %,failed: 'failed') == { 35 m := n + 1; 36 m = 0 => [failed]; 37 [m]} 38 (x:%) = (y:%):Boolean == rep(x) =$Rep rep(y); 39 (x:%) * (y:%):% == { 40 import from Integer; 41 per(mulmod(rep(x),rep(y),p::Rep)); 42 } 43 44 (n:Integer) * (x:%):% == 45 per(mulmod(positiveRemainder(n::Rep,p::Rep),rep(x),p::Rep)); 46 47 (x:%) + (y:%):% == { 48 import from Integer; 49 per(addmod(rep(x),rep(y),p::Rep)); 50 } 51 52 (x:%) - (y:%):% == { 53 import from Integer; 54 per(submod(rep(x),rep(y),p::Rep)); 55 } 56 57 random():% == { import from Integer; per(random(p::Rep)$Rep) }; 58 index (a:PositiveInteger):% == { 59 import from Integer; 60 per(positiveRemainder(a::Rep,p::Rep)); 61 } 62 63 - (x:%):% == { 64 import from Integer; 65 zero? rep(x) => per(0); 66 per(p::Rep -$Rep rep(x)); 67 } 68 69 (x:%) ^ (n:NonNegativeInteger):% == { 70 import from Integer; 71 per(powmod(rep(x),n::Rep,p::Rep)); 72 } 73 74 recip (x:%):Union(value1: %,failed: 'failed') == { 75 import from Integer; 76 import from Record(coef1: Rep,coef2: Rep,generator: Rep); 77 import from Record(coef1: %,coef2: %,generator: %); 78 import from Union(value1: Rep,failed: 'failed'); 79 (c1,c2,g) := explode extendedEuclidean(rep(x),p::Rep); 80 one?(g) => [per positiveRemainder(c1,p::Rep)]; 81 [failed]; 82 } 83 84 }
For this particular example very few hand edits were required: in
the definition of recip, the call to explode was
added to convert the record output of extendedEuclidean to
a tuple for tuple assignment, and a per was inserted in the
next to last line.
In general the translator will make most necessary syntactic
changes, and will try to add the necessary import lines.
It currently needs some help in converting union references and
sometimes omits or adds extraneous rep and per
calls.
18.8 : Changes made to the interpreter language
The leave keyword has been replaced by the break keyword for compatibility with the Aldor language.
Curly braces are no longer used to create sets. Instead, use AXIOMFunset followed by a bracketed expression: for example,
set [1,2,3,4]
Curly braces are now used to enclose compound expressions, such as sequences.
18.9 : Using free functios with AXIOM
A free function is a function defined at the top level
in an Aldor source file, in other words the function definition is not contained within any
domain or category.
Before AXIOM Version 2.0, library functions had to come from
domains (or packages), but this is no longer the case.
Whenever you use )library directly or indirectly (for example,
by using )compile), the AXIOM databases are updated with
knowledge of all constructors and free functions.
After that, free functions participate fully in function selection
within the AXIOM intepreter, and
can also be passed to other functions, for example
AXIOMFunmap.
Note that they cannot be package-called since they do not come from a
domain.
You may need to more fully qualify the types of their arguments via
declarations or coercions to get the exact operation you intend.
18.10 : Efficiency
The Aldor compiler's runtime efficiency is, in part, due to
the inlining of functions at the point of their call.
In order to do this, it must be able to find suitable code in an
object file.
Unfortunately the old AXIOM compiler does not produce
compatible files, so it is not possible to inline old compiler
code.
This is particularly important for domains such as
AXIOMTypeNonNegativeInteger, AXIOMTypeInteger, and
AXIOMTypeList: typical code spends much of its time manipulating
objects of these types.
The Aldor runtime therefore extends certain important domains
with operations which are identical in name and function to their
AXIOM counterparts, but can be found by the Aldor compiler
because they are redefined by Aldor source code.
The files that implement this extension process are axextend.as and
axext_l.l which should be in the
$ALDORROOT/samples/libax0 directory. The idea is that Aldor
provides a mechanism for extending existing domains into objects which
have more functionality -- we use this to change (in this case, make
more efficient) the existing operations.
This is done for the low level datatypes, such as integers, floats
and some aggregate types (currently AXIOMTypeList and
AXIOMTypeVector).
Algebraic datatypes such as polynomials and expressions have not
been extended in this way.
A subset of the
This will ensure that whenever the Aldor compiler finds a call to
+, and it wishes to inline the call, a call to the FOAM builtin
BIntPlus will be generated, rather than a much more expensive
call to an AXIOM-defined function.
Similarly, it is possible to define extensions in terms of
functions (or macros) imported from
This course of redefining AXIOM operations should be a last
resort used in order to gain efficiency, because any changes to
the representation of a domain must be reflected in both the
AXIOM library, and in the Aldor and Lisp code which defines
the extension.
18.11 : Details of system commands
In this section we describe in detail three AXIOM system
commands that are useful when compiling Aldor files within
AXIOM:
The )compile system command acts as a front-end to both the Aldor compiler and the old AXIOM
system compiler. In what follows we shall only describe the options as they pertain
to Aldor; see the AXIOM system command documentation
for additional information regarding the old system compiler.
The first thing )compile does is look for a source code
filename among its arguments.
Thus the following commands:
This is frequently all you need to do to compile your file.
This simple command:
Should you not want the )library command automatically
invoked, call )compile with the )nolibrary option. For example,
The general description of Aldor command line arguments is in
chapter 27. The default options used by the )compile
command can be viewed and set using the )set axiomxl args AXIOM
system command.
The current defaults are
To supplement these default arguments, use the )moreargs option on )compile.
For example,
To completely replace these default arguments for a particular
use of )compile, use the )onlyargs option.
For example,
To completely replace the default arguments for all calls to )compile
within your AXIOM session, use )set axiomxl args.
For example, to use the above arguments for all compilations, issue
By default, the )library system command exposes all
domains and categories it processes.
This means that the AXIOM intepreter will consider those
domains and categories when it is trying to resolve a reference
to a function.
Sometimes domains and categories should not be exposed.
For example, a domain may just be used privately by another
domain and may not be meant for top-level use.
The )library command should still be used though, so that
the code will be loaded on demand.
In this case, you should use the )nolibrary option on
)compile and the )noexpose option in the )library
command. For example,
Once you have established your own collection of compiled code,
you may find it handy to use the )dir option on the )library command. This causes )library
to process all compiled code in the
specified directory. For example,
The )compile command works with several file extensions. We saw
above what happens when it is invoked on a file with extension
.as. A .ao file is a portable binary compiled version of a
.as file, and )compile simply passes the .ao file
on to Aldor. The generated Lisp file is compiled and )library
is automatically called, just as if you had specified a .as file.
A .al file is an archive file containing .ao files. The
archive is created (on Unix systems) with the ar program. When
)compile is given a .al file, it creates a directory whose
name is based on that of the archive. For example, if you issue
A .lsp file is a Lisp source file, presumably, in our context,
generated by Aldor when called with the -Flsp option. When
)compile is used with a .lsp file, the Lisp file is
compiled and )library is called. You must also have a
.asy file present, generated from the same source file.
Finally, when called with a file having the extension .spad, the
)compile command invokes the old AXIOM system compiler.
18.12 : Using Aldor outside AXIOM for AXIOM Section 18.11 discusses what really happens when you invoke the )compile system
command from within AXIOM.
If you invoke Aldor manually from the operating system prompt (or
from a front-end windowed application), you must use the proper options
so that all files needed by AXIOM are generated.
You must include the options
Note that you cannot test the execution of your code except by starting
AXIOM and then loading and executing the compiled version.
There are several reasons why you might want to develop your code
outside AXIOM:
Now we look at these options and discuss which ones you might want to
leave out in the early stages of developing your code.
Since compilation of large files can take some time, you may decide to
include more and more of the ``optional'' arguments as your work
proceeds, just in case the next compile is that lucky one where
everything works!
When you are ready to test and use your code within AXIOM, start
up AXIOM and then )cd to the directory containing your
compiled code. Invoke )compile on each .lsp file you wish
to use. The Lisp compiler will be invoked and the )library
command will be called automatically unless you specify
)nolibrary on )compile.
18.13 : Fine Print
At present, code from the AXIOM library will only run inside
an AXIOM workspace.
Consequentely Aldor programs extending the AXIOM library will
only run inside AXIOM.
For a later version, it is planned that the entire AXIOM library will
be translated into Aldor, at which point it should be possible to
call it from C, Fortran, or any other environment in which Aldor operates.
You must choose whether you wish to use
the stand-alone Aldor library (aldor.as + libaldor)
or whether you wish to use the AXIOM library (axiom.as + libaxiom).
It is possible to use them both together, but some types exist in both
libraries but have slightly
different meanings, so using them together is quite tricky.
The AXIOM and Aldor libraries contain many constructors with the same names.
Unfortunately, the like-named constructors often export different
operations, complicating the translation of a program written for the
Aldor library to one written for AXIOM.
It is beyond the scope of this document to do a detailed comparison
of the libraries.
We suggest you compare the exports of the constructors if you intend
to start a project using the Aldor library and then shift to the
AXIOM library, or vice versa.
For example, look at AXIOMTypeComplex in the complex.as file
in the Aldor library source directories and compare it to the
definition in gaussian.spad in the AXIOM source
``algebra'' directory
(this directory is probably $AXIOM/../../src/algebra on
a Unix machine.)
When you compile a .as file within AXIOM, the
-DAxiom global assertion is automatically added to the Aldor
command line.
The Aldor libraries will cause compilation to terminate when they
are processed if this assertion is present.
This gives you some measure of protection against trying to use
Aldor libraries within AXIOM.
Integer
extension is shown below:
extend
extend Integer: with {
+: (%, %) -> %;
=: (%, %) -> Boolean;
integer: Literal -> %;
}
== add {
import from Machine;
Rep ==> BInt;
import {
BIntPlus: (BInt, BInt) -> BInt;
BIntEQ: (BInt, BInt) -> Bool;
ArrToBInt: (Arr) -> BInt;
} from Builtin;
(a: %) + (b: %): % ==
per(BIntPlus(rep a, rep b));
(a: %) = (b: %): Boolean ==
BIntEQ(rep a, rep b) pretend Boolean;
integer(l: Literal): % ==
per ArrToBInt(l pretend Arr);
}
Foreign(Lisp)
.
The Lisp function should be defined in an auxilliary lisp file,
which may be compiled and loaded into the AXIOM system.
We've already seen examples of the last two commands in the
previous section.
)compile mycode.as
)compile /u/jones/apps/mycode.as
)compile mycode
all invoke )compiler on the file
/u/jones/apps/mycode.as if the current AXIOM working
directory is /u/jones/apps. (Recall that you can set the
working directory via the )cd command. If you don't set it
explicitly, it is the directory from which you started
AXIOM.)
)compile mycode.as )nolibrary
-O -Fasy -Fao -Flsp -laxiom -Mno-ALDOR_W_WillObsolete -DAxiom
These options mean:
)compile mycode.as )moreargs "-v"
uses the default arguments and appends the -v (verbose)
argument flag.
The additional argument specification must be enclosed in
double quotes.
)compile mycode.as )onlyargs "-v -O"
only uses the -v (verbose) and -O (optimize)
arguments.
The argument specification must be enclosed in double quotes.
In this example, Lisp code is not produced and so the compilation
output will not be available to AXIOM.
)set axiomxl args "-v -O"
Make sure you include the necessary -l and -Y
arguments along with those needed for Lisp file creation.
As above, the argument specification must be enclosed in double
quotes.
)compile mycode.as )nolibrary
)library mycode )noexpose
)library )dir /u/jones/apps/quantum
You must give an explicit directory after )dir, even if you
want all compiled code in the current working directory
processed, i.e.
)library )dir .
)compile mylib.al
the directory mylib.axldir is created. All
members of the archive are unarchived into the
directory and )compile is called on each .ao file found. It
is your responsibility to remove the directory and its contents, if you
choose to do so.
Previous
Home
Contents
Next