The FriCAS System For Computer Mathematics
The FriCAS System For Computer Mathematics
Website: https://fricas.github.io
Repository: https://github.com/fricas/fricas
Git hash: 28984914c3d15ec2976cf804a6691279d910b570
Warning
Since this book is a moving target, each part of its generation is automated. In particular, the output
of FriCAS commands (including their typesetting in LATEX) is automated. However, that sometimes
means that you see boxes with output that does not fit the width of the page. We use the breqn LATEX
package to break equations appropriately. Unfortunately, that does not always work nicely.
If you find other inaccuracies, please report them to the mailing list [email protected].
Authors
The book is an effort of quite a number of people. The original Axiom book lists the following
people as authors: Manuel Bronstein, William H. Burge, Timothy P. Daly, Patrizia Gianni, Johannes
Grabmeier, Scott C. Morrison, Jonathan M. Steinbach, Robert S. Sutor, Barry M. Trager, Stephen M.
Watt, Richard D. Jenks, Clifton J. Williamson.
Since FriCAS has been forked from the Axiom project, there have been a number of contributions and
corrections by Martin Baker, Riccardo Guida, Waldek Hebisch, Ralf Hemmecke, Qian Yun.
Contents
0 Introduction to FriCAS 3
0.1 Symbolic computation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
0.2 Numeric computation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
0.3 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
0.4 HyperDoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
0.5 Interactive Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
0.6 Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
0.7 Mathematical Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
0.8 Pattern Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
0.9 Polymorphic Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
0.10 Extensibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1 An Overview of FriCAS 21
1.1 Starting Up and Winding Down . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.1.1 Clef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.2 Typographic Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.3 The FriCAS Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.3.1 Arithmetic Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.3.2 Previous Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.3.3 Some Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.3.4 Symbols, Variables, Assignments, and Declarations . . . . . . . . . . . . . . . . . 25
1.3.5 Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.3.6 Calling Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
i
ii CONTENTS
3 Using HyperDoc 99
3.1 Headings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
3.2 Key Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
3.3 Scroll Bars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
3.4 Input Areas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
3.5 Radio Buttons and Toggles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.6 Search Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.6.1 Logical Searches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.7 Example Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.8 X Window Resources for HyperDoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
7 Graphics 195
7.1 Two-Dimensional Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
7.1.1 Plotting Two-Dimensional Functions of One Variable . . . . . . . . . . . . . . . . 196
7.1.2 Plotting Two-Dimensional Parametric Plane Curves . . . . . . . . . . . . . . . . 197
7.1.3 Plotting Plane Algebraic Curves . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
7.1.4 Two-Dimensional Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
7.1.5 Color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
7.1.6 Palette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
7.1.7 Two-Dimensional Control-Panel . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
7.1.8 Operations for Two-Dimensional Graphics . . . . . . . . . . . . . . . . . . . . . . 209
7.1.9 Addendum: Building Two-Dimensional Graphs . . . . . . . . . . . . . . . . . . . 211
7.1.10 Addendum: Appending a Graph to a Viewport Window Containing a Graph . . 219
7.2 Three-Dimensional Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
7.2.1 Plotting Three-Dimensional Functions of Two Variables . . . . . . . . . . . . . . 221
vi CONTENTS
11 Packages 649
11.1 Names, Abbreviations, and File Structure . . . . . . . . . . . . . . . . . . . . . . . . . . 650
11.2 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651
11.3 Abstract Datatypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651
11.4 Capsules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
11.5 Input Files vs. Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
xii CONTENTS
12 Categories 661
12.1 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662
12.2 Exports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662
12.3 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663
12.4 Hierarchies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
12.5 Membership . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 664
12.6 Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665
12.7 Axioms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
12.8 Correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
12.9 Categories as attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 667
12.10Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668
12.11Conditionals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 669
12.12Anonymous Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 669
13 Domains 671
13.1 Domains vs. Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671
13.2 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671
13.3 Category Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673
13.4 A Demo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673
13.5 Browse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675
13.6 Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675
13.7 Multiple Representations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
13.8 Add Domain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
13.9 Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677
13.10Origins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677
13.11Short Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678
13.12Example 1: Clifford Algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 678
13.13Example 2: Building A Query Facility . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680
CONTENTS xiii
14 Browse 689
14.1 The Front Page: Searching the Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
14.2 The Constructor Page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
14.2.1 Constructor Page Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696
14.2.2 Views Of Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
14.2.3 Giving Parameters to Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . 701
14.3 Miscellaneous Features of Browse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 702
14.3.1 The Description Page for Operations . . . . . . . . . . . . . . . . . . . . . . . . . 702
14.3.2 Views of Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
14.3.3 Capitalization Convention . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
Introduction to FriCAS
Welcome to the world of FriCAS. We call FriCAS 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 FriCAS offers.
√ √ √ √ 2√
√ 2 √ 2√ √ √ √
2 3
2 3
3
a
3 √
b x + a+a 3
−2 b2 x2
3 3
3 log 3 a b x + a + 3 a b x + a + a + 4 b2 x2 3 log 3 a b x + a − a + 12 b2 x2 arctan 3a
√ √3
(1)
2 2
18 a x 3 a
Union(Expression( Integer ) , ...)
FriCAS provides state-of-the-art algebraic machinery to handle your most advanced symbolic problems.
For example, FriCAS’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 FriCAS provides.
3
4 CHAPTER 0. INTRODUCTION TO FRICAS
[x = −0.6546536706904271136718122105095984761851224331556,
(1)
x = 1.086921395653859508493939035954893289009213388763,
x = 0.6546536707255271739694686066136764835361487607661]
List (Equation(Polynomial(Float)))
The output of a computation can be converted to FORTRAN to be used in a later numerical com-
putation. Besides floating point numbers, FriCAS 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 100th power in base 32?
radix (10^100 ,32)
4I9LKIP9GRSTC5IF164PO5V72ME827226JSLAP462585Q7H00000000000000000000 (2)
RadixExpansion(32)
0.3 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 FriCAS graphics capability.
p
Draw J0 ( x2 + y 2 ) for −20 ≤ x, y ≤ 20.
draw (5* besselJ (0 , sqrt ( x ^2+ y ^2) ) , x = -20..20 , y = -20..20)
5*besselJ(0,(y^2+x^2)^(1/2))
X Y
Graphs in FriCAS 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.
0.4. HYPERDOC 5
0.4 HyperDoc
HyperDoc presents you windows on the world of FriCAS, offering on-line help, examples, tutorials,
a browser, and reference material. HyperDoc gives you on-line access to this book 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 x49 −49x4 +9
to 49 digits (as in our previous example) and you don’t know how to tell FriCAS to do this. The “basic
command” facility of HyperDoc leads the way. Through the series of HyperDoc windows shown in
Figure 1 and the specified mouse clicks, you and HyperDoc generate the correct command to issue to
compute the answer.
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 FriCAS Images section in the center of the
book, for example, were created by programs written in the interactive language.
The above definitions for p do no computation—they simply tell FriCAS how to compute p(k) for
some positive integer k. To actually get a value of a Legendre polynomial, you ask for it.
What is the tenth Legendre polynomial?
p (10)
Compiling function p with type Integer -> Polynomial ( Fraction ( Integer ))
Compiling function p as a recurrence relation .
FriCAS 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 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
p, FriCAS 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 x90 in p(90)?
coefficient ( p (90) ,x ,90)
5688265542052017822223458237426581853561497449095175
(5)
77371252455336267181195264
Polynomial(Fraction ( Integer ))
In general, a user function is type-analyzed and compiled on first use. Later, if you use it with a
different kind of object, the function is recompiled if necessary.
0.6. DATA STRUCTURES 7
15 2 3 35 3 15 315 4 105 2 15
1, 3 x, x − , x − x, x − x + , (5)
2 2 2 2 8 4 8
693 5 315 3 105 3003 6 3465 4 945 2 35
x − x + x, x − x + x − , ...
8 4 8 16 16 16 16
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, FriCAS 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 = π/2?
series ( log ( cot ( x ) ) ,x = % pi /2)
−2 x + π 1 π 2 7 π 4 62 π 6 π 8
log + x− + x− + x− +O x− (6)
2 3 2 90 2 2835 2 2
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 50th term of this series?
coefficient (% ,50)
44590788901016030052447242300856550965644
(7)
7131469286438669111584090881309360354581359130859375
Expression ( Integer )
x+i 0
(1)
1 −2
Matrix(Polynomial(Complex(Integer)))
The FriCAS 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.
inverse (%)
1
x+i
0
1 (2)
2 x+2 i
− 21
Union(Matrix(Fraction(Polynomial(Complex(Integer)))) , ...)
sin(y + x) == cos(x) sin(y) + cos(y) sin(x), cos(y + x) == − sin(x) sin(y) + cos(x) cos(y), (1)
2 2
sin(2 x) == 2 cos(x) sin(x), cos(2 x) == −sin(x) + cos(x)
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.
0.9. POLYMORPHIC ALGORITHMS 9
y + 3 x3 + 1 = 0, y 2 = 4
(1)
Solve the system S using rational number arithmetic and 30 digits of accuracy.
digits (30) ; solve (S ,1/10^30)
57602201066248085349435651342568509
y = −2, x = , [y = 2, x = −1] (2)
83076749736557242056487941267521536
√ √
−3 + 1 − −3 + 1
[y = 2, x = −1] , y = 2, x = , y = 2, x = , y = −2, (3)
2 2
√ √ √ √
− −1 3 − 1 −1 3 − 1 1
x= √3
, y = −2, x = √3
, y = −2, x = √
3
2 3 2 3 3
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.
0.10 Extensibility
Users and system developers alike can augment the FriCAS 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.
10 CHAPTER 0. INTRODUCTION TO FRICAS
A Technical Introduction to FriCAS
FriCAS has both an interactive language for user interactions and a programming language for building
library modules. Like Modula 2, PASCAL, FORTRAN, and Ada, the programming language empha-
sizes strict type-checking. Unlike these languages, types in FriCAS are dynamic objects: they are
created at run-time in response to user commands.
Here is the idea of the FriCAS programming language in a nutshell. FriCAS 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, pro-
grams 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 FriCAS interactive language is oriented towards ease-of-use. The FriCAS 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:
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
11
12 CHAPTER 0. INTRODUCTION TO FRICAS
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 (Poly-
nomial (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.
The Exports part specifies operations for creating and manipulating objects of the domain. For
example, type Integer exports constants 0 and 1, and operations +, -, and *. While these operations
are common, others such as odd? and bit? are not.
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.
0.10. EXTENSIBILITY 13
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 R) are not.
Categories serve to ensure the type-correctness. The definition of matrices states 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.
R: Ring
power: (R, NonNegativeInteger): R -> R
power(x, n) == x ** n
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 = Integer. Also, power(3.0,2) produces
9.0 for x = 3.0 and R = Float. power("oxford",2) however fails since "oxford" has type String
which is not a ring.
Using symbolic domains, algorithms can be defined in their most natural or general setting.
14 CHAPTER 0. INTRODUCTION TO FRICAS
SetCategory
IntegralDomain OrderedFinite
Field
This definition asserts that Integer is both an ordered set and an integral domain. In fact, Integer
does not explicitly export constants 0 and 1 and operations +, - and * at all: it inherits them all from
Ring! Since IntegralDomain is a descendant of Ring, 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?”. FriCAS allows operation names (for example, norm) to have very different meanings
in different contexts. The meaning of an operation in FriCAS 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: abs(x) ==
if x < 0 then -x else x. Such a definition for abs in FriCAS is protected by context: argument x
is required to be a member of a domain of category OrderedSet.
where Exports specifies the solve operations you wish to export and Implementation defines functions
for implementing your algorithms. Once FriCAS 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.
16 CHAPTER 0. INTRODUCTION TO FRICAS
FriCAS is Extensible
Users and system implementers alike use the FriCAS language to add facilities to the FriCAS library.
The entire FriCAS library is in fact written in the FriCAS source code and available for user modification
and/or extension.
FriCAS’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. Cat-
egories 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, FriCAS provides an automatic, guaranteed interaction between new and old code. For example:
0.10. EXTENSIBILITY 17
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.
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.
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.
18 CHAPTER 0. INTRODUCTION TO FRICAS
Part I
19
Chapter 1
An Overview of FriCAS
Welcome to the FriCAS environment for interactive computation and problem solving. Consider this
chapter a brief, whirlwind tour of the FriCAS world. We introduce you to FriCAS’s graphics and
the FriCAS language. Then we give a sampling of the large variety of facilities in the FriCAS system,
ranging from the various kinds of numbers, to data types (like lists, arrays, and sets) and mathematical
objects (like matrices, integrals, and differential equations). We conclude with the discussion of system
commands and an interactive “undo.”
Before embarking on the tour, we need to brief those readers working interactively with FriCAS on
some details. Others can skip right immediately to Section 1.2 on page 22.
(1) ->
When you want to enter input to FriCAS, you do so on the same line after the prompt. The “1” in
“(1)” is the computation step number and is incremented after you enter FriCAS statements. Note,
however, that a system command such as )clear all may change the step number in other ways. We
talk about step numbers more when we discuss system commands and the workspace history facility.
If you are running FriCAS under the X Window System, there may be two windows: the console window
(as just described) and the HyperDoc main menu. HyperDoc is a multiple-window hypertext system
that lets you view FriCAS documentation and examples on-line, execute FriCAS expressions, and
generate graphics. If you are in a graphical windowing environment, it is usually started automatically
when FriCAS begins. If it is not running, issue )hd to start it. We discuss the basics of HyperDoc in
Chapter 3.
21
22 CHAPTER 1. AN OVERVIEW OF FRICAS
To interrupt an FriCAS computation, hold down the Ctrl (control) key and press c . This brings
you back to the FriCAS prompt.
To exit from FriCAS, move to the console window, type )quit at the input prompt and press the
Enter key. You will probably be prompted with the following message:
Please enter y or yes if you really want to leave the
interactive environment and return to the operating system
You should respond yes, for example, to exit FriCAS.
We are purposely vague in describing exactly what your screen looks like or what messages FriCAS
displays. FriCAS runs on a number of different machines, operating systems and window environments,
and these differences all affect the physical look of the system. You can also change the way that FriCAS
behaves via system commands described later in this chapter and in Appendix A. System commands
are special commands, like )set, that begin with a closing parenthesis and are used to change your
environment. For example, you can set a system variable so that you are not prompted for confirmation
when you want to leave FriCAS.
1.1.1 Clef
If you are using FriCAS under the X Window System, the Clef command line editor is probably
available and installed. With this editor you can recall previous lines with the up and down arrow
keys.
To move forward and backward on a line, use the right and left arrows. You can use the Insert key
to toggle insert mode on or off. When you are in insert mode, the cursor appears as a large block and
if you type anything, the characters are inserted into the line without deleting the previous ones.
If you press the Home key, the cursor moves to the beginning of the line and if you press the End
key, the cursor moves to the end of the line. Pressing Ctrl – End deletes all the text from the cursor
to the end of the line.
Clef also provides FriCAS operation name completion for a limited set of operations. If you enter a few
letters and then press the Tab key, Clef tries to use those letters as the prefix of an FriCAS operation
name. If a name appears and it is not what you want, press Tab again to see another name.
You are ready to begin your journey into the world of FriCAS. Proceed to the first stop.
Categories, domains and packages are displayed in a sans-serif typeface: Ring, Integer, Dio-
phantineSolutionPackage.
Prefix operators, infix operators, and punctuation symbols in the FriCAS language are displayed
in the text like this: +, “$”, “+->”.
1.3. THE FRICAS LANGUAGE 23
Function names and HyperDoc button names are displayed in the text in a bold typeface: factor,
integrate, Lighting.
Italics are used for emphasis and for words defined in the glossary: category.
This book contains over 2500 examples of FriCAS input and output. All examples were run though
FriCAS and their output was created in LATEX form for this book by the FriCAS FormatLaTex
package.
For arithmetic expressions, use the + and - operators as in mathematics. Use * for multiplication, and
^ for exponentiation. To create a fraction, use /. When an expression contains several operators, those
of highest precedence are evaluated first. For arithmetic operators, ^ has highest precedence, * and /
have the next highest precedence, and + and - have the lowest precedence.
FriCAS puts implicit parentheses around operations of higher precedence, and groups those of equal
precedence from left to right.
1 + 2 - 3 / 4 * 3 ^ 2 - 1
19
− (1)
4
Fraction ( Integer )
19
− (2)
4
Fraction ( Integer )
11
(3)
4
Fraction ( Integer )
Use the percent sign (“%”) to refer to the last result. Also, use “%%” to refer to previous results. %%(-1)
is equivalent to “%”, %%(-2) returns the next to the last result, and so on. %%(1) returns the result
from step number 1, %%(2) returns the result from step number 2, and so on. %%(0) is not defined.
This is ten to the tenth power.
10 ^ 10
10000000000 (1)
PositiveInteger
9999999999 (2)
PositiveInteger
9999999999 (3)
PositiveInteger
10000000000 (4)
PositiveInteger
Everything in FriCAS has a type. The type determines what operations you can perform on an object
and how the object can be used. An entire chapter of this book (Chapter 2) is dedicated to the
interactive use of types. Several of the final chapters discuss how types are built and how they are
organized in the FriCAS library.
Positive integers are given type PositiveInteger.
8
1.3. THE FRICAS LANGUAGE 25
8 (1)
PositiveInteger
Negative ones are given type Integer. This fine distinction is helpful to the FriCAS interpreter.
-8
−8 (2)
Integer
x8 (3)
Polynomial( Integer )
1
(4)
x8
Fraction (Polynomial( Integer ))
A symbol is a literal used for the input of things like the “variables” in polynomials and power series.
We use the three symbols x, y, and z in entering this polynomial.
( x - y * z ) ^2
y 2 z 2 − 2 x y z + x2 (1)
Polynomial( Integer )
A symbol has a name beginning with an uppercase or lowercase alphabetic character, “%”, or “!”.
Successive characters (if any) can be any of the above, digits, or “?”. Case is distinguished: the
symbol points is different from the symbol Points.
A symbol can also be used in FriCAS as a variable. A variable refers to a value. To assign a value to
a variable, the operator “:=” is used.1 A variable initially has no restrictions on the kinds of values to
which it can refer.
This assignment gives the value 4 (an integer) to a variable named x.
x := 4
1 FriCAS actually has two forms of assignment: immediate assignment, as discussed here, and delayed assignment.
4 (2)
PositiveInteger
3
z+ (3)
5
Polynomial(Fraction ( Integer ))
To restrict the types of objects that can be assigned to a variable, use a declaration
y : Integer
After a variable is declared to be of some type, only values of that type can be assigned to that
variable.
y := 89
89 (5)
Integer
0 (6)
Integer
A type declaration can also be given together with an assignment. The declaration can assist FriCAS
in choosing the correct operations to apply.
f : Float := 2/3
0.66666666666666666667 (7)
Float
Any number of expressions can be given on input line. Just separate them by semicolons. Only the
result of evaluating the last expression is displayed.
These two expressions have the same effect as the previous single expression.
1.3. THE FRICAS LANGUAGE 27
f : Float ; f := 2/3
0.66666666666666666667 (8)
Float
The type of a symbol is either Symbol or Variable(name) where name is the name of the symbol.
By default, the interpreter gives this symbol the type Variable(q).
q
q (9)
Variable (q)
[q, r] (10)
List ( OrderedVariableList ([ q, r ]) )
What happens when you try to use a symbol that is the name of a variable?
f
0.66666666666666666667 (11)
Float
Use a single quote (“’”) before the name to get the symbol.
’f
f (12)
Variable ( f )
Quoting a name creates a symbol by preventing evaluation of the name as a variable. Experience will
teach you when you are most likely going to need to use a quote. We try to point out the location of
such trouble spots.
1.3.5 Conversion
Objects of one type can usually be “converted” to objects of several other types. To convert an object
to a new type, use the “::” infix operator.2 For example, to display an object, it is necessary to
convert the object to type OutputForm.
This produces a polynomial with rational number coefficients.
p := r ^2 + 2/3
2
r2 + (1)
3
Polynomial(Fraction ( Integer ))
3 r2 + 2
(2)
3
Fraction (Polynomial( Integer ))
Some conversions can be performed automatically when FriCAS tries to evaluate your input. Others
conversions must be explicitly requested.
As we saw earlier, when you want to add or subtract two values, you place the arithmetic operator +
or - between the two arguments denoting the values. To use most other FriCAS operations, however,
you use another syntax: write the name of the operation first, then an open parenthesis, then each of
the arguments separated by commas, and, finally, a closing parenthesis. If the operation takes only
one argument and the argument is a number or a symbol, you can omit the parentheses.
This calls the operation factor with the single integer argument 120.
factor (120)
23 3 5 (1)
Factored( Integer )
This is a call to divide with the two integer arguments 125 and 7.
divide (125 ,7)
Quaternion(Float)
3628800 (4)
PositiveInteger
An operations that returns a Boolean value (that is, true or false) frequently has a name suffixed
with a question mark (“?”). For example, the even? operation returns true if its integer argument is
an even number, false otherwise.
An operation that can be destructive on one or more arguments usually has a name ending in a
exclamation point (“!”). This actually means that it is allowed to update its arguments but it is
not required to do so. For example, the underlying representation of a collection type may not allow
the very last element to removed and so an empty object may be returned instead. Therefore, it is
important that you use the object returned by the operation and not rely on a physical change having
occurred within the object. Usually, destructive operations are provided for efficiency reasons.
FriCAS provides several macros for your convenience.3 Macros are names (or forms) that expand to
larger expressions for commonly used values.
When you enter FriCAS expressions from your keyboard, there will be times when they are too long
to fit on one line. FriCAS does not care how long your lines are, so you can let them continue from
the right margin to the left side of the next line.
Alternatively, you may want to enter several shorter lines and have FriCAS glue them together. To
get this glue, put an underscore ( ) at the end of each line you wish to continue.
2_
+_
3
2+3
If you are putting your FriCAS statements in an input file (see Section 4.1 on page 105), you can use
indentation to indicate the structure of your program. (see Section 5.2 on page 126).
3 See Section 6.2 on page 150 for a discussion on how to write your own macros.
30 CHAPTER 1. AN OVERVIEW OF FRICAS
1.3.9 Comments
Comment statements begin with two consecutive hyphens or two consecutive plus signs and continue
until the end of the line.
The comment beginning with -- is ignored by FriCAS.
2 + 3 -- this is rather simple, no?
5 (1)
PositiveInteger
There is no way to write long multi-line comments other than starting each line with “--” or “++”.
1.4 Graphics
FriCAS has a two- and three-dimensional drawing and rendering package that allows you to draw,
shade, color, rotate, translate, map, clip, scale and combine graphic output of FriCAS computations.
The graphics interface is capable of plotting functions of one or more variables and plotting parametric
surfaces. Once the graphics figure appears in a window, move your mouse to the window and click. A
control panel appears immediately and allows you to interactively transform the object.
This is an example of FriCAS’s two-dimensional plotting. From the 2D Control Panel you can rescale
the plot, turn axes and units on and off and save the image, among other things. This PostScript
image was produced by clicking on the PS 2D Control Panel button.
draw ( cos (5* t /8) , t =0..16*% pi , coordinates == polar )
cos((5*t)/8)
FriCAS3D
X Y
An exhibit of FriCAS Images is given in the center section of this book. For a description of the
commands and programs that produced these figures, see Appendix B. PostScript output is available
so that FriCAS images can be printed.4 See Chapter 7 for more examples and details about using
FriCAS’s graphics facilities.
1.5 Numbers
FriCAS distinguishes very carefully between different kinds of numbers, how they are represented and
what their properties are. Here are a sampling of some of these kinds of numbers and some things you
can do with them.
Integer arithmetic is always exact.
11^13 * 13^11 * 17^7 - 19^5 * 23^3
25387751112538918594666224484237298 (1)
PositiveInteger
Factored( Integer )
Results stay factored when you do arithmetic. Note that the 12 is automatically factored for you.
% * 12
Factored( Integer )
Integers can also be displayed to bases other than 10. This is an integer in base 11.
4 PostScript is a trademark of Adobe Systems Incorporated, registered in the United States.
32 CHAPTER 1. AN OVERVIEW OF FRICAS
10000000000 (4)
RadixExpansion(11)
M CM XCII (5)
RomanNumeral
55739
(6)
2520
Fraction ( Integer )
To factor fractions, you have to map factor onto the numerator and denominator.
map ( factor , r )
139 401
(7)
23 32 5 7
Fraction (Factored( Integer ))
Type SingleInteger refers to machine word-length integers. In English, this expression means “11 as
a small integer”.
11 @Single Integer
11 (8)
SingleInteger
Machine double-precision floating-point numbers are also available for numeric and graphical applica-
tions.
123.21 @DoubleFloat
123.21000000000001 (9)
DoubleFloat
The normal floating-point type in FriCAS, Float, is a software implementation of floating-point num-
bers in which the exponent and the mantissa may have any number of digits.5 The types Com-
plex(Float) and Complex(DoubleFloat) are the corresponding software implementations of com-
plex floating-point numbers.
5 See ‘Float’ on page 419 and ‘DoubleFloat’ on page 395 for additional information on floating-point types.
1.5. NUMBERS 33
This is a floating-point approximation to about twenty digits. The “::” is used here to change from
one kind of object (here, a rational number) to another (a floating-point number).
r :: Float
22.118650793650793651 (10)
Float
Use digits to change the number of digits in the representation. This operation returns the previous
value so you can reset it later.
digits (22)
20 (11)
PositiveInteger
√
To 22 digits of precision, the number eπ 163.0
appears to be an integer.
exp (% pi * sqrt 163.0)
262537412640768744.0 (12)
Float
262537412640768743.9999999999992500725976 (13)
Float
Here are complex numbers with rational numbers as real and imaginary parts.
(2/3 + % i ) ^3
46 1
− + i (14)
27 3
Complex(Fraction(Integer))
46 1
− − i (15)
27 3
Complex(Fraction(Integer))
Factored(Complex(Integer))
Complex(Float)
Every rational number has an exact representation as a repeating decimal expansion (see ‘DecimalExpansion’
on page 388).
decimal (1/352)
0.0028409 (18)
DecimalExpansion
A rational number can also be expressed as a continued fraction (see ‘ContinuedFraction’ on page
375).
c o n t i n u e d F r a c t i o n (6543/210)
1| 1| 1| 1|
31 + + + + (19)
|6 |2 |1 |3
ContinuedFraction( Integer )
97 58 13 6
− + 4 + 2 − (20)
28 3 5 7
PartialFraction ( Integer )
1 1 1 2 1 1 2 3 6
− − 3 − 8 + + 3 + 4 + + 2 − (21)
22 2 2 3 3 3 5 5 7
PartialFraction ( Integer )
Like integers, bases (radices) other than ten can be used for rational numbers (see ‘RadixExpansion’
on page 542). Here we use base eight.
radix (4/7 , 8)
1.5. NUMBERS 35
0.4 (22)
RadixExpansion(8)
Of course, there are complex versions of these as well. FriCAS decides to make the result a complex
rational number.
% + 2/3*% i
4 2
+ i (23)
7 3
Complex(Fraction(Integer))
√
q
3
14 7 + 5 (24)
AlgebraicNumber
5 (25)
PrimeField(7)
6 (26)
PrimeField(7)
3 (27)
PrimeField(7)
5 (28)
36 CHAPTER 1. AN OVERVIEW OF FRICAS
IntegerMod(6)
5 (29)
IntegerMod(6)
Inversion is not available if the modulus is not a prime number. Modular arithmetic and prime fields
are discussed in Section 8.11.1 on page 304.
1/ y
There are 11 exposed and 15 unexposed library operations named / having 2
argument ( s ) but none was determined to be applicable . Use HyperDoc Browse ,
or issue
) display op /
to learn more about the available operations . Perhaps package - calling the
operation or using coercions on the arguments will allow you to apply the
operation .
Cannot find a definition or applicable library operation named / with argument
type ( s )
P os it iv e In te ge r
IntegerMod (6)
Perhaps you should use " @ " to indicate the required return type , or " $ " to
specify which version of the function you need .
a (30)
Expression ( Integer )
Expression ( Integer )
b (32)
Expression ( Integer )
Do some arithmetic.
2/( b - 1)
1.6. DATA STRUCTURES 37
2
(33)
b−1
Expression ( Integer )
a4 − a3 + 2 a2 − a + 1 b3 + a4 − a3 + 2 a2 − a + 1 b2 + a4 − a3 + 2 a2 − a + 1 b + a4 − a3 + 2 a2 − a + 1
(34)
Expression ( Integer )
a4 − a3 + 2 a2 − a + 1 b3 + a4 − a3 + 2 a2 − a + 1 b2 + a4 − a3 + 2 a2 − a + 1 b + a4 − a3 + 2 a2 − a + 3
Expression ( Integer )
b (36)
Expression ( Integer )
Types Quaternion and Octonion are also available. Multiplication of quaternions is non-commutative,
as expected.
q := quatern (1 ,2 ,3 ,4) * quatern (5 ,6 ,7 ,8) - quatern (5 ,6 ,7 ,8) * quatern (1 ,2 ,3 ,4)
− 8 i + 16 j − 8 k (37)
Quaternion(Integer )
Write a list of elements using square brackets with commas separating the elements.
u := [1 , -7 ,11]
List ( Integer )
This is the value at the third node. Alternatively, you can say u.3.
first rest rest u
11 (2)
PositiveInteger
Many operations are defined on lists, such as: empty?, to test that a list has no elements; cons(x,l),
to create a new list with first element x and rest l; reverse, to create a new list with elements in reverse
order; and sort, to arrange elements in order.
An important point about lists is that they are “mutable”: their constituent elements and links can
be changed “in place.” To do this, use any of the operations whose names end with the character “!”.
The operation concat!(u,v) replaces the last link of the list u to point to some other list v. Since u
refers to the original list, this change is seen by u.
concat !( u ,[9 ,1 ,3 , -4]) ; u
List ( Integer )
A cyclic list is a list with a “cycle”: a link pointing back to an earlier node of the list. To create a
cycle, first get a node somewhere down the list.
lastnode := rest (u ,3)
List ( Integer )
Use setrest! to change the link emanating from that node to point back to an earlier part of the list.
setrest !( lastnode , rest (u ,2) ) ; u
1, −7, 11, 9 (5)
List ( Integer )
A stream is a structure that (potentially) has an infinite number of distinct elements.7 Think of a
stream as an “infinite list” where elements are computed successively.
Create an infinite stream of factored integers. Only a certain number of initial elements are computed
and displayed.
7 Streams are discussed in ‘Stream’ on page 578 and in Section 5.5 on page 144.
1.6. DATA STRUCTURES 39
2, 22 , 2 3, 23 , 2 5, 22 3, 2 7, . . .
(6)
Stream(Factored(Integer))
23 32 (7)
Factored( Integer )
Streams can also be finite or cyclic. They are implemented by a linked list structure similar to lists
and have many of the same operations. For example, first and rest are used to access elements and
successive nodes of a stream.
A one-dimensional array is another data structure used to hold objects of the same type.8 Unlike
lists, one-dimensional arrays are inflexible—they are implemented using a fixed block of storage. Their
advantage is that they give quick and equal access time to any element.
A simple way to create a one-dimensional array is to apply the operation oneDimensionalArray to a list
of elements.
a := o n e D i m e n s i o n a l A r r a y [1 , -7 , 3 , 3/2]
3
1, −7, 3, (8)
2
OneDimensionalArray(Fraction(Integer))
One-dimensional arrays are also mutable: you can change their constituent elements “in place.”
a .3 := 11; a
3
1, −7, 11, (9)
2
OneDimensionalArray(Fraction(Integer))
However, one-dimensional arrays are not flexible structures. You cannot destructively concat! them
together.
concat !( a , o n e D i m e n s i o n a l A r r a y [1 , -2])
There are 5 exposed and 0 unexposed library operations named concat ! having 2
argument ( s ) but none was determined to be applicable . Use HyperDoc Browse ,
or issue
) display op concat !
to learn more about the available operations . Perhaps package - calling the
operation or using coercions on the arguments will allow you to apply the
operation .
8 See ‘OneDimensionalArray’ on page 518 for details.
40 CHAPTER 1. AN OVERVIEW OF FRICAS
Perhaps you should use " @ " to indicate the required return type , or " $ " to
specify which version of the function you need .
"11111111111111111111111111111111" (10)
Bits
9
A flexible array is a cross between a list and a one-dimensional array. Like a one-dimensional array,
a flexible array occupies a fixed block of storage. Its block of storage, however, has room to expand!
When it gets full, it grows (a new, larger block of storage is allocated); when it has too much room, it
contracts.
Create a flexible array of three elements.
f := flexibleArray [2 , 7 , -5]
FlexibleArray ( Integer )
FlexibleArray ( Integer )
Flexible arrays are used to implement “heaps.” A heap is an example of a data structure called a
priority queue, where elements are ordered with respect to one another.10 A heap is organized so as to
optimize insertion and extraction of maximum elements. The extract! operation returns the maximum
element of the heap, after destructively removing that element and reorganizing the heap so that the
next maximum element is ready to be delivered.
An easy way to create a heap is to apply the operation heap to a list of values.
h := heap [ -4 ,7 ,11 ,3 ,4 , -7]
9 See
‘FlexibleArray’ on page 416 for details.
10 See ‘Heap’ on page 439 for more details. Heaps are also examples of data structures called bags. Other bag data
structures are Stack, Queue, and Dequeue.
1.6. DATA STRUCTURES 41
Heap(Integer)
This loop extracts elements one-at-a-time from h until the heap is exhausted, returning the elements
as a list in the order they were extracted.
[ extract !( h ) while not empty ?( h ) ]
List ( Integer )
A binary tree is a “tree” with at most two branches per node: it is either empty, or else is a node
consisting of a value, and a left and right subtree (again, binary trees).11
A binary search tree is a binary tree such that, for each node, the value of the node is greater than all
values (if any) in the left subtree, and less than or equal all values (if any) in the right subtree.
b i n a r y S e a r c h T r ee [5 ,3 ,2 ,9 ,4 ,7 ,11]
BinarySearchTree( PositiveInteger )
A balanced binary tree is useful for doing modular computations. Given a list lm of moduli, modTree(
a,lm) produces a balanced binary tree with the values a mod m at its leaves.
modTree (8 ,[2 ,3 ,5 ,7])
[0, 2, 3, 1] (16)
List ( Integer )
A set is a collection of elements where duplication and order is irrelevant.12 Sets are always finite and
have no corresponding structure like streams for infinite collections.
Create sets by using the set function.
fs := set [1/3 ,4/5 , -1/3 ,4/5]
1 1 4
− , , (17)
3 3 5
A multiset is a set that keeps track of the number of duplicate values.13 For all the primes p between
2 and 1000, find the distribution of p mod 5.
multiset [ x rem 5 for x in primes (2 ,1000) ]
{47 : 2, 42 : 3, 0, 40 : 1, 38 : 4} (18)
11 Example of binary tree types are BinarySearchTree (see ‘BinarySearchTree’ on page 349, PendantTree, Tour-
Multiset ( Integer )
A table is conceptually a set of “key–value” pairs and is a generalization of a multiset.14 The domain
Table(Key, Entry) provides a general-purpose type for tables with values of type Entry indexed by
keys of type Key.
Compute the above distribution of primes using tables. First, let t denote an empty table of keys and
values, each of type Integer.
t : Table ( Integer , Integer ) := empty ()
table () (19)
We define a function howMany to return the number of values of a given modulus k seen so far. It
calls search(k,t) which returns the number of values stored under the key k in table t, or "failed"
if no such value is yet stored in t under k.
In English, this says “Define howMany(k) as follows. First, let n be the value of search(k, t). Then, if
n has the value ”f ailed”, return the value 1; otherwise return n + 1.”
howMany ( k ) == ( n := search (k , t ) ; n case " failed " = > 1; n +1)
Run through the primes to create the table, then print the table. The expression t.m := howMany(m)
updates the value in table t stored under key m.
for p in primes (2 ,1000) repeat ( m := p rem 5; t . m := howMany ( m ) ) ; t
Compiling function howMany with type Integer -> Integer
Give daniel a value, using square brackets to enclose the values of the fields.
daniel := [28 , 32005.12]
14 For examples of tables, see AssociationList (‘AssociationList’ on page 341), HashTable, KeyedAccessFile
(‘KeyedAccessFile’ on page 457), Library (‘Library’ on page 474), SparseTable (‘SparseTable’ on page 572),
StringTable (‘StringTable’ on page 585), and Table (‘Table’ on page 589).
15 See Section 2.4 on page 76 for details.
1.7. EXPANDING TO HIGHER DIMENSIONS 43
"Whisper" (26)
All told, there are over forty different data structures in FriCAS. Using the domain constructors
described in Chapter 13, you can add your own data structure or extend an existing one. Choosing
the right data structure for your application may be the key to obtaining good performance.
1 2
(1)
3 4
Matrix( Integer )
The “collections” construct (see Section 5.5 on page 144) is useful for creating matrices whose entries
are given by formulas.
matrix ([[1/( i + j - x ) for i in 1..4] for j in 1..4])
16 See Section 2.5 on page 79 for details.
17 See ‘TwoDimensionalArray’ on page 593 for more information about arrays. For more information about FriCAS’s
linear algebra facilities, see ‘Matrix’ on page 504, ‘Permanent’ on page 532, ‘SquareMatrix’ on page 577, ‘Vector’ on page
604, Section 8.4 on page 267 (computation of eigenvalues and eigenvectors) , and Section 8.5 on page 270 (solution of
linear and polynomial equations) .
44 CHAPTER 1. AN OVERVIEW OF FRICAS
1 1 1 1
− x−2 − x−3 − x−4 − x−5
− 1 1
− x−4 1
− x−5 1
− x−6
x−3 (2)
− 1 1
− x−5 1
− x−6 − 1
x−4 x−7
1 1 1 1
− x−5 − x−6 − x−7 − x−8
1 1 1
x y z (3)
x2 y2 z2
Matrix(Polynomial( Integer ))
z2 (4)
Polynomial( Integer )
1, y, y 2
(5)
Vector(Polynomial( Integer ))
x2 + x + 1 y2 + y + 1 z2 + z + 1
2
x z + xy + x y z + y2 + x
2
z3 + y z + x (6)
x2 z 2 + x y 2 + x2 y 2 z 2 + y 3 + x2 z 4 + y 2 z + x2
Matrix(Polynomial( Integer ))
(y − x) (z − y) (z − x) (7)
Factored(Polynomial( Integer ))
1.8. WRITING YOUR OWN FUNCTIONS 45
Ask for the value at 50. The resulting function created by FriCAS computes the value by iteration.
fact (50)
Compiling function fact with type Integer -> Integer
Compiling function fact as a recurrence relation .
30414093201713378043612608166064768844377641568960512000000000000 (3)
PositiveInteger
This function is less efficient than the previous version since each iteration involves a recursive function
call.
fac (50)
Compiling function fac with type Integer -> Integer
30414093201713378043612608166064768844377641568960512000000000000 (5)
PositiveInteger
30414093201713378043612608166064768844377641568960512000000000000 (7)
PositiveInteger
A final version appears to construct a large list and then reduces over it with multiplication.
f ( n ) == reduce (* ,[ i for i in 2.. n ])
In fact, the resulting computation is optimized into an efficient iteration loop equivalent to that of the
third version.
f (50)
Compiling function f with type P os it i ve In te g er -> Po s it iv eI n te ge r
30414093201713378043612608166064768844377641568960512000000000000 (9)
PositiveInteger
The library version uses an algorithm that is different from the four above because it highly optimizes
the recurrence relation definition of factorial.
factorial (50)
30414093201713378043612608166064768844377641568960512000000000000 (10)
PositiveInteger
You are not limited to one-line functions in FriCAS. If you place your function definitions in .input
files (see Section 4.1 on page 105), you can have multi-line functions that use indentation for grouping.
Given n elements, diagonalMatrix creates an n by n matrix with those elements down the diagonal.
This function uses a permutation matrix that interchanges the ith and jth rows of a matrix by which
it is right-multiplied.
This function definition shows a style of definition that can be used in .input files. Indentation is used
to create blocks: sequences of expressions that are evaluated in sequence except as modified by control
statements such as if-then-else and return.
permMat (n , i , j ) ==
m := diagona lMatrix
[( if i = k or j = k then 0 else 1)
for k in 1.. n ]
m (i , j ) := 1
m (j , i ) := 1
m
This creates a four by four matrix that interchanges the second and third rows.
p := permMat (4 ,2 ,3)
Compiling function permMat with type ( PositiveInteger , PositiveInteger ,
P os itiv e In te ge r ) -> Matrix ( N o n N e g a t i v e I n t e g e r )
1 0 0 0
0 0 1 0
0
(12)
1 0 0
0 0 0 1
1.8. WRITING YOUR OWN FUNCTIONS 47
Matrix(NonNegativeInteger)
1 2 3 4
5 6 7 8
9
(13)
10 11 12
13 14 15 16
Matrix(NonNegativeInteger)
1 2 3 4
9 10 11 12
5
(14)
6 7 8
13 14 15 16
Matrix(NonNegativeInteger)
A function can also be passed as an argument to another function, which then applies the function or
passes it off to some other function that does. You often have to declare the type of a function that
has functional arguments.
This declares t to be a two-argument function that returns a Float. The first argument is a function
that takes one Float argument and returns a Float.
t : ( Float -> Float , Float ) -> Float
We have not defined a cos in the workspace. The one from the FriCAS library will do.
t ( cos , 5.2058)
Compiling function t with type (( Float -> Float ) , Float ) -> Float
1.0 (17)
Float
1.739223724180051649254147684772932520785 (19)
48 CHAPTER 1. AN OVERVIEW OF FRICAS
Float
FriCAS also has pattern matching capabilities for simplification of expressions and for defining new
functions by rules. For example, suppose that you want to apply regularly a transformation that groups
together products of radicals: √ √ √
a b 7→ ab, (∀a)(∀b)
Note that such a transformation is not generally correct. FriCAS never uses it automatically.
Give this rule the name groupSqrt.
groupSqrt := rule ( sqrt ( a ) * sqrt ( b ) == sqrt ( a * b ) )
√ √ √
%C a b == %C a b (20)
√ √ √
(4 z + 4 y + 12 x) y + (4 z + 12 y + 4 x) x z (21)
√ √
+ (12 z + 4 y + 4 x) x y + z 2 + (6 y + 6 x) z + y 2 + 6 x y + x2
Expression ( Integer )
√ √ √
(4 z + 4 y + 12 x) y z + (4 z + 12 y + 4 x) x z + (12 z + 4 y + 4 x) x y + z 2 + (6 y + 6 x) z + y 2 + 6 x y + x2 (22)
Expression ( Integer )
1.9 Polynomials
Polynomials are the commonly used algebraic types in symbolic computation. Interactive users of
FriCAS generally only see one type of polynomial: Polynomial(R). This type represents polynomials
in any number of unspecified variables over a particular coefficient domain R. This type represents its
coefficients sparsely: only terms with non-zero coefficients are represented.
In building applications, many other kinds of polynomial representations are useful. Polynomials may
have one variable or multiple variables, the variables can be named or unnamed, the coefficients can
be stored sparsely or densely. So-called “distributed multivariate polynomials” store polynomials as
coefficients paired with vectors of exponents. This type is particularly efficient for use in algorithms
for solving systems of non-linear polynomial equations.
The polynomial constructor most familiar to the interactive user is Polynomial.
( x ^2 - x * y ^3 +3* y ) ^2
x2 y 6 − 6 x y 4 − 2 x3 y 3 + 9 y 2 + 6 x2 y + x4 (1)
1.10. LIMITS 49
Polynomial( Integer )
If you wish to restrict the variables used, UnivariatePolynomial provides polynomials in one variable.
18 x3 + 60 x2 − 46 x + 8 (2)
x4 − 2 y 3 x3 + y 6 + 6 y x2 − 6 y 4 x + 9 y 2
(3)
MultivariatePolynomial ([ x, y ], Integer )
You can change the way the polynomial appears by modifying the variable ordering in the explicit
list.
m :: MPOLY ([ y , x ] , INT )
x2 y 6 − 6 x y 4 − 2 x3 y 3 + 9 y 2 + 6 x2 y + x4 (4)
MultivariatePolynomial ([ y, x ], Integer )
y 6 x2 − 6 y 4 x − 2 y 3 x3 + 9 y 2 + 6 y x2 + x4 (5)
DistributedMultivariatePolynomial ([ y, x ], Integer )
y 6 x2 − 2 y 3 x3 − 6 y 4 x + x4 + 6 y x2 + 9 y 2 (6)
HomogeneousDistributedMultivariatePolynomial([y, x ], Integer )
1.10 Limits
FriCAS’s limit function is usually used to evaluate limits of quotients where the numerator and de-
50 CHAPTER 1. AN OVERVIEW OF FRICAS
nominator both tend to zero or both tend to infinity. To find the limit of an expression f as a real
variable x tends to a limit value a, enter limit(f, x=a). Use complexLimit if the variable is complex.
Additional information and examples of limits are in Section 8.6 on page 275.
You can take limits of functions with parameters.
g := csc ( a * x ) / csch ( b * x )
csc(a x)
(1)
csch(b x)
Expression ( Integer )
b
(2)
a
Union(OrderedCompletion(Expression(Integer)) , ...)
x
x+k
(3)
x
Expression ( Integer )
ek (4)
Union(OrderedCompletion(Expression(Integer)) , ...)
A function can be defined on both sides of a particular value, but may tend to different limits as its
variable approaches that value from the left and from the right.
limit ( sqrt ( y ^2) /y , y = 0)
0 (6)
1.11. SERIES 51
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.
complexLimit ( exp ( -1/ x ^2) ,x = 0)
"failed" (7)
1.11 Series
FriCAS also provides power series. By default, FriCAS tries to compute and display the first ten
elements of a series. Use )set streams calculate to change the default value to something else. For
the purposes of this book, we have used this system command to display fewer than ten terms. For
more information about working with series, see Section 8.9 on page 282.
You can convert a functional expression to a power series by using the operation series. In this example,
sin(a*x) is expanded in powers of (x - 0), that is, in powers of x.
series ( sin ( a * x ) ,x = 0)
a3 3 a5 5 a7 7
x + O x9
ax − x + x − (1)
6 120 5040
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
2 aπ
aπ aπ π a sin 4 π 2
sin + a cos x− − x−
4 4 4 2 4
a3 cos a4π 4 aπ 5 aπ (2)
π 3 a sin 4 π 4 a cos 4 π 5
− x− + x− + x−
6 4 24 4 120 4
a6 sin a4π 7 aπ
π 6 a cos 4 π 7 π 8
− x− − x− +O x−
720 4 5040 4 4
FriCAS provides Puiseux series: series with rational number exponents. The first argument to series
is an in-place function that computes the nth coefficient. (Recall that the “+->” is an infix operator
meaning “maps to.”)
series ( n + - > ( -1) ^((3* n - 4) /6) / factorial ( n - 1/3) ,x = 0 ,4/3.. ,2)
4 1 10
x 3 + O x4
x3 − (3)
6
52 CHAPTER 1. AN OVERVIEW OF FRICAS
Once you have created a power series, you can perform arithmetic operations on that series. We
compute the Taylor expansion of 1/(1-x).
f := series (1/(1 - x ) ,x = 0)
1 + x + x2 + x3 + x4 + x5 + x6 + x7 + O x8
(4)
1 + 2 x + 3 x2 + 4 x3 + 5 x4 + 6 x5 + 7 x6 + 8 x7 + O x8
(5)
The usual elementary functions (log, exp, trigonometric functions, and so on) are defined for power
series.
f := series (1/(1 - x ) ,x = 0)
1 + x + x2 + x3 + x4 + x5 + x6 + x7 + O x8
(6)
g := log ( f )
1 2 1 3 1 4 1 5 1 6 1 7 1 8
x + x + x + x + x + x + x + O x9
x+ (7)
2 3 4 5 6 7 8
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
exp ( g )
1 + x + x2 + x3 + x4 + x5 + x6 + x7 + O x8
(8)
Here is a way to obtain numerical approximations of e from the Taylor series expansion of exp(x).
First create the desired Taylor expansion.
f := taylor ( exp ( x ) )
1 2 1 3 1 4 1 5 1 6 1
x7 + O x8
1+x+ x + x + x + x + x + (9)
2 6 24 120 720 5040
UnivariateTaylorSeries ( Expression ( Integer ) , x, 0)
Evaluate the series at the value 1.0. As you see, you get a sequence of partial sums.
eval (f ,1.0)
1.12. DERIVATIVES 53
Stream(Expression(Float))
1.12 Derivatives
Use the FriCAS function D to differentiate an expression.
To find the derivative of an expression f with respect to a variable x, enter D(f, x).
f := exp exp x
x
ee (1)
Expression ( Integer )
D (f , x )
x
ex ee (2)
Expression ( Integer )
An optional third argument n in D asks FriCAS for the nth derivative of f. This finds the fourth
derivative of f with respect to x.
D (f , x , 4)
x
(ex )4 + 6 (ex )3 + 7 (ex )2 + ex ee (3)
Expression ( Integer )
You can also compute partial derivatives by specifying the order of differentiation.
g := sin ( x ^2 + y )
sin y + x2
(4)
Expression ( Integer )
D (g , y )
cos y + x2
(5)
54 CHAPTER 1. AN OVERVIEW OF FRICAS
Expression ( Integer )
D (g , [y , y , x , x ])
4 x2 sin y + x2 − 2 cos y + x2
(6)
Expression ( Integer )
FriCAS can manipulate the derivatives (partial and iterated) of expressions involving formal operators.
All the dependencies must be explicit. This returns 0 since F (so far) does not explicitly depend on
x.
D (F , x )
0 (7)
Polynomial( Integer )
Suppose that we have F a function of x, y, and z, where x and y are themselves functions of z. Start
by declaring that F, x, and y are operators.
F := operator ’F ; x := operator ’x ; y := operator ’y
y (8)
BasicOperator
Expression ( Integer )
Differentiate formally with respect to z. The formal derivatives appearing in dadz are not just formal
symbols, but do represent the derivatives of x, y, and F.
dadz := D (a , z )
2 z F,3 x(z), y(z), z 2 + y ′ (z) F,2 x(z), y(z), z 2 + x′ (z) F,1 x(z), y(z), z 2 + x′ (y(z + 1)) y ′ (z + 1)
(10)
Expression ( Integer )
You can evaluate the above for particular functional values of F, x, and y. If x(z) is exp(z) and y(z)
is log(z+1), then this evaluates dadz.
eval ( eval ( dadz , ’x , z + - > exp z ) , ’y , z + - > log ( z +1) )
You obtain the same result by first evaluating a and then differentiating.
1.13. INTEGRATION 55
F ez , log(z + 1), z 2 + z + 2
(12)
Expression ( Integer )
D (% , z )
1.13 Integration
FriCAS has extensive library facilities for integration.
The first example is the integration of a fraction with denominator that factors into a quadratic and
a quartic irreducible polynomial. The usual partial fraction approach used by most other computer
algebra systems either fails or introduces expensive unneeded algebraic numbers.
We use a factorization-free algorithm.
integrate (( x ^2+2* x +1) /(( x +1) ^6+1) ,x )
arctan x3 + 3 x2 + 3 x + 1
(1)
3
Union(Expression( Integer ) , ...)
When real parameters are present, the form of the integral can depend on the signs of some expressions.
Rather than query the user or make sign assumptions, FriCAS returns all possible answers.
integrate (1/( x ^2 + a ) ,x )
√
(x2 −a)
√
−a+2 a x
log x2 +a arctan x a a
√ , √ (2)
2 −a a
The integrate operation generally assumes that all parameters are real. The only exception is when
the integrand has complex valued quantities.
If the parameter is complex instead of real, then the notion of sign is undefined and there is a unique
answer. You can request this answer by “prepending” the word “complex” to the command name:
c o m p l e x I n t e g r a te (1/( x ^2 + a ) ,x )
q q q q
− a1 log a − a1 + x − − a1 log −a − a1 + x
(3)
2
56 CHAPTER 1. AN OVERVIEW OF FRICAS
Expression ( Integer )
The following two examples illustrate the limitations of table-based approaches. The two integrands
are very similar, but the answer to one of them requires the addition of two new algebraic numbers.
This one is the easy one. The next one looks very similar but the answer is much more complicated.
integrate ( x ^3 / ( a + b * x ) ^(1/3) ,x )
√ 2
120 b3 x3 − 135 a b2 x2 + 162 a2 b x − 243 a3
3
bx + a
(4)
440 b4
Union(Expression( Integer ) , ...)
Only an algorithmic approach is guaranteed to find what new constants must be added in order to find
a solution.
integrate (1 / ( x ^3 * ( a + b * x ) ^(1/3) ) ,x )
√ √ √ √ 2√
√ 2 √ 2√ √ √ √
2 3
2 3
3
a
3 √
b x + a+a 3
−2 b2 x2
3 3
3 log 3 a b x + a + 3 a b x + a + a + 4 b2 x2 3 log 3 a b x + a − a + 12 b2 x2 arctan 3a
√ √ (5)
18 a2 x2 3 3 a
Union(Expression( Integer ) , ...)
Some computer algebra systems use heuristics or table-driven approaches to integration. When these
systems cannot determine the answer to an integration problem, they reply “I don’t know.” FriCAS
uses a algorithm for integration. that conclusively proves that an integral cannot be expressed in terms
of elementary functions.
When FriCAS returns an integral sign, it has proved that no answer exists as an elementary function.
integrate ( log (1 + sqrt ( a * x + b ) ) / x , x )
√
Z x log b + %D a + 1
d%D (6)
%D
Union(Expression( Integer ) , ...)
FriCAS can handle complicated mixed functions much beyond what you can find in tables. Whenever
possible, FriCAS tries to express the answer using the functions present in the integrand.
integrate (( sinh (1+ sqrt ( x + b ) ) +2* sqrt ( x + b ) ) / ( sqrt ( x + b ) * ( x + cosh (1+ sqrt ( x + b ) ) ) ) , x )
√ !
√
−2 cosh x + b + 1 − 2 x
2 log √ √ −2 x+b (7)
sinh x + b + 1 − cosh x + b + 1
A strong structure-checking algorithm in FriCAS finds hidden algebraic relationships between func-
tions.
integrate ( tan ( atan ( x ) /3) ,x )
1.14. DIFFERENTIAL EQUATIONS 57
2 2
8 log 3 tan arctan(x)
3
− 1 − 3 tan arctan(x)
3
+ 18 x tan arctan(x)
3
(8)
18
Union(Expression( Integer ) , ...)
The discovery of this algebraic relationship is necessary for correct integration of this function. Here
are the details:
This is an example of a mixed function where the algebraic layer is over the transcendental one.
integrate (( x + 1) / ( x *( x + log x ) ^ (3/2) ) , x )
p
2 log(x) + x
− (9)
log(x) + x
While incomplete for non-elementary functions, FriCAS can handle some of them.
integrate ( exp ( - x ^2) * erf ( x ) / ( erf ( x ) ^3 - erf ( x ) ^2 - erf ( x ) + 1) ,x )
√ √
(erf(x) − 1) π log erf(x)−1
erf(x)+1
−2 π
(10)
8 erf(x) − 8
More examples of FriCAS’s integration capabilities are discussed in Section 8.8 on page 279.
y (1)
BasicOperator
Equation(Expression( Integer ))
solve ( deq , y , x )
x5 − 10 x3 + 20 x2 + 4
3
2 x − 3 x2 + 1 x3 − 1 x3 − 3 x2 − 1
particular = , basis = , , (3)
15 x x x x
Union(Record( particular : Expression ( Integer ) , basis : List ( Expression ( Integer ))) , ...)
Equation(Expression( Integer ))
solve ( deq , y , x )
" " √ ##
1 log x2 + 1 − x
particular = 0, basis = √ , √ (5)
x2 + 1 x2 + 1
Union(Record( particular : Expression ( Integer ) , basis : List ( Expression ( Integer ))) , ...)
Coefficients of differential equations can come from arbitrary constant fields. For example, coefficients
can contain algebraic numbers.
This example has solutions whose logarithmic derivative is an algebraic function of degree two.
eq := 2* x ^3 * D ( y x ,x ,2) + 3* x ^2 * D ( y x , x ) - 2 * y x
Expression ( Integer )
solve ( eq ,y , x ) . basis
h √2 √2
i
−
e x, e x (7)
deq := D ( y x , x ) = y ( x ) / ( x + y ( x ) * log y x )
y(x)
y ′ (x) = (8)
y(x) log(y(x)) + x
Equation(Expression( Integer ))
solve ( deq , y , x )
y(x) log(y(x))2 − 2 x
(9)
2 y(x)
Rather than attempting to get a closed form solution of a differential equation, you instead might want
to find an approximate solution in the form of a series.
Let’s solve a system of nonlinear first order equations and get a solution in power series. Tell FriCAS
that x is also an operator.
x := operator ’x
x (10)
BasicOperator
Equation(Expression( Integer ))
eq2 := D ( y ( t ) , t ) = x ( t ) * y ( t )
Equation(Expression( Integer ))
We can 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
[series for x(t), series for y(t)].
seriesSolve ([ eq2 , eq1 ] , [x , y ] , t = 0 , [ y (0) = 1 , x (0) = 0])
Compiling function % JL with type List ( U n i v a r i a t e T a y l o r S e r i e s ( Expression ( Integer
) ,t ,0)) -> U n i v a r i a t e T a y l o r S e r i e s ( Expression ( Integer ) ,t ,0)
Compiling function % JM with type List ( U n i v a r i a t e T a y l o r S e r i e s ( Expression ( Integer
) ,t ,0)) -> U n i v a r i a t e T a y l o r S e r i e s ( Expression ( Integer ) ,t ,0)
1 2 5 17 7 1 5 4 61 6
t + t3 + t + O t8 , 1 + t2 + t + O t8
t + t + (13)
3 15 315 2 24 720
60 CHAPTER 1. AN OVERVIEW OF FRICAS
Find the real roots of S(19) with rational arithmetic, correct to within 1/1020 .
solve ( S (19) ,1/10^20)
Compiling function S with type P os it i ve In te g er -> List ( Polynomial ( Integer ))
80336736493669365924189585 80336736493669365924189585
y = 5, x = − , y = 5, x = (2)
9671406556917033397649408 9671406556917033397649408
Find the complex roots of S(19) with floating point coefficients to 20 digits accuracy in the mantissa.
complexSolve ( S (19) ,10. e -20)
If a system of equations has symbolic coefficients and you want a solution in radicals, try radicalSolve.
radicalSolve ( S ( a ) ,[x , y ])
Compiling function S with type Variable ( a ) -> List ( Polynomial ( Integer ))
For systems of equations with symbolic coefficients, you can apply solve, listing the variables that you
want FriCAS to solve for. For polynomial equations, a solution cannot usually be expressed solely in
terms of the other variables. Instead, the solution is presented as a “triangular” system of equations,
where each polynomial has coefficients involving only the succeeding variables. This is analogous to
converting a linear system of equations to “triangular form”. A system of three equations in five
variables.
eqns := [ x ^2 - y + z , x ^2* z + x ^4 - b *y , y ^2 * z - a - b * x ]
1.16. SYSTEM COMMANDS 61
z − y + x2 , x2 z − b y + x4 , y 2 z − b x − a
(5)
Solve the system for unknowns [x, y, z], reducing the solution to triangular form.
solve ( eqns ,[ x ,y , z ])
a2 z 3 + 2 b z 2 + b2 z − a
a
x = − , y = 0, z = − 2 , x = , y = z + b, (6)
b b b
z 6 + 4 b z 5 + 6 b2 z 4 + 4 b3 − 2 a z 3 + b4 − 4 a b z 2 − 2 a b2 z − b3 + a2 = 0
A useful system command is )undo. Sometimes while computing interactively with FriCAS, you make
a mistake and enter an incorrect definition or assignment. Or perhaps you need to try one of several
alternative approaches, one after another, to find the best way to approach an application. For this,
you will find the undo facility of FriCAS helpful.
System command )undo n means “undo back to step n”; it restores the values of user variables to
those that existed immediately after input expression n was evaluated. Similarly, )undo -n undoes
changes caused by the last n input expressions. Once you have done an )undo, you can continue on
from there, or make a change and redo all your input expressions from the point of the )undo forward.
The )undo is completely general: it changes the environment like any user expression. Thus you can
)undo any previous undo.
Here is a sample dialogue between user and FriCAS. “Let me define two mutually dependent functions
f and g piece-wise.”
f (0) == 1; g (0) == 1
“Hmm, I think I want to define f differently. Undo to the environment right after I defined f.”
) undo 2
“I want my old definition of f after all. Undo the undo and restore the environment to that immediately
after (4).”
) undo 4
After you have gone off on several tangents, then backtracked to previous points in your conversation
using )undo, you might want to save all the “correct” input commands you issued, disregarding those
undone. The system command )history )write mynew.input writes a clean straight-line program
onto the file mynew.input on your disk.
This concludes your tour of FriCAS. To disembark, issue the system command )quit to leave FriCAS
and return to the operating system.
64 CHAPTER 1. AN OVERVIEW OF FRICAS
Chapter 2
In this chapter we look at the key notion of type and its generalization mode. We show that every
FriCAS object has a type that determines what you can do with the object. In particular, we explain
how to use types to call specific functions from particular parts of the library and how types and modes
can be used to create new objects from old. We also look at Record and Union types and the special
type Any. Finally, we give you an idea of how FriCAS manipulates types and modes internally to
resolve ambiguities.
−3 (1)
Integer
Here we create a rational number but it looks like the last result. The type however tells you it is
different. You cannot identify the type of an object by how FriCAS displays the object.
65
66 CHAPTER 2. USING TYPES AND MODES
-3/1
−3 (2)
Fraction ( Integer )
When a computation produces a result of a simpler type, FriCAS leaves the type unsimplified. Thus
no information is lost.
x + 3 - x
3 (3)
Polynomial( Integer )
This seldom matters since FriCAS retracts the answer to the simpler type if it is necessary.
factorial (%)
6 (4)
Expression ( Integer )
When you issue a positive number, the type PositiveInteger is printed. Surely, 3 also has type
Integer! The curious reader may now have two questions. First, is the type of an object not unique?
Second, how is PositiveInteger related to Integer? Read on!
3
3 (5)
PositiveInteger
Any domain can be refined to a subdomain by a membership predicate.1 For example, the domain
Integer can be refined to the subdomain PositiveInteger, the set of integers x such that x > 0,
by giving the FriCAS predicate x 7→ x > 0. Similarly, FriCAS can define subdomains such as “the
subdomain of diagonal matrices,” “the subdomain of lists of length two,” “the subdomain of monic
irreducible polynomials in x,” and so on. Trivially, any domain is a subdomain of itself.
While an object belongs to a unique domain, it can belong to any number of subdomains. Any
subdomain of the domain of an object can be used as the type of that object. The type of 3 is indeed
both Integer and PositiveInteger as well as any other subdomain of integer whose predicate is
satisfied, such as “the prime integers,” “the odd positive integers between 3 and 17,” and so on.
In FriCAS, domains are objects. You can create them, pass them to functions, and, as we’ll see later,
test them for certain properties.
In FriCAS, you ask for a value of a function by applying its name to a set of arguments.
To ask for “the factorial of 7” you enter this expression to FriCAS. This applies the function factorial
to the value 7 to compute the result.
1A predicate is a function that, when applied to an object of the domain, returns either true or false.
2.1. THE BASIC IDEA 67
factorial (7)
5040 (1)
PositiveInteger
Enter the type Polynomial (Integer) as an expression to FriCAS. This looks much like a function
call as well. It is! The result is stated to be of type Type, which according to our usual convention,
denotes the class of all domains.
Polynomial ( Integer )
Polynomial(Integer) (2)
Type
The most basic operation involving domains is that of building a new domain from a given one. To
create the domain of “polynomials over the integers,” FriCAS applies the function Polynomial to
the domain Integer. A function like Polynomial is called a domain constructor or, more simply, a
constructor. A domain constructor is a function that creates a domain. An argument to a domain
constructor can be another domain or, in general, an arbitrary kind of object. Polynomial takes
a single domain argument while SquareMatrix takes a positive integer as an argument to give its
dimension and a domain argument to give the type of its components.
What kinds of domains can you use as the argument to Polynomial or SquareMatrix or List? Well,
the first two are mathematical in nature. You want to be able to perform algebraic operations like +
and * on polynomials and square matrices, and operations such as determinant on square matrices. So
you want to allow polynomials of integers and polynomials of square matrices with complex number
coefficients and, in general, anything that “makes sense.” At the same time, you don’t want FriCAS
to be able to build nonsense domains such as “polynomials of strings!”
In contrast to algebraic structures, data structures can hold any kind of object. Operations on lists
such as insert, delete, and concat just manipulate the list itself without changing or operating on its
elements. Thus you can build List over almost any datatype, including itself. Create a complicated
algebraic domain.
List ( List ( Matrix ( Polynomial ( Complex ( Fraction ( Integer ) ) ) ) ) )
List(List(Matrix(Polynomial(Complex(Fraction(Integer)))))) (3)
Type
Evidently from our last example, FriCAS has some mechanism that tells what a constructor can use
as an argument. This brings us to the notion of category. As domains are objects, they too have
a domain. The domain of a domain is a category. A category is simply a type whose members are
domains.
A common algebraic category is Ring, the class of all domains that are “rings.” A ring is an algebraic
structure with constants 0 and 1 and operations +, -, and *. These operations are assumed “closed”
with respect to the domain, meaning that they take two objects of the domain and produce a result
68 CHAPTER 2. USING TYPES AND MODES
object also in the domain. The operations are understood to satisfy certain “axioms,” certain math-
ematical principles providing the algebraic foundation for rings. For example, the additive inverse
axiom for rings states:
The prototypical example of a domain that is a ring is the integers. Keep them in mind whenever we
mention Ring.
Many algebraic domain constructors such as Complex, Polynomial, Fraction, take rings as argu-
ments and return rings as values. You can use the infix operator “has” to ask a domain if it belongs
to a particular category.
All numerical types are rings. Domain constructor Polynomial builds “the ring of polynomials over
any other ring.”
Polynomial ( Integer ) has Ring
true (4)
Boolean
false (5)
Boolean
The constructor Matrix(R) builds “the domain of all matrices over the ring R.” This domain is never
a ring since the operations “+”, “-”, and “*” on matrices of arbitrary shapes are undefined.
Matrix ( Integer ) has Ring
false (6)
Boolean
Use SquareMatrix(n,R) instead. For any positive integer n, it builds “the ring of n by n matrices
over R.”
Polynomial ( SquareMatrix (7 , Complex ( Integer ) ) )
Another common category is Field, the class of all fields. A field is a ring with additional operations.
For example, a field has commutative multiplication and a closed operation / for the division of two
elements. Integer is not a field since, for example, 3/2 does not have an integer result. The prototypical
2.1. THE BASIC IDEA 69
example of a field is the rational numbers, that is, the domain Fraction(Integer). In general, the
constructor Fraction takes a ring as an argument and returns a field.2 Other domain constructors,
such as Complex, build fields only if their argument domain is a field.
The complex integers (often called the “Gaussian integers”) do not form a field.
Complex ( Integer ) has Field
false (8)
Boolean
true (9)
Boolean
The algebraically equivalent domain of complex rational numbers is a field since domain constructor
Complex produces a field whenever its argument is a field.
Complex ( Fraction ( Integer ) ) has Field
true (10)
Boolean
3
The most basic category is Type. It denotes the class of all domains and subdomains. Domain
constructor List is able to build “lists of elements from domain D” for arbitrary D simply by requiring
that D belong to category Type.
Now, you may ask, what exactly is a category? Like domains, categories can be defined in the FriCAS
language. A category is defined by three components:
1. a name (for example, Ring), used to refer to the class of domains that the category represents;
2. a set of operations, used to refer to the operations that the domains of this class support (for
example, +, -, and * for rings); and
3. an optional list of other categories that this category extends.
This last component is a new idea. And it is key to the design of FriCAS! Because categories can
extend one another, they form hierarchies. Detailed charts showing the category hierarchies in FriCAS
are displayed in the endpages of this book. There you see that all categories are extensions of Type
and that Field is an extension of Ring.
The operations supported by the domains of a category are called the exports of that category because
these are the operations made available for system-wide use. The exports of a domain of a given
category are not only the ones explicitly mentioned by the category. Since a category extends other
categories, the operations of these other categories—and all categories these other categories extend—
are also exported by the domains.
2 Actually, the argument domain must have some additional properties so as to belong to category IntegralDomain.
3 Type does not denote the class of all types. The type of all categories is Category. The type of Type itself is
undefined.
70 CHAPTER 2. USING TYPES AND MODES
For example, polynomial domains belong to PolynomialCategory. This category explicitly mentions
some twenty-nine operations on polynomials, but it extends eleven other categories (including Ring).
As a result, the current system has over one hundred operations on polynomials.
If a domain belongs to a category that extends, say, Ring, it is convenient to say that the domain
exports Ring. The name of the category thus provides a convenient shorthand for the list of operations
exported by the category. Rather than listing operations such as + and * of Ring each time they are
needed, the definition of a type simply asserts that it exports category Ring.
The category name, however, is more than a shorthand. The name Ring, in fact, implies that the
operations exported by rings are required to satisfy a set of “axioms” associated with the name Ring.4
Why is it not correct to assume that some type is a ring if it exports all of the operations of Ring?
Here is why. Some languages such as APL denote the Boolean constants true and false by the
integers 1 and 0 respectively, then use + and * to denote the logical operators or and and. But with
these definitions Boolean is not a ring since the additive inverse axiom is violated.5 This alternative
definition of Boolean can be easily and correctly implemented in FriCAS, since Boolean simply does
not assert that it is of category Ring. This prevents the system from building meaningless domains
such as Polynomial(Boolean) and then wrongfully applying algorithms that presume that the ring
axioms hold.
Enough on categories. To learn more about them, see Chapter 12. We now return to our discussion of
domains.
Domains export a set of operations to make them available for system-wide use. Integer, for example,
exports the operations + and = given by the signatures +: (Integer,Integer)→Integer and =: (
Integer,Integer)→Boolean, respectively. Each of these operations takes two Integer arguments.
The + operation also returns an Integer but = returns a Boolean: true or false. The operations
exported by a domain usually manipulate objects of the domain—but not always.
The operations of a domain may actually take as arguments, and return as values, objects from any
domain. For example, Fraction (Integer) exports the operations /: (Integer,Integer)→Fraction
(Integer) and characteristic: →NonNegativeInteger.
Suppose all operations of a domain take as arguments and return as values, only objects from other
domains. This kind of domain is what FriCAS calls a package.
A package does not designate a class of objects at all. Rather, a package is just a collection of op-
erations. Actually the bulk of the FriCAS library of algorithms consists of packages. The facilities
for factorization; integration; solution of linear, polynomial, and differential equations; computation of
limits; and so on, are all defined in packages. Domains needed by algorithms can be passed to a package
as arguments or used by name if they are not “variable.” Packages are useful for defining operations
that convert objects of one type to another, particularly when these types have different parameter-
izations. As an example, the package PolynomialFunction2(R,S) defines operations that convert
polynomials over a domain R to polynomials over S. To convert an object from Polynomial(Integer)
to Polynomial(Float), FriCAS builds the package PolynomialFunctions2(Integer,Float) in or-
der to create the required conversion function. (This happens “behind the scenes” for you: see Section
2.7 on page 84 for details on how to convert objects.)
FriCAS categories, domains and packages and all their contained functions are written in the FriCAS
programming language and have been compiled into machine code. This is what comprises the FriCAS
library. In the rest of this book we show you how to use these domains and their functions and how to
4 This subtle but important feature distinguishes FriCAS from other abstract datatype designs.
5 There is no inverse element a such that 1 + a = 0, or, in the usual terms: true or a = false.
2.2. WRITING TYPES AND MODES 71
You need to do so when you declare functions (Section 2.3 on page 74),
f : Integer -> String
You need to do so when you convert an object from one type to another (Section 2.7 on page 84).
factor (2 :: Complex ( Integer ) )
− i (1 + i)2 (3)
Factored(Complex(Integer))
(2 = 3) $ Integer
false (4)
Boolean
You need to do so when you give computation target type information (Section 2.9 on page 89).
(2 = 3) @Boolean
false (5)
Boolean
A constructor with no arguments can be written either with or without trailing opening and closing
parentheses (“()”).
A constructor with one argument can frequently be written with no parentheses. Types nest from
right to left so that Complex Fraction Polynomial Integer is the same as Complex (Fraction
(Polynomial (Integer))). You need to use parentheses to force the application of a constructor to
the correct argument, but you need not use any more than is necessary to remove ambiguities.
Here are some guidelines for using parentheses (they are possibly slightly more restrictive than they
need to be). If the argument is an expression like 2 + 3 then you must enclose the argument in
parentheses.
e : PrimeField (2 + 3)
If the type is to be used with package calling then you must enclose the argument in parentheses.
content (2) $ Polynomial ( Integer )
2 (2)
Integer
Alternatively, you can write the type without parentheses then enclose the whole type expression with
parentheses.
content (2) $ ( Polynomial Complex Fraction Integer )
2 (3)
Complex(Fraction(Integer))
If you supply computation target type information (Section 2.9 on page 89) then you should enclose
the argument in parentheses.
(2/3) @Fraction ( Polynomial ( Integer ) )
2
(4)
3
Fraction (Polynomial( Integer ))
If the type itself has parentheses around it and we are not in the case of the first example above, then
the parentheses can usually be omitted.
(2/3) @Fraction ( Polynomial Integer )
2
(5)
3
Fraction (Polynomial( Integer ))
If the type is used in a declaration and the argument is a single-word type, integer or symbol, then the
parentheses can usually be omitted.
(d ,f , g ) : Complex Polynomial Integer
2.2. WRITING TYPES AND MODES 73
If a constructor has more than one argument, you must use parentheses. Some examples are
UnivariatePolynomial(x, Float)
MultivariatePolynomial([z,w,r], Complex Float)
SquareMatrix(3, Integer)
FactoredFunctions2(Integer,Fraction Integer)
2.2.4 Modes
A mode is a type that possibly is a question mark (“?”) or contains one in an argument position. For
example, the following are all modes.
? Polynomial ?
Matrix Polynomial ? SquareMatrix(3,?)
Integer OneDimensionalArray(Float)
As is evident from these examples, a mode is a type with a part that is not specified (indicated by
a question mark). Only one “?” is allowed per mode and it must appear in the most deeply nested
argument that is a type. Thus ?(Integer), Matrix(? (Polynomial)), SquareMatrix(?, Integer)
and SquareMatrix(?, ?) are all invalid. The question mark must take the place of a domain, not
data (for example, the integer that is the dimension of a square matrix). This rules out, for example,
the two SquareMatrix expressions.
Modes can be used for declarations (Section 2.3 on page 74) and conversions (Section 2.7 on page 84).
However, you cannot use a mode for package calling or giving target type information.
2.2.5 Abbreviations
Every constructor has an abbreviation that you can freely substitute for the constructor name. In
some cases, the abbreviation is nothing more than the capitalized version of the constructor name.
Aside from allowing types to be written more concisely, abbreviations are used by FriCAS to name
various system files for constructors (such as library filenames, test input files and example files).
Here are some common abbreviations.
COMPLEX abbreviates Complex DFLOAT abbreviates DoubleFloat
EXPR abbreviates Expression FLOAT abbreviates Float
FRAC abbreviates Fraction INT abbreviates Integer
MATRIX abbreviates Matrix NNI abbreviates NonNegativeInteger
PI abbreviates PositiveInteger POLY abbreviates Polynomial
STRING abbreviates String UP abbreviates UnivariatePolynomial
You can combine both full constructor names and abbreviations in a type expression. Here are some
types using abbreviations.
74 CHAPTER 2. USING TYPES AND MODES
There are several ways of finding the names of constructors and their abbreviations. For a specific
constructor, use )abbreviation query. You can also use the )what system command to see the names
and abbreviations of constructors. For more information about )what, see Section A.28 on page 761.
)abbreviation query can be abbreviated (no pun intended) to )abb q.
) abb q Integer
INT abbreviates domain Integer
The )abbreviation query command lists the constructor name if you give the abbreviation. Issue
)abb q if you want to see the names and abbreviations of all FriCAS constructors.
) abb q DMP
DMP abbreviates domain D i s t r i b u t e d M u l t i v a r i a t e P o l y n o m i a l
Issue this to see all packages whose names contain the string “ode”.
) what packages ode
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Packages - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2.3 Declarations
A declaration is an expression used to restrict the type of values that can be assigned to variables. A
colon (“:”) is always used after a variable or list of variables to be declared.
You can always combine a declaration with an assignment. When you do, it is equivalent to first giving
a declaration statement, then giving an assignment. For more information on assignment, see Section
2.3. DECLARATIONS 75
1.3.4 on page 25 and Section 5.1 on page 123. To see how to declare your own functions, see Section
6.4 on page 153.
This declares one variable to have a type.
a : Integer
45 (3)
Integer
− 36 + 9 i (6)
Complex(Integer)
This complex object has fractional symbolic real and imaginary parts.
n := complex (4/( x + y ) ,y / x )
4 y
+ i (7)
y+x x
Complex(Fraction(Polynomial(Integer)))
This matrix has entries that are polynomials with integer coefficients.
p := [[1 ,2] ,[3 ,4] ,[5 ,6]]
76 CHAPTER 2. USING TYPES AND MODES
1 2
3 4 (8)
5 6
Matrix(Polynomial( Integer ))
This matrix has a single entry that is a polynomial with rational number coefficients.
q := [[ x - 2/3]]
x − 23
(9)
This matrix has entries that are polynomials with complex integer coefficients.
r := [[1 -% i *x ,7* y +4*% i ]]
−i x + 1 7y + 4i (10)
Matrix(Polynomial(Complex(Integer)))
Note the difference between this and the next example. This is a complex object with polynomial real
and imaginary parts.
f : COMPLEX POLY ? := ( x + y *% i ) ^2
− y 2 + x2 + 2 x y i (11)
Complex(Polynomial(Integer))
This is a polynomial with complex integer coefficients. The objects are convertible from one to the
other. See Section 2.7 on page 84 for more information.
g : POLY COMPLEX ? := ( x + y *% i ) ^2
− y 2 + 2 i x y + x2 (12)
Polynomial(Complex(Integer))
2.4 Records
A Record is an object composed of one or more other objects, each of which is referenced with a
selector. Components can all belong to the same type or each can have a different type.
Record components are implicitly ordered. All the components of a record can be set at once by
assigning the record a bracketed tuple of values of the proper length (for example, r : Record(a:
Integer, b: String):= [1, "two"]). To access a component of a record r, write the name r,
followed by a period, followed by a selector.
The object returned by this computation is a record with two components: a quotient part and a
remainder part.
u := divide (5 ,2)
2 (2)
PositiveInteger
1 (3)
PositiveInteger
You can use selector expressions on the left-hand side of an assignment to change destructively the
components of a record.
u . quotient := 8978
8978 (4)
PositiveInteger
The selected component quotient has the value 8978, which is what is returned by the assignment.
Check that the value of u was modified.
u
Selectors are evaluated. Thus you can use variables that evaluate to selectors instead of the selectors
themselves.
s := ’ quotient
quotient (6)
78 CHAPTER 2. USING TYPES AND MODES
Variable ( quotient )
Be careful! A selector could have the same name as a variable in the workspace. If this occurs, precede
the selector name by a single quote, as in u.’quotient.
divide (5 ,2) . s
2 (7)
PositiveInteger
Here we declare that the value of bd has two components: a string, to be accessed via name, and an
integer, to be accessed via birthdayMonth.
bd : Record ( name : String , birthdayMonth : Integer )
You must initially set the value of the entire Record at once.
bd := [" Judith " , 3]
"Katie" (10)
String
Records may be nested and the selector names can be shared at different levels.
r : Record ( a : Record ( b : Integer , c : Integer ) , b : Integer )
The record r has a b selector at two different levels. Here is an initial value for r.
r := [[1 ,2] ,3]
[a = [b = 1, c = 2] , b = 3] (12)
1 (13)
PositiveInteger
3 (14)
PositiveInteger
You can also use spaces or parentheses to refer to Record components. This is the same as r.a.
r(a)
[b = 1, c = 2] (15)
3 (16)
PositiveInteger
10 (17)
PositiveInteger
[a = [b = 1, c = 2] , b = 10] (18)
2.5 Unions
Type Union is used for objects that can be of any of a specific finite set of types. Two versions of
unions are available, one with selectors (like records) and one without.
The declaration x : Union(Integer, String, Float) states that x can have values that are integers,
strings or “big” floats. If, for example, the Union object is an integer, the object is said to belong to
the Integer branch of the Union.6
6 Note that we are being a bit careless with the language here. Technically, the type of x is always Union(Integer,
String, Float). If it belongs to the Integer branch, x may be converted to an object of type Integer.
80 CHAPTER 2. USING TYPES AND MODES
It is possible to create unions like Union(Integer, PositiveInteger) but they are difficult to work
with because of the overlap in the branch types. See below for the rules FriCAS uses for converting
something into a union object.
The case infix operator returns a Boolean and can be used to determine the branch in which an
object lies.
This function displays a message stating in which branch of the Union the object (defined as x above)
lies.
sayBranch ( x : Union ( Integer , String , Float ) ) : Void ==
output
x case Integer = > " Integer branch "
x case String = > " String branch "
" Float branch "
Function declaration sayBranch : Union ( Integer , String , Float ) -> Void has been
added to workspace .
There are two things of interest about this particular example to which we would like to draw your
attention.
1. FriCAS normally converts a result to the target value before passing it to the function. If we left
the declaration information out of this function definition then the sayBranch call would have
been attempted with an Integer rather than a Union, and an error would have resulted.
2. The types in a Union are searched in the order given. So if the type were given as
sayBranch(x: Union(String,Integer,Float,Any)): Void
then the result would have been “String branch” because there is a conversion from Integer to
String.
Sometimes Union types can have extremely long names. FriCAS therefore abbreviates the names of
unions by printing the type of the branch first within the Union and then eliding the remaining types
with an ellipsis (“...”).
2.5. UNIONS 81
Here the Integer branch is displayed first. Use “::” to create a Union object from an object.
78 :: Union ( Integer , String )
78 (5)
Union(Integer , ...)
"string" (6)
Union(String , ...)
A common operation that returns a union is exquo which returns the “exact quotient” if the quotient
is exact,...
three := exquo (6 ,2)
3 (8)
Union(Integer , ...)
"failed" (9)
A union with a "failed" is frequently used to indicate the failure or lack of applicability of an object.
As another example, assign an integer a variable r declared to be a rational number.
r : FRAC INT := 3
3 (10)
Fraction ( Integer )
The operation retractIfCan tries to retract the fraction to the underlying domain Integer. It produces
a union object. Here it succeeds.
retractIfCan ( r )
82 CHAPTER 2. USING TYPES AND MODES
3 (11)
Union(Integer , ...)
3
(12)
2
Fraction ( Integer )
"failed" (13)
Like records (Section 2.4 on page 76), you can write Union types with selectors.
Be sure to understand the difference between records and unions with selectors. Records can have more
than one component and the selectors are used to refer to the components. Unions always have one
component but the type of that one component can vary. An object of type Record(a: Integer, b:
Float, c: String) contains an integer and a float and a string. An object of type Union(a: Integer,
b: Float, c: String) contains an integer or a float or a string.
Here is a version of the sayBranch function (cf. Section 2.5.1 on page 79) that works with a union
with selectors. It displays a message stating in which branch of the Union the object lies.
sayBranch(x:Union(i:Integer,s:String,f:Float)):Void==
output
x case i => "Integer branch"
x case s => "String branch"
"Float branch"
Note that case uses the selector name as its right-hand argument.
Declare variable u to have a union type with selectors.
2.6. THE “ANY” DOMAIN 83
false (3)
Boolean
u case s
true (4)
Boolean
String
3 2
1, 7.2, , x , "wally" (2)
2
List (Any)
1 (3)
PositiveInteger
Actually, these objects belong to Any but FriCAS automatically converts them to their natural types
for you.
u .3
3
(4)
2
Fraction ( Integer )
Since type Any can be anything, it can only belong to type Type. Therefore it cannot be used in
algebraic domains.
v : Matrix ( Any )
Matrix ( Any ) is not a valid type .
Perhaps you are wondering how FriCAS internally represents objects of type Any. An object of type
Any consists not only a data part representing its normal value, but also a type part (a badge) giving
its type. For example, the value 1 of type PositiveInteger as an object of type Any internally looks
like [1,PositiveInteger()].
2.7 Conversion
Conversion is the process of changing an object of one type into an object of another type. The
syntax for conversion is:
object :: newType
3 (1)
PositiveInteger
We can change this into an object of type Fraction Integer by using “::”.
3 :: Fraction Integer
3 (2)
Fraction ( Integer )
A coercion is a special kind of conversion that FriCAS is allowed to do automatically when you enter
an expression. Coercions are usually somewhat safer than more general conversions. The FriCAS
2.7. CONVERSION 85
library contains operations called coerce and convert. Only the coerce operations can be used by the
interpreter to change an object into an object of another type unless you explicitly use a “::”.
By now you will be quite familiar with what types and modes look like. It is useful to think of a
type or mode as a pattern for what you want the result to be. Let’s start with a square matrix of
polynomials with complex rational number coefficients.
m : SquareMatrix (2 , POLY COMPLEX FRAC INT )
x − 34 i y 2 z + 21
(4)
3
7
i y4 − x 12 − 95 i
SquareMatrix(2, Polynomial(Complex(Fraction(Integer))))
We first want to interchange the Complex and Fraction layers. We do the conversion by doing the
interchange in the type expression.
m1 := m :: SquareMatrix (2 , POLY FRAC COMPLEX INT )
x − 34i y2 z + 1
2 (5)
3i 4 60−9 i
7
y −x 5
" #
4 x−3 i 2 y 2 z+1
4 2 (6)
3 i y 4 −7 x 60−9 i
7 5
" #
4 x−3 i 2 y 2 z+1
4 2 (7)
−7 x+3 y 4 i 60−9 i
7 5
All the entries have changed types, although in comparing the last two results only the entry in the
lower left corner looks different. We did all the intermediate steps to show you what FriCAS can do.
In fact, we could have combined all these into one conversion.
m :: SquareMatrix (2 , FRAC COMPLEX POLY INT )
" #
4 x−3 i 2 y 2 z+1
4 2 (8)
−7 x+3 y 4 i 60−9 i
7 5
86 CHAPTER 2. USING TYPES AND MODES
There are times when FriCAS is not be able to do the conversion in one step. You may need to break
up the transformation into several conversions in order to get an object of the desired type.
We cannot move either Fraction or Complex above (or to the left of, depending on how you look
at it) SquareMatrix because each of these levels requires that its argument type have commutative
multiplication, whereas SquareMatrix does not.7 The Integer level did not move anywhere because
it does not allow any arguments. We also did not move the SquareMatrix part anywhere, but we
could have. Recall that m looks like this.
m
x − 34 i y 2 z + 21
(9)
3
7
i y4 − x 12 − 95 i
SquareMatrix(2, Polynomial(Complex(Fraction(Integer))))
If we want a polynomial with matrix coefficients rather than a matrix with polynomial entries, we can
just do the conversion.
m :: POLY SquareMatrix (2 , COMPLEX FRAC INT )
3 1
0 1 2 0 0 4 1 0 −4 i 2
y z+ 3 y + x+ 9 (10)
0 0 7
i 0 −1 0 0 12 − 5
i
Polynomial(SquareMatrix(2, Complex(Fraction(Integer))))
We have not yet used modes for any conversions. Modes are a great shorthand for indicating the type
of the object you want. Instead of using the long type expression in the last example, we could have
simply said this.
m :: POLY ?
3 1
0 1 2 0 0 4 1 0 −4 i 2
y z+ 3 y + x+ 9 (11)
0 0 7
i 0 −1 0 0 12 − 5
i
Polynomial(SquareMatrix(2, Complex(Fraction(Integer))))
We can also indicate more structure if we want the entries of the matrices to be fractions.
m :: POLY SquareMatrix (2 , FRAC ?)
3i 1
0 1 2 0 0 4 1 0 −4 2
y z + 3i y + x+ 60−9 i (12)
0 0 7
0 −1 0 0 5
argument belong to CommutativeRing. See Section 2.1 on page 65 for a brief discussion of categories.
2.8. SUBDOMAINS AGAIN 87
1. those elements of D that satisfy some predicate (that is, a test that returns true or false) and
2. a subset of the operations of D.
Every domain is a subdomain of itself, trivially satisfying the membership test: true.
Currently, there are only two system-defined subdomains in FriCAS that receive substantial use. Pos-
itiveInteger and NonNegativeInteger are subdomains of Integer. An element x of NonNega-
tiveInteger is an integer that is greater than or equal to zero, that is, satisfies x >= 0. An element
x of PositiveInteger is a nonnegative integer that is, in fact, greater than zero, that is, satisfies
x > 0. Not all operations from Integer are available for these subdomains. For example, negation
and subtraction are not provided since the subdomains are not closed under those operations. When
you use an integer in an expression, FriCAS assigns to it the type that is the most specific subdomain
whose predicate is satisfied. This is a positive integer.
5
5 (1)
PositiveInteger
0 (2)
NonNegativeInteger
−5 (3)
Integer
Furthermore, unless you are assigning an integer to a declared variable or using a conversion, any
integer result has as type the most specific subdomain.
( -2) - ( -3)
1 (4)
PositiveInteger
0 :: Integer
0 (5)
Integer
x : N o n N e g a t i v e I n t e g e r := 5
88 CHAPTER 2. USING TYPES AND MODES
5 (6)
NonNegativeInteger
When necessary, FriCAS converts an integer object into one belonging to a less specific subdomain.
For example, in 3-2, the arguments to - are both elements of PositiveInteger, but this type does
not provide a subtraction operation. Neither does NonNegativeInteger, so 3 and 2 are viewed as
elements of Integer, where their difference can be calculated. The result is 1, which FriCAS then
automatically assigns the type PositiveInteger.
Certain operations are very sensitive to the subdomains to which their arguments belong. This is an
element of PositiveInteger.
2 ^ 2
4 (7)
PositiveInteger
1
(8)
4
Fraction ( Integer )
List ( PositiveInteger )
What should the type of [10^(i-1)for i in 2..5] be? On one hand, i-1 is always an integer greater
than zero as i ranges from 2 to 5 and so 10^i is also always a positive integer. On the other, i-1 is a
very simple function of i. FriCAS does not try to analyze every such function over the index’s range
of values to determine whether it is always positive or nowhere negative. For an arbitrary FriCAS
function, this analysis is not possible.
So, to be consistent no such analysis is done and we get this.
[10^( i -1) for i in 2..5]
To get a list of elements of PositiveInteger instead, you have two choices. You can use a conversion.
[10^(( i -1) :: PI ) for i in 2..5]
Compiling function G297 with type Integer -> Boolean
Compiling function G299 with type N o n N e g a t i v e I n t e g e r -> Boolean
2.9. PACKAGE CALLING AND TARGET TYPES 89
List ( PositiveInteger )
List ( PositiveInteger )
The operation pretend is used to defeat the FriCAS type system. The expression object pretend D
means “make a new object (without copying) of type D from object.” If object were an integer and
you told FriCAS to pretend it was a list, you would probably see a message about a fatal error being
caught and memory possibly being damaged. Lists do not have the same internal representation as
integers!
You use pretend at your peril.
Use pretend with great care! FriCAS trusts you that the value is of the specified type.
(2/3) pretend Complex Integer
2 + 3i (13)
Complex(Integer)
2
(1)
3
Fraction ( Integer )
0.66666666666666666667 (2)
Float
2
(3)
3
Fraction (Complex(Integer))
In each case, FriCAS used the indicated operations, sometimes first needing to convert the two integers
into objects of an appropriate type. In these examples, / is written as an infix operator.
To use package calling with an infix operator, use the following syntax:
For an operator written before its arguments, you must use parentheses around the arguments
(even if there is only one), and follow the closing parenthesis by a “$” and then the type.
fun ( arg1 , arg1 , ..., argN )$type
For example, to call the “minimum” function from DoubleFloat on two integers, you could write
min(4,89)$DoubleFloat. Another use of package calling is to tell FriCAS to use a library function
rather than a function you defined. We discuss this in Section 6.9 on page 158.
Sometimes rather than specifying where an operation comes from, you just want to say what type the
result should be. We say that you provide a target type for the expression. Instead of using a “$”,
use a “@” to specify the requested target type. Otherwise, the syntax is the same. Note that giving a
target type is not the same as explicitly doing a conversion. The first says “try to pick operations so
that the result has such-and-such a type.” The second says “compute the result and then convert to
an object of such-and-such a type.”
Sometimes it makes sense, as in this expression, to say “choose the operations in this expression so
that the final result is a Float.”
(2/3) @Float
0.66666666666666666667 (4)
8 Float,because the package call causes FriCAS to convert (2 + 3) and 4 to type Float. Before the sum is converted,
it is given a target type (see below) of Float by FriCAS and then evaluated. The target type causes the + from Float
to be used.
2.9. PACKAGE CALLING AND TARGET TYPES 91
Float
Here we used “@” to say that the target type of the left-hand side was Float. In this simple case, there
was no real difference between using “$” and “@”. You can see the difference if you try the following.
This says to try to choose + so that the result is a string. FriCAS cannot do this.
(2 + 3) @String
An expression involving @ String actually evaluated to one of type
P os itiv e In te ge r . Perhaps you should use :: String .
This says to get the + from String and apply it to the two integers. FriCAS also cannot do this
because there is no + exported by String.
(2 + 3) $ String
The function + is not implemented in String .
(By the way, the operation concat or juxtaposition is used to concatenate two strings.)
When we have more than one operation in an expression, the difference is even more evident. The
following two expressions show that FriCAS uses the target type to create different objects. The +, *
and ^ operations are all chosen so that an object of the correct final type is created.
This says that the operations should be chosen so that the result is a Complex object.
(( x + y * % i ) ^2) @ ( Complex Polynomial Integer )
− y 2 + x2 + 2 x y i (5)
Complex(Polynomial(Integer))
This says that the operations should be chosen so that the result is a Polynomial object.
(( x + y * % i ) ^2) @ ( Polynomial Complex Integer )
− y 2 + 2 i x y + x2 (6)
Polynomial(Complex(Integer))
What do you think might happen if we left off all target type and package call information in this last
example?
( x + y * % i ) ^2
− y 2 + 2 i x y + x2 (7)
Polynomial(Complex(Integer))
We can convert it to Complex as an afterthought. But this is more work than just saying making
what we want in the first place.
% :: Complex ?
− y 2 + x2 + 2 x y i (8)
92 CHAPTER 2. USING TYPES AND MODES
Complex(Polynomial(Integer))
Finally, another use of package calling is to qualify fully an operation that is passed as an argument
to a function.
Start with a small matrix of integers.
h := matrix [[8 ,6] ,[ -4 ,9]]
8 6
(9)
−4 9
Matrix( Integer )
We want to produce a new matrix that has for entries the multiplicative inverses of the entries of h.
One way to do this is by calling map with the inv function from Fraction (Integer).
map ( inv $ Fraction ( Integer ) ,h )
1 1
8 6 (10)
− 14 1
9
Matrix(Fraction ( Integer ))
1 1
8 6 (11)
− 14 1
9
Matrix(Fraction ( Integer ))
As it turns out, FriCAS is smart enough to know what we mean anyway. We can just say this.
map ( inv , h )
1 1
8 6 (12)
− 14 1
9
Matrix(Fraction ( Integer ))
x (1)
Variable (x)
1 (2)
PositiveInteger
There are no operations in PositiveInteger that add positive integers to objects of type Variable(x)
nor are there any in Variable(x). Before it can add the two parts, FriCAS must come up with a
common type to which both x and 1 can be converted. We say that FriCAS must resolve the two types
into a common type. In this example, the common type is Polynomial(Integer).
Once this is determined, both parts are converted into polynomials, and the addition operation from
Polynomial(Integer) is used to get the answer.
x + 1
x+1 (3)
Polynomial( Integer )
FriCAS can always resolve two types: if nothing resembling the original types can be found, then Any
is be used. This is fine and useful in some cases.
[" string " ,3.14159]
List (Any)
In other cases objects of type Any can’t be used by the operations you specified.
" string " + 3.14159
There are 13 exposed and 11 unexposed library operations named + having 2
argument ( s ) but none was determined to be applicable . Use HyperDoc Browse ,
or issue
) display op +
to learn more about the available operations . Perhaps package - calling the
operation or using coercions on the arguments will allow you to apply the
operation .
Cannot find a definition or applicable library operation named + with argument
type ( s )
String
Float
Perhaps you should use " @ " to indicate the required return type , or " $ " to
specify which version of the function you need .
Although this example was contrived, your expressions may need to be qualified slightly to help FriCAS
resolve the types involved. You may need to declare a few variables, do some package calling, provide
some target type information or do some explicit conversions.
94 CHAPTER 2. USING TYPES AND MODES
We suggest that you just enter the expression you want evaluated and see what FriCAS does. We
think you will be impressed with its ability to “do what I mean.” If FriCAS is still being obtuse, give
it some hints. As you work with FriCAS, you will learn where it needs a little help to analyze quickly
and perform your computations.
basic
AlgebraicNumber AN
AlgebraGivenByStructuralConstants ALGSC
Any ANY
AnyFunctions1 ANY1
BinaryExpansion BINARY
Boolean BOOLEAN
CardinalNumber CARD
CartesianTensor CARTEN
Character CHAR
CharacterClass CCLASS
CliffordAlgebra CLIF
Color COLOR
Complex COMPLEX
ContinuedFraction CONTFRAC
DecimalExpansion DECIMAL
...
categories
AbelianGroup ABELGRP
AbelianMonoid ABELMON
AbelianMonoidRing AMR
AbelianSemiGroup ABELSG
Aggregate AGG
Algebra ALGEBRA
AlgebraicallyClosedField ACF
AlgebraicallyClosedFunctionSpace ACFS
2.11. EXPOSING DOMAINS AND PACKAGES 95
ArcHyperbolicFunctionCategory AHYP
...
For each constructor in a group, the full name and the abbreviation is given. There are other groups
in exposed.lsp but initially only the constructors in exposure groups “basic” and “categories” are
exposed.
As an interactive user of FriCAS, you do not need to modify this file. Instead, use )set expose to
expose, hide or query the exposure status of an individual constructor or exposure group. The reason for
having exposure groups is to be able to expose or hide multiple constructors with a single command.
For example, you might group together into exposure group “quantum” a number of domains and
packages useful for quantum mechanical computations. These probably should not be available to
every user, but you want an easy way to make the whole collection visible to FriCAS when it is looking
for operations to apply.
If you wanted to hide all the basic constructors available by default, you would issue )set expose
drop group basic. We do not recommend that you do this. If, however, you discover that you have
hidden all the basic constructors, you should issue )set expose add group basic to restore your
default environment.
It is more likely that you would want to expose or hide individual constructors. In Section 6.19 on page
184 we use several operations from OutputForm, a domain usually hidden. To avoid package calling
every operation from OutputForm, we expose the domain and let FriCAS conclude that those oper-
ations should be used. Use )set expose add constructor and )set expose drop constructor to
expose and hide a constructor, respectively. You should use the constructor name, not the abbreviation.
The )set expose command guides you through these options.
If you expose a previously hidden constructor, FriCAS exhibits new behavior (that was your intention)
though you might not expect the results that you get. OutputForm is, in fact, one of the worst
offenders in this regard. This domain is meant to be used by other domains for creating a structure
that FriCAS knows how to display. It has functions like + that form output representations rather than
do mathematical calculations. Because of the order in which FriCAS looks at constructors when it is
deciding what operation to apply, OutputForm might be used instead of what you expect. This is
a polynomial.
x + x
2x (1)
Polynomial( Integer )
Expose OutputForm.
) set expose add constructor OutputForm
OutputForm is now explicitly exposed in frame initial
x+x (2)
96 CHAPTER 2. USING TYPES AND MODES
OutputForm
Hide OutputForm so we don’t run into problems with any later examples!
) set expose drop constructor OutputForm
OutputForm is now explicitly hidden in frame initial
Finally, exposure is done on a frame-by-frame basis. A frame (see Section A.11 on page 745) is one
of possibly several logical FriCAS workspaces within a physical one, each having its own environment
(for example, variables and function definitions). If you have several FriCAS workspace windows on
your screen, they are all different frames, automatically created for you by HyperDoc. Frames can
be manually created, made active and destroyed by the )frame system command. They do not share
exposure information, so you need to use )set expose in each one to add or drop constructors from
view.
If you want to see all domains with “matrix” in their names, issue this.
) what domain matrix
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Domains - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2.12. COMMANDS FOR SNOOPING 97
Similarly, if you wish to see all packages whose names contain “gauss”, enter this.
) what package gauss
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Packages - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This command shows all the operations that Any provides. Wherever “%” appears, it means “Any”.
) show Any
Any is a domain constructor .
Abbreviation for Any is ANY
This constructor is exposed in this frame .
10 Names for 10 Operations in this Domain .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Operations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Let’s analyze this output. First we find out what some of the abbreviations mean.
) abbreviation query COMPCAT
COMPCAT abbreviates category Co m pl ex Ca t eg or y
) abbreviation query COMRING
COMRING abbreviates category Co m mu ta ti v eR in g
Using HyperDoc
HyperDoc is the gateway to FriCAS. It’s both an on-line tutorial and an on-line reference manual.
It also enables you to use FriCAS simply by using the mouse and filling in templates. HyperDoc is
available to you if you are running FriCAS under the X Window System.
Pages usually have active areas, marked in this font (bold face). As you move the mouse pointer to
an active area, the pointer changes from a filled dot to an open circle. The active areas are usually
linked to other pages. When you click on an active area, you move to the linked page.
3.1 Headings
Most pages have a standard set of buttons at the top of the page. This is what they mean:
99
100 CHAPTER 3. USING HYPERDOC
Click on this to get help. The button only appears if there is specific help for the page you are
viewing. You can get general help for HyperDoc by clicking the help button on the home page.
Click here to go back one page. By clicking on this button repeatedly, you can go back several
pages and then take off in a new direction.
Go back to the home page, that is, the page on which you started. Use HyperDoc to explore, to
make forays into new topics. Don’t worry about how to get back. HyperDoc remembers where
you came from. Just click on this button to return.
From the root window (the one that is displayed when you start the system) this button leaves
the HyperDoc program, and it must be restarted if you want to use it again. From any other
HyperDoc window, it just makes that one window go away. You must use this button to get rid
of a window. If you use the window manager “Close” button, then all of HyperDoc goes away.
The buttons are not displayed if they are not applicable to the page you are viewing. For example,
there is no button on the top-level menu.
F3 Same as , makes the window go away if you are not at the top-level window or quits the
HyperDoc facility if you are at the top-level.
F5 Rereads the HyperDoc database, if necessary (for system developers).
F9 Displays this information about key definitions.
F12 Same as F3.
parts. It also shows where the aperture is relative to the whole text. The aperture is indicated by a
strip on the scroll bar.
Move the cursor with the mouse to the “down-arrow” at the bottom of the scroll bar and click. See
that the aperture moves down one line. Do it several times. Each time you click, the aperture moves
down one line. Move the mouse to the “up-arrow” at the top of the scroll bar and click. The aperture
moves up one line each time you click.
Next move the mouse to any position along the middle of the scroll bar and click. HyperDoc attempts
to move the top of the aperture to this point in the text.
You cannot make the aperture go off the bottom edge. When the aperture is about half the size of
text, the lowest you can move the aperture is halfway down.
To move up or down one screen at a time, use the PageUp and PageDown keys on your keyboard.
They move the visible part of the region up and down one page each time you press them.
If the HyperDoc page does not contain an input area (see Section 3.4 on page 101), you can also use
the Home and ↑ and ↓ arrow keys to navigate. When you press the Home key, the screen is
positioned at the very top of the page. Use the ↑ and ↓ arrow keys to move the screen up and down
one line at a time, respectively.
The glossary has an input area at its bottom. We review the various kinds of search strings you can
enter to search the glossary.
The simplest search string is a word, for example, operation. A word only matches an entry having
exactly that spelling. Enter the word operation into the input area above then click on Search. As
you can see, operation matches only one entry, namely with operation itself.
Normally matching is insensitive to whether the alphabetic characters of your search string are in
uppercase or lowercase. Thus operation and OperAtion both have the same effect.
You will very often want to use the wildcard “*” in your search string so as to match multiple entries
in the list. The search key “*” matches every entry in the list. You can also use “*” anywhere within
a search string to match an arbitrary substring. Try cat* for example: enter cat* into the input area
and click on Search. This matches several entries.
You use any number of wildcards in a search string as long as they are not adjacent. Try search strings
such as *dom*. As you see, this search string matches domain, domain constructor, subdomain, and
so on.
For more complicated searches, you can use “and”, “or”, and “not” with basic search strings; write
logical expressions using these three operators just as in the FriCAS language. For example, domain or
package matches the two entries domain and package. Similarly, dom* and *con* matches domain
constructor and others. Also not *a* matches every entry that does not contain the letter a some-
where.
Use parentheses for grouping. For example, dom* and (not *con*) matches domain but not domain
constructor.
3.7. EXAMPLE PAGES 103
There is no limit to how complex your logical expression can be. For example,
is a valid expression.
FriCAS.hyperdoc.RmFont: font
This is the standard text font. The default value is "Rom14".
FriCAS.hyperdoc.RmColor: color
This is the standard text color. The default value is "black".
FriCAS.hyperdoc.ActiveFont: font
This is the font used for HyperDoc link buttons. The default value is "Bld14".
FriCAS.hyperdoc.ActiveColor: color
This is the color used for HyperDoc link buttons. The default value is "black".
FriCAS.hyperdoc.FriCASFont: font
This is the font used for active FriCAS commands. The default value is "Bld14".
FriCAS.hyperdoc.FriCASColor: color
This is the color used for active FriCAS commands. The default value is "black".
FriCAS.hyperdoc.BoldFont: font
This is the font used for bold face. The default value is "Bld14".
104 CHAPTER 3. USING HYPERDOC
FriCAS.hyperdoc.BoldColor: color
This is the color used for bold face. The default value is "black".
FriCAS.hyperdoc.TtFont: font
This is the font used for FriCAS output in HyperDoc. This font must be fixed-width. The default
value is "Rom14".
FriCAS.hyperdoc.TtColor: color
This is the color used for FriCAS output in HyperDoc. The default value is "black".
FriCAS.hyperdoc.EmphasizeFont: font
This is the font used for italics. The default value is "Itl14".
FriCAS.hyperdoc.EmphasizeColor: color
This is the color used for italics. The default value is "black".
FriCAS.hyperdoc.InputBackground: color
This is the color used as the background for input areas. The default value is "black".
FriCAS.hyperdoc.InputForeground: color
This is the color used as the foreground for input areas. The default value is "white".
FriCAS.hyperdoc.BorderColor: color
This is the color used for drawing border lines. The default value is "black".
FriCAS.hyperdoc.Background: color
This is the color used for the background of all windows. The default value is "white".
Note: In the past resource names used word Axiom instead of FriCAS.
Chapter 4
In this chapter we discuss how to collect FriCAS statements and commands into files and then read the
contents into the workspace. We also show how to display the results of your computations in several
different styles including TEX, FORTRAN and monospace two-dimensional format.1
The printed version of this book uses the FriCAS TEX output formatter. When we demonstrate a
particular output style, we will need to turn TEX formatting off and the output style on so that the
correct output is shown in the text.
)read /spad/src/input/matrix.input
)read /spad/src/input/matrix
What happens if you just enter )read matrix.input or even )read matrix? FriCAS looks in your
current working directory for input files that are not qualified by a directory name. Typically, this
directory is the directory from which you invoked FriCAS. To change the current working directory,
1T
EX is a trademark of the American Mathematical Society.
105
106 CHAPTER 4. INPUT FILES AND OUTPUT STYLES
use the )cd system command. The command )cd by itself shows the current working directory. To
change it to the src/input subdirectory for user “babar”, issue
)cd /u/babar/src/input
FriCAS looks first in this directory for an input file. If it is not found, it looks in the system’s directories,
assuming you meant some input file that was provided with FriCAS.
If you have the FriCAS history facility turned on (which it is by default), you can save all the lines
you have entered into the workspace by entering
)history )write
FriCAS tells you what input file to edit to see your statements. The file is in your home directory
or in the directory you specified with )cd.
In Section 5.2 on page 126 we discuss using indentation in input files to group statements into blocks.
You must also turn on the creation of FORTRAN output. The above just says where it goes if it is
created.
) set output fortran on
In what directory is this output placed? It goes into the directory from which you started FriCAS, or
if you have used the )cd system command, the one that you specified with )cd. You should use )cd
before you send the output to the file.
You can always direct output back to the screen by issuing this.
) set output fortran console
Let’s make sure FORTRAN formatting is off so that nothing we do from now on produces FORTRAN
output.
) set output fortran off
You can abbreviate the words “on,” “off” and “console” to the minimal number of characters needed
to distinguish them. Because of this, you cannot send output to files called on.sfort, off.sfort,
of.sfort, console.sfort, consol.sfort and so on.
The width of the output on the page is set by )set output length for all formats except FORTRAN.
Use )set fortran fortlength to change the FORTRAN line length from its default value of 72.
Since the printed version of this book (as opposed to the HyperDoc version) shows output produced
by the TEX output formatter, let us temporarily turn off TEX output.
108 CHAPTER 4. INPUT FILES AND OUTPUT STYLES
+ 3 3 2+
|3%i y + x 3%i y + 2x |
| |
| 4 4 2|
+4%i y + x 4%i y + 2x +
The characters used for the matrix brackets above are rather ugly. You get this character set when
you issue )set output characters plain. This character set should be used when your machine or
your version of FriCAS does not support Unicode character set. If your machine and your version of
FriCAS support Unicode, issue )set output characters default to get better looking output.
\begin{fricasmath}{1}
\begin{MATRIX}{2}3\TIMES \ImaginaryI \TIMES \SUPER{\SYMBOL{y}}{3}+\SYMBOL{x}&%
3\TIMES \ImaginaryI \TIMES \SUPER{\SYMBOL{y}}{3}+2\TIMES \SUPER{\SYMBOL{x}}{2%
}\\4\TIMES \ImaginaryI \TIMES \SUPER{\SYMBOL{y}}{4}+\SYMBOL{x}&4\TIMES %
\ImaginaryI \TIMES \SUPER{\SYMBOL{y}}{4}+2\TIMES \SUPER{\SYMBOL{x}}{2}%
\end{MATRIX}%
\end{fricasmath}
3 See Leslie Lamport, LaTeX: A Document Preparation System, Reading, Massachusetts: Addison-Wesley Publishing
With the definition of the fricasmath environment as defined in fricasmath.sty this formats as
3 i y3 + x 3 i y 3 + 2 x2
(1)
4 i y4 + x 4 i y 4 + 2 x2
To turn TEX output formatting off, issue )set output tex off. The LATEX macros in the output
generated by FriCAS are generic. See the source file of TexFormat for appropriate definitions of these
commands.
x+sqrt(2)
x+sqrt(2)
For the initial examples, we set the optimization level to 0, which is the lowest level.
) set fortran optlevel 0
The output is usually in columns 7 through 72, although fewer columns are used in the following
examples so that the output fits nicely on the page.
) set fortran fortlength 60
By default, the output goes to the screen and is displayed before the standard FriCAS two-dimensional
output. In this example, an assignment to the variable R1 was generated because this is the result of
step 1.
( x + y ) ^3
y 3 + 3 x y 2 + 3 x2 y + x3 (1)
Polynomial( Integer )
z 3 + (3 y + 3 x) z 2 + 3 y 2 + 6 x y + 3 x2 z + y 3 + 3 x y 2 + 3 x2 y + x3
(2)
Polynomial( Integer )
Note in the above examples that integers are generally converted to floating point numbers, except in
exponents. This is the default behavior but can be turned off by issuing )set fortran ints2floats
off. The rules governing when the conversion is done are:
These rules only govern integers in expressions. Numbers generated by FriCAS for DIMENSION state-
ments are also integers.
To set the type of generated FORTRAN data, use one of the following:
4.8. FORTRAN FORMAT 111
When temporaries are created, they are given a default type of REAL. Also, the REAL versions of
functions are used by default.
sin ( x )
sin(x) (3)
Expression ( Integer )
( x + y + z ) ^3
z 3 + (3 y + 3 x) z 2 + 3 y 2 + 6 x y + 3 x2 z + y 3 + 3 x y 2 + 3 x2 y + x3
(4)
Polynomial( Integer )
This changes the precision to DOUBLE. Substitute single for double to return to single precision.
) set fortran precision double
Complex(Float)
The function names that FriCAS generates depend on the chosen precision.
sin % e
sin(e) (6)
Expression ( Integer )
Reset the precision to single and look at these two examples again.
) set fortran precision single
2.3 + 5.6*% i
Complex(Float)
sin % e
sin(e) (8)
Expression ( Integer )
Expressions that look like lists, streams, sets or matrices cause array code to be generated.
[ x +1 , y +1 , z +1]
[x + 1, y + 1, z + 1] (9)
A temporary variable is generated to be the name of the array. This may have to be changed in your
particular application.
set [2 ,3 ,4 ,3 ,5]
{2, 3, 4, 5} (10)
Set( PositiveInteger )
2.3 9.7
(11)
0.0 18.778
Matrix(Float)
To change the starting index for generated FORTRAN arrays to be 1, issue this. This value can only
be 0 or 1.
) set fortran startindex 1
2.3 9.7
(12)
0.0 18.778
Matrix(Float)
A template is a skeletal program which is “fleshed out” with data when it is processed. It is a sequence
of active and passive parts: active parts are sequences of FriCAS commands which are processed as
if they had been typed into the interpreter; passive parts are simply echoed verbatim on the Fortran
output stream.
Suppose, for example, that we have the following template, stored in the file “test.tem”:
-- A simple template
beginVerbatim
DOUBLE PRECISION FUNCTION F(X)
DOUBLE PRECISION X
endVerbatim
outputAsFortran("F",f)
beginVerbatim
RETURN
END
endVerbatim
The passive parts lie between the two tokens beginVerbatim and
endVerbatim. There are two active statements: one which is simply a FriCAS ( --) comment, and
one which produces an assignment to the current value of f. We could use it as follows:
4
(4) ------
2
X + 1
(5) "CONSOLE"
(A more reliable method of specifying the filename will be introduced below.) Note that the Fortran
assignment F=4.0D0/(X*X+1.0D0) automatically converted 4.0 and 1 into DOUBLE PRECISION
numbers; in general, the FriCAS Fortran generation facility will convert anything which should be a
floating point object into either a Fortran REAL or DOUBLE PRECISION object. Which alternative
is used is determined by the command
) set fortran precision
It is sometimes useful to end a template before the file itself ends (e.g. to allow the template to be
tested incrementally or so that a piece of text describing how the template works can be included).
It is of course possible to “comment-out” the remainder of the file. Alternatively, the single token
114 CHAPTER 4. INPUT FILES AND OUTPUT STYLES
endInput as part of an active portion of the template will cause processing to be ended prematurely
at that point.
The processTemplate command comes in two flavours. In the first case, illustrated above, it takes one
argument of domain FileName, the name of the template to be processed, and writes its output on
the current Fortran output stream. In general, a filename can be generated from directory, name and
extension components, using the operation filename, as in
processTemplate filename("","test","tem")
There is an alternative version of processTemplate, which takes two arguments (both of domain File-
Name). In this case the first argument is the name of the template to be processed, and the second is
the file in which to write the results. Both versions return the location of the generated Fortran code
as their result ("CONSOLE" in the above example).
It is sometimes useful to be able to mix active and passive parts of a line or statement. For example
you might want to generate a Fortran Comment describing your data set. For this kind of application
we provide three functions as follows:
1 2 3
(1)
4 5 6
Matrix( Integer )
or, alternatively:
fort ranLiter al (" C \ \ \ \ \ \ The \ Matrix \ has \ ") $ F o r t r a n T e m p l a t e
f o r t r a n C a r r i a g e R e t u r n () $ F o r t r a n T e m p l a t e
4.9. GENERAL FORTRAN-GENERATION UTILITIES IN FRICAS 115
We should stress that these functions, together with the outputAsFortran function are the only sure
ways of getting output to appear on the Fortran output stream. Attempts to use FriCAS commands
such as output or writeline! may appear to give the required result when displayed on the console, but
will give the wrong result when Fortran and algebraic output are sent to differing locations. On the
other hand, these functions can be used to send helpful messages to the user, without interfering with
the generated Fortran.
Sometimes it is useful to manipulate the Fortran output stream in a program, possibly without being
aware of its current value. The main use of this is for gathering type declarations (see “Fortran Types”
below) but it can be useful in other contexts as well. Thus we provide a set of commands to manipulate
a stack of (open) output streams. Only one stream can be written to at any given time. The stack
is never empty—its initial value is the console or the current value of the Fortran output stream, and
can be determined using
t o p F o r t r a n O u t p u t S t a c k () $ F o r t r a n O u t p u t S t a c k P a c k a g e
"/dev/shm/hemmecke/fricas/b/src/doc/linalg.sfort" (1)
String
When generating code it is important to keep track of the Fortran types of the objects which we are
generating. This is useful for a number of reasons, not least to ensure that we are actually generating
legal Fortran code. The current type system is built up in several layers, and we shall describe each in
turn.
4.9.4 FortranScalarType
This domain represents the simple Fortran datatypes: REAL, DOUBLE PRECISION, COMPLEX,
LOGICAL, INTEGER, and CHARACTER. It is possible to coerce a String or Symbol into the
domain, test whether two objects are equal, and also apply the predicate functions real? etc.
116 CHAPTER 4. INPUT FILES AND OUTPUT STYLES
4.9.5 FortranType
This domain represents “full” types: i.e., datatype plus array dimensions (where appropriate) plus
whether or not the parameter is an external subprogram. It is possible to coerce an object of For-
tranScalarType into the domain or construct one from an element of FortranScalarType, a list
of Polynomial Integers (which can of course be simple integers or symbols) representing its dimen-
sions, and a Boolean declaring whether it is external or not. The list of dimensions must be empty if
the Boolean is true. The functions scalarTypeOf, dimensionsOf and external? return the appropriate
parts, and it is possible to get the various basic Fortran Types via functions like fortranReal. For
example:
type := construct ( real ,[ i ,10] , false ) $ FortranType
or
type :=[ real ,[ i ,10] , false ] $ FortranType
scalarTypeOf type
REAL (1)
dimensionsOf type
external ? type
false (3)
Boolean
fort ranLogic al () $ FortranType
LOGICAL (4)
FortranType
4.9.6 SymbolTable
This domain creates and manipulates a symbol table for generated Fortran code. This is used by
FortranProgram to represent the types of objects in a subprogram. The commands available are:
4.9. GENERAL FORTRAN-GENERATION UTILITIES IN FRICAS 117
table () (1)
SymbolTable
REAL (2)
FortranType
IN T EGER (3)
FortranType
symbols
fortranTypeOf (i , symbols )
IN T EGER (4)
FortranType
printTypes symbols
118 CHAPTER 4. INPUT FILES AND OUTPUT STYLES
4.9.7 TheSymbolTable
This domain creates and manipulates one global symbol table to be used, for example, during template
processing. It is also used when linking to external Fortran routines. The information stored for each
subprogram (and the main program segment, where relevant) is:
its name;
Initially, any information provided is deemed to be for the main program segment. Issuing the
following command indicates that from now on all information refers to the subprogram F.
newSubProgram ( F ) $ T he Sy m bo lT ab l e
It is possible to return to processing the main program segment by issuing the command:
endSubProgram () $ T he Sy mb o lT ab l e
M AIN (2)
Symbol
In addition there are versions of these commands which are parameterised by the name of a subprogram,
and others parameterised by both the name of a subprogram and by an instance of TheSymbol-
Table.
newSubProgram ( F ) $ T he Sy m bo lT ab l e
4.9. GENERAL FORTRAN-GENERATION UTILITIES IN FRICAS 119
argumentList !( F , [ X ]) $ T he Sy m bo lT ab l e
returnType !( F , real ) $ T he Sy m bo lT ab l e
declare !( X , fortranReal () ,F ) $ T he Sy mb o lT ab l e
REAL (6)
FortranType
printHeader ( F ) $ T he Sy mb o lT ab l e
This section describes facilities for representing Fortran statements, and building up complete subpro-
grams from them.
4.9.9 Switch
This domain is used to represent statements like x < y. Although these can be represented directly in
FriCAS, it is a little cumbersome.
Instead we have a set of operations, such as LT to represent <, to let us build such statements. The
available constructors are:
LT <
GT >
LE ≤
GE ≥
EQ =
AND and
OR or
NOT not
So for example:
LT (x , y ) $ Switch
x<y (1)
Switch
4.9.10 FortranCode
This domain represents code segments or operations: currently assignments, conditionals, blocks, com-
ments, gotos, continues, various kinds of loops, and return statements. For example we can create
quite a complicated conditional statement using assignments, and then turn it into Fortran code:
c :=
cond ( LT (X , Y ) , assign (F , X ) , cond ( GT (Y , Z ) , assign (F , Y ) , assign (F , Z ) ) $ FortranCode ) $ FortranCode
120 CHAPTER 4. INPUT FILES AND OUTPUT STYLES
"conditional" (1)
FortranCode
printCode c
4.9.11 FortranProgram
This domain is used to construct complete Fortran subprograms out of elements of FortranCode. It is
parameterised by the name of the target subprogram (a Symbol), its return type (from Union(FortranScalarType,“void
its arguments (from List Symbol), and its symbol table (from SymbolTable). One can coerce ele-
ments of either FortranCode or Expression into it.
First of all we create a symbol table:
symbols := empty () $ SymbolTable
table () (1)
SymbolTable
REAL (2)
FortranType
Type
X sin(Y ) (4)
Expression ( Integer )
We can generate a FortranProgram using FortranCode. For example: Augment our symbol
table:
declare !( Z , fortranReal () $ FortranType , symbols )
4.9. GENERAL FORTRAN-GENERATION UTILITIES IN FRICAS 121
REAL (6)
FortranType
prepare conditional:
cc := cond ( LT (X , Y ) , assign (F , X ) , assign (F , Y ) ) $ FortranCode
"conditional" (7)
FortranCode
In this chapter we look at some of the basic components of the FriCAS language that you can use
interactively. We show how to create a block of expressions, how to form loops and list iterations, how
to modify the sequential evaluation of a block and how to use if-then-else to evaluate parts of your
program conditionally. We suggest you first read the boxed material in each section and then proceed
to a more thorough reading of the chapter.
a tooBig? a1B2c3%!?
A %j numberOfPoints
beta6 %J numberofpoints
The “:=” operator is the immediate assignment operator. Use it to associate a value with a variable.
The right-hand side of the expression is evaluated, yielding 1. This value is then assigned to a.
a := 1
123
124 CHAPTER 5. INTRODUCTION TO THE FRICAS INTERACTIVE LANGUAGE
1 (1)
PositiveInteger
The right-hand side of the expression is evaluated, yielding 1. This value is then assigned to b. Thus
a and b both have the value 1 after the sequence of assignments.
b := a
1 (2)
PositiveInteger
2 (3)
PositiveInteger
1 (4)
PositiveInteger
This is what we mean when we say this kind of assignment is 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, PASCAL and FORTRAN.
FriCAS provides delayed assignment with “==”. This implements a delayed evaluation of the right-hand
side and dependency checking.
b == a
The right-hand side of each delayed assignment is left unevaluated until the variables on the left-hand
sides are evaluated. Therefore this evaluation and . . .
a
Compiling body of rule a to compute value of type Po si t iv eI n te ge r
5.1. IMMEDIATE AND DELAYED ASSIGNMENTS 125
1 (7)
PositiveInteger
1 (8)
PositiveInteger
If we change a to 2
a == 2
Compiled code for a has been cleared .
Compiled code for b has been cleared .
1 old definition ( s ) deleted for function or rule a
2 (10)
PositiveInteger
2 (11)
PositiveInteger
It is possible to set several variables at the same time by using a tuple of variables and a tuple of
expressions.1
2 (12)
PositiveInteger
Multiple immediate assignments 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.
(x , y ) := (y , x )
1 (13)
PositiveInteger
2 (14)
PositiveInteger
1 (15)
PositiveInteger
There is no syntactic form for multiple delayed assignments. See the discussion in Section 6.8 on page
158 about how FriCAS differentiates between delayed assignments and user functions of no arguments.
5.2 Blocks
A block is a sequence of expressions evaluated in the order that they appear, except as modified by
control expressions such as break, return, iterate and if-then-else constructions. The value of a
block is the value of the expression last evaluated in the block.
To leave a block early, use “=>”. For example, i < 0 => x. The expression before the “=>” must
evaluate to true or false. The expression following the “=>” is the return value for the block.
A block can be constructed in two ways:
1. the expressions can be separated by semicolons and the resulting expression surrounded by paren-
theses, and
2. the expressions can be written on succeeding lines with each line indented the same number of
spaces (which must be greater than zero). A block entered in this form is called a pile.
Only the first form is available if you are entering expressions directly to FriCAS. Both forms are
available in .input files.
5.2. BLOCKS 127
In .input files, blocks can also be written using piles. The examples throughout this book are assumed
to come from .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.
a :=
i := gcd (234 ,672)
i := 3* i ^5 - i + 1
1 / i
1
(1)
23323
Fraction ( Integer )
Here is the same block written on one line. This is how you are required to enter it at the input
prompt.
a := ( i := gcd (234 ,672) ; i := 3* i ^5 - i + 1; 1 / i )
1
(2)
23323
Fraction ( Integer )
Blocks can be used to put several expressions on one line. The value returned is that of the last
expression.
( a := 1; b := 2; c := 3; [a ,b , c ])
[1, 2, 3] (3)
List ( PositiveInteger )
FriCAS gives you two ways of writing a block and the preferred way in an .input file is to use a pile.
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. FriCAS
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.
d :=
c := a ^2 + b ^2
sqrt ( c * 1.3)
128 CHAPTER 5. INTRODUCTION TO THE FRICAS INTERACTIVE LANGUAGE
2.549509756796392415 (4)
Float
Blocks can be used in the arguments to functions. (Here h is assigned 2.1 + 3.5.)
h := 2.1 +
1.0
3.5
5.6 (5)
Float
Here the second argument to eval is x = z, where the value of z is computed in the first line of the
block starting on the second line.
eval ( x ^2 - x * y ^2 ,
z := % pi /2.0 - exp (4.1)
x = z
)
Polynomial(Float)
Blocks can be used in the clauses of if-then-else expressions (see Section 5.3 on page 129).
if h > 3.1 then 1.0 else ( z := cos ( h ) ; max (z ,0.5) )
1.0 (7)
Float
1.0 (8)
Float
482630400 (9)
PositiveInteger
c :=
d := eulerPhi (22)
factorial ( d )
b+c
482630400 (10)
PositiveInteger
Since c + d does equal 3628855, a has the value of c and the last line is never evaluated.
a :=
c := factorial 10
d := fibonacci 10
c + d = 3628855 = > c
d
3628800 (11)
PositiveInteger
5.3 if-then-else
Like many other programming languages, FriCAS uses the three keywords if, then and else to form
conditional expressions. The else part of the conditional is optional. The expression between the if
and then keywords is a predicate: an expression that evaluates to or is convertible to either true or
false, that is, a Boolean.
where the else expression2 part is optional. The value returned from a conditional expression
is expression1 if the predicate evaluates to true and expression2 otherwise. If no else clause is
given, the value is always the unique value of Void.
An if-then-else expression always returns a value. If the else clause is missing then the entire
expression returns the unique value of Void. If both clauses are present, the type of the value returned
by if is obtained by resolving the types of the values of the two clauses. See Section 2.10 on page 92
for more information.
The predicate must evaluate to, or be convertible to, an object of type Boolean: true or false. By
default, the equal sign = creates an equation.
This is an equation. In particular, it is an object of type Equation Polynomial Integer.
x + 1 = y
x+1=y (1)
130 CHAPTER 5. INTRODUCTION TO THE FRICAS INTERACTIVE LANGUAGE
Equation(Polynomial(Integer ))
However, for predicates in if expressions, FriCAS places a default target type of Boolean on the
predicate and equality testing is performed. Thus you need not qualify the “=” in any way. In other
contexts you may need to tell FriCAS that you want to test for equality rather than create an equation.
In those cases, use “@” and a target type of Boolean. See Section 2.9 on page 89 for more information.
The compound symbol meaning “not equal” in FriCAS is ~=. This can be used directly without a
package call or a target specification. The expression a ~= b is directly translated into not (a = b).
Many other functions have return values of type Boolean. These include <, <=, >, >=, ~= and member?.
By convention, operations with names ending in “?” return Boolean values.
The usual rules for piles are suspended for conditional expressions. In .input files, the then and else
keywords can begin in the same column as the corresponding if but may also appear to the right.
Each of the following styles of writing if-then-else expressions is acceptable:
if i > 0
then output("positive")
else output("nonpositive")
if i > 0
then output("positive")
else output("nonpositive")
A block can follow the then or else keywords. In the following two assignments to a, the then and
else clauses each are followed by two-line piles. The value returned in each is the value of the second
line.
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
5.4. LOOPS 131
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))
5.4 Loops
A loop is an expression that contains another expression, called the loop body, which is to be evaluated
zero or more times. All loops contain the repeat keyword and return the unique value of Void. Loops
can contain inner loops to any depth.
Unless loopBody contains a break or return expression, the loop repeats forever. The value
returned by the loop is the unique value of Void.
FriCAS 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 FriCAS decides that it cannot compile the loop, it issues a message stating the problem and then
the following message:
It is still possible that FriCAS can evaluate the loop but in interpret-code mode. See Section 6.10 on
page 160 where this is discussed in terms of compiling versus interpreting functions.
A return expression is used to exit a function with a particular value. In particular, if a return is in
a loop within the function, the loop is terminated whenever the return is evaluated. Suppose we
start with this.
f () ==
i := 1
repeat
if factorial ( i ) > 1000 then return i
i := i + 1
132 CHAPTER 5. INTRODUCTION TO THE FRICAS INTERACTIVE LANGUAGE
When 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).
f ()
Compiling function f with type () -> Void
What went wrong? Isn’t it obvious that this function should return an integer? Well, FriCAS 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 FriCAS 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 Void! So the return type of f
is Void.
There are two ways to fix this. The best way is for you to tell FriCAS what the return type of f is. You
do this by giving f a declaration f: () → Integer prior to calling for its value. This tells FriCAS:
“trust me—an integer is returned.” We’ll explain more about this in the next chapter. Another clumsy
way is to add a dummy expression as follows.
Since we want an integer, let’s stick in a dummy final expression that is an integer and will never be
evaluated.
f () ==
i := 1
repeat
if factorial ( i ) > 1000 then return i
i := i + 1
0
Compiled code for f has been cleared .
1 old definition ( s ) deleted for function or rule f
When we try f again we get what we wanted. See Section 6.15 on page 172 for more information.
f ()
Compiling function f with type () -> N o n N e g a t i v e I n t e g e r
7 (4)
PositiveInteger
The break keyword is often more useful in terminating a loop. A break causes control to transfer to
the expression immediately following the loop. As loops always return the unique value of Void, you
cannot return a value with break. That is, break takes no argument.
This example is a modification of the last example in the previous section. Instead of using return,
we’ll use break.
f () ==
i := 1
repeat
if factorial ( i ) > 1000 then break
i := i + 1
i
The loop terminates when 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.
5.4. LOOPS 133
f ()
Compiling function f with type () -> P os it iv e In te g er
7 (2)
PositiveInteger
You can only use 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.
(i , j ) := (1 , 1)
1 (3)
PositiveInteger
Nested loops must have multiple break expressions at the appropriate nesting level. How would you
rewrite this so (i + j) > 10 is only evaluated once?
repeat
repeat
if ( i + j ) > 10 then break
j := j + 1
if ( i + j ) > 10 then break
i := i + 1
i := 1 i := 1
repeat repeat
i := i + 1 i := i + 1
i > 3 => i if i > 3 then break
output(i) output(i)
In the example on the left, the values 2 and 3 for i are displayed but then the “=>” does not allow
control to reach the call to output 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 “=>” only means
to leave the block, not the loop.
In the example on the right, upon reaching 4, the break will be executed, and both the block and the
loop will terminate. This is one of the reasons why both “=>” and break are provided. Using a while
clause (see below) with the “=>” lets you simulate the action of break.
Here we give four examples of repeat loops that terminate when a value exceeds a given bound.
i := 0
0 (1)
NonNegativeInteger
Here is the first loop. When the square of i exceeds 100, the loop terminates.
repeat
i := i + 1
if i ^2 > 100 then break
11 (3)
NonNegativeInteger
0 (4)
NonNegativeInteger
repeat
i := i + 1
i ^2 > 100 = > break
11 (6)
NonNegativeInteger
1 (7)
PositiveInteger
933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272
(9)
PositiveInteger
Finally, we show an example of nested loops. First define a four by four matrix.
m := matrix [[21 ,37 ,53 ,14] , [8 , -24 ,22 , -16] , [2 ,10 ,15 ,14] , [26 ,33 ,55 , -13]]
21 37 53 14
8 −24 22 −16
2
(10)
10 15 14
26 33 55 −13
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.
(r , c ) := (1 , 1)
1 (11)
PositiveInteger
Also, let lastrow and lastcol be the final row and column index.
( lastrow , lastcol ) := ( nrows ( m ) , ncols ( m ) )
4 (12)
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 for clause with repeat. See Section 5.4.8 on page 138 for
more information.
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]
FriCAS provides an iterate expression that skips over the remainder of a loop body and starts the
next loop iteration. We first initialize a counter.
i := 0
136 CHAPTER 5. INTRODUCTION TO THE FRICAS INTERACTIVE LANGUAGE
0 (1)
NonNegativeInteger
The repeat in a loop can be modified by adding one or more while clauses. Each clause contains a
predicate immediately following the while keyword. The predicate is tested before the evaluation of
the body of the loop. The loop body is evaluated whenever the predicates in a while clause are all
true.
The predicate is evaluated before loopBody is evaluated. A while loop terminates immediately
when predicate evaluates to false or when a break or return expression is evaluated in loopBody.
The value returned by the loop is the unique value of Void.
Here is a simple example of using while in a loop. We first initialize the counter.
i := 1
1 (1)
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 true, and (3) do not evaluate the loop body and therefore do not display
"hello".
while i < 1 repeat
output " hello "
i := i + 1
If you have multiple predicates to be tested use the logical and operation to separate them. FriCAS
evaluates these predicates from left to right.
(x , y ) := (1 , 1)
1 (3)
5.4. LOOPS 137
PositiveInteger
A break expression can be included in a loop body to terminate a loop even if the predicate in any
while clauses are not false.
(x , y ) := (1 , 1)
1 (5)
PositiveInteger
This loop has multiple while clauses and the loop terminates before any one of their conditions
evaluates to false.
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]
Here’s a different version of the nested loops that looked for the first negative element in a matrix.
m := matrix [[21 ,37 ,53 ,14] , [8 , -24 ,22 , -16] , [2 ,10 ,15 ,14] , [26 ,33 ,55 , -13]]
21 37 53 14
8 −24 22 −16
2
(7)
10 15 14
26 33 55 −13
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.
r := 1
1 (8)
PositiveInteger
4 (9)
PositiveInteger
FriCAS provides the for and in keywords in repeat loops, allowing you to iterate across all 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 repeat loops as for clauses. These clauses can be present in
addition to while clauses. As with all other types of repeat loops, break can be used to prematurely
terminate the evaluation of the loop.
If for is followed by a variable name, the in keyword and then an integer segment of the form n..m,
the end test for this loop is the predicate i > m. The body of the loop is evaluated m-n+1 times if this
number is greater than 0. If this number is less than or equal to 0, the loop body is not evaluated at
all.
The variable i has the value n, n+1, ..., m for successive iterations of the loop body. The loop
variable is a 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 103 , 113 , and 123 :
for i in 10..12 repeat output ( i ^3)
1000
1331
1728
[1, 2, 3] (2)
List ( PositiveInteger )
Iterate across this list, using “.” to access the elements of a list and the # operation to count its
elements.
for i in 1..# a repeat output ( a . i )
1
2
3
This type of iteration is applicable to anything that uses “.”. You can also use it with functions that
use indices to extract elements. Define m to be a matrix.
m := matrix [[1 ,2] ,[4 ,3] ,[9 ,0]]
1 2
4 3 (4)
9 0
Matrix(NonNegativeInteger)
You can use iterate with for-loops. Display the even integers in a segment.
for i in 1..5 repeat
if odd ?( i ) then iterate
output ( i )
2
4
By default, the difference between values taken on by a variable in loops such as for i in n..m
repeat ... is 1. It is possible to supply another, possibly negative, step value by using the by
keyword along with for and in. Like the upper and lower bounds, the step value following the by
keyword must be an integer. Note that the loop 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.
for i in 1..5 by 2 repeat output ( i )
1
3
5
If the value after the “..” 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 break or return expression is evaluated in the loop body. However you may also add some other
modifying clause on the repeat (for example, a 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.
for i in 15.. while not prime ?( i ) repeat output ( i )
15
16
This form is used when you want to iterate directly over the elements of a list. In this form of the for
loop, the variable x takes on the value of each successive element in l. The end test is most simply
stated in English: “are there no more x in l?”
If l is this list,
l := [0 , -5 ,3]
List ( Integer )
Since the list constructing expression expand [n..m] creates the list [n, n+1, ..., m]2 , you might
be tempted to think that the loops
and
2 This list is empty if n > m.
5.4. LOOPS 141
are equivalent. The second form first creates the list expand [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.
for f in factors ( factor (2400000) ) repeat output ( f )
[ factor = 2 , exponent = 8]
[ factor = 3 , exponent = 1]
[ factor = 5 , exponent = 5]
A for loop can be followed by a “|” and then a predicate. The predicate qualifies the use of the values
from the iterator following the for. Think of the vertical bar “|” as the phrase “such that.” This
loop expression prints out the integers n in the given segment such that n is odd.
for n in 0..4 | odd ? n repeat output n
1
3
The predicate need not refer only to the variable in the for clause: any variable in an outer scope can
be part of the predicate. In this example, the predicate on the inner for loop uses i from the outer
loop and the j from the for clause that it directly modifies.
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]
The last example of the previous section gives an example of nested iteration: a loop is contained
in another loop. Sometimes you want to iterate across two lists in parallel, or perhaps you want to
traverse a list while incrementing a variable.
142 CHAPTER 5. INTRODUCTION TO THE FRICAS INTERACTIVE LANGUAGE
Here we write a loop to iterate across two lists, computing the sum of the pairwise product of elements.
Here is the first list.
l := [1 ,3 ,5 ,7]
[1, 3, 5, 7] (1)
List ( PositiveInteger )
List ( PositiveInteger )
0 (3)
NonNegativeInteger
The last two elements of l are not used in the calculation because m has two fewer elements than l.
for x in l for y in m repeat
sum := sum + x * y
700 (5)
NonNegativeInteger
Next, we write a loop to compute the sum of the products of the loop elements with their positions in
the loop.
l := [2 ,3 ,5 ,7 ,11 ,13 ,17 ,19 ,23 ,29 ,31 ,37]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] (6)
5.4. LOOPS 143
List ( PositiveInteger )
0 (7)
NonNegativeInteger
Here looping stops when the list l is exhausted, even though the for i in 0.. specifies no terminating
condition.
for i in 0.. for x in l repeat sum := i * x
407 (9)
NonNegativeInteger
When “|” is used to qualify any of the for clauses in a parallel iteration, the variables in the predicates
can be from an outer scope or from a for clause in or to the left of a modified clause.
This is correct:
This is not correct since the variable j has not been defined outside the inner loop.
This example shows that it is possible to mix several of the forms of repeat modifying clauses on a
loop.
for i in 1..10
for j in 151..160 | odd ? j
while i + j < 160 repeat
output [i , j ]
[1 , 151]
[3 , 153]
1. while predicates can only refer to variables that are global (or in an outer scope) or that are
defined in for clauses to the left of the predicate.
2. A “such that” predicate (something following “|”) must directly follow a for clause and can only
refer to variables that are global (or in an outer scope) or defined in the modified for clause or
any for clause to the left.
144 CHAPTER 5. INTRODUCTION TO THE FRICAS INTERACTIVE LANGUAGE
List ( PositiveInteger )
[1, 2, 3, 4, 5, 6, 7, . . .] (2)
Stream( PositiveInteger )
[2, 3, 5, 7] (3)
List ( PositiveInteger )
Stream( PositiveInteger )
This is a list of the integers between 1 and 10, inclusive, whose squares are less than 700.
[ i for i in 1..10 while i * i < 700]
List ( PositiveInteger )
This is a stream of the integers greater than or equal to 1 whose squares are less than 700.
[ i for i in 1.. while i * i < 700]
[1, 2, 3, 4, 5, 6, 7, . . .] (6)
Stream( PositiveInteger )
Be careful when you use while to create a stream. By default, FriCAS tries to compute and display
the first ten elements of a stream. If the while condition is not satisfied quickly, FriCAS can spend a
long (possibly infinite) time trying to compute the elements. Use )set streams calculate to change
the default to something else. 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 lists which can then be given as an argument to matrix.
matrix [[ x ^ i + j for i in 1..3] for j in 10..12]
x2 + 10 x3 + 10
x + 10
x + 11 x2 + 11 x3 + 11 (7)
x + 12 x2 + 12 x3 + 12
Matrix(Polynomial( Integer ))
You can also create lists of streams, streams of lists and streams of streams. Here is a stream of
streams.
[[ i / j for i in j +1..] for j in 1..]
3 5 7 9 4 5 7 8
[2, 3, 4, 5, 6, 7, 8, . . .] , , 2, , 3, , 4, , . . . , , , 2, , , 3,
2 2 2 2 3 3 3 3
10
5 3 7 9 5 11
6 7 8 9 11 12
(8)
, ... , , , , 2, , , , ... , , , , , 2, , , ... ,
3 4 2 4 4 2 4 5 5 5 5 5 5
7 4 3 5 11 13 8 9 10 11 12 13
, , , , , 2, , ... , , , , , , , 2, . . . , . . .
6 3 2 3 6 6 7 7 7 7 7 7
Stream(Stream(Fraction(Integer)))
You can use parallel iteration across lists and streams to create new lists.
[ i / j for i in 3.. by 10 for j in 2..]
3 13 23 33 43 53 63
, , , , , , , ... (9)
2 3 4 5 6 7 8
Stream(Fraction( Integer ))
Stream(Integer)
As with loops, you can combine these modifiers to make very complicated conditions.
[[[ i , j ] for i in 10..15 | prime ? i ] for j in 17..22 | j = s quareFre ePart j ]
[[[11, 17] , [13, 17]] , [[11, 19] , [13, 19]] , [[11, 21] , [13, 21]] , [[11, 22] , [13, 22]]] (11)
See ‘List’ on page 490 and ‘Stream’ on page 578 for more information on creating and manipulating
lists and streams, respectively.
Stream(Integer)
A more elegant way, however, is to use the stream operation from Stream. Given an initial value a
and a function f, 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 stream to generate an
infinite stream of primes.
primes := stream ( nextPrime ,2)
Stream(Integer)
Once the stream is generated, you might only be interested in primes starting at a particular value.
smallPrimes := [ p for p in primes | p > 1000]
Stream(Integer)
Stream(Integer)
Stream(Integer)
To get these expanded into a finite stream, you call complete on the stream.
complete %
Stream(Integer)
Twin primes are consecutive odd number pairs which are prime. Here is the stream of twin primes.
twinPrimes := [[ p , p +2] for p in primes | prime ?( p + 2) ]
[[3, 5] , [5, 7] , [11, 13] , [17, 19] , [29, 31] , [41, 43] , [59, 61] , . . .] (7)
Stream(List( Integer ))
Since we already have the primes computed we can avoid the call to prime? by using a double iteration.
This time we’ll just generate a stream of the first of the twin primes.
firstOfTwins := [ p for p in primes for q in rest primes | q = p +2]
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 for iteration. A more
economical way is to use firstOfTwins. This time however, put a semicolon at the end of the line.
Put a semicolon at the end so that no elements are computed.
firstTriplets := [ p for p in firstOfTwins for q in rest firstOfTwins | q = p +2];
Stream(Integer)
What happened? As you know, by default FriCAS displays the first ten elements of a stream when
you first display it. And, therefore, it needs to compute them! If you want no elements computed, just
terminate the expression by a semicolon (“;”).3
3 Why does this happen? The semi-colon prevents the display of the result of evaluating the expression. Since no
stream elements are needed for display (or anything else, so far), none are computed.
148 CHAPTER 5. INTRODUCTION TO THE FRICAS INTERACTIVE LANGUAGE
3 (10)
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.
firstTriples.10
To compute the tenth triplet prime, FriCAS first must compute the second, the third, and so on. But
since there isn’t even a second triplet prime, FriCAS will compute forever. Nonetheless, this effort can
produce a useful result. After waiting a bit, hit Ctrl – c . The system responds as follows.
Let’s say that you want to know how many primes have been computed. Issue
numberOfComputedEntries primes
and, for this discussion, let’s say that the result is 2045. How big is the 2045th prime?
primes .2045
17837 (11)
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.
Chapter 6
In this chapter we show you how to write functions and macros, and we explain how FriCAS looks for
and applies them. We show some simple one-line examples of functions, together with larger ones that
are defined piece-by-piece or through the use of piles.
8 (1)
PositiveInteger
This is an unnamed function that does the same thing, using the “maps-to” syntax “+->” that we
discuss in Section 6.17 on page 179.
( x + - > if x < 0 then -x else x ) ( -8)
8 (2)
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 ‘Exit’ on page 399 and ‘Void’ on page 606). They may also read data from your keyboard, move
information from one place to another, or format and display results on your screen.
In FriCAS, as in mathematics, functions are usually parameterized. Each time you call (some people
say apply or invoke) a function, you give values to the parameters (variables). Such a value is called
149
150 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
an argument of the function. FriCAS 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. FriCAS 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 FriCAS
expression parser.
6.2 Macros
A macro provides general textual substitution of an FriCAS 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.
For example, suppose you decided that you like to use df for D. You define the macro df like this.
macro df == D
2x + 1 (2)
Polynomial( Integer )
Macros can be parameterized and so can be used for many different kinds of objects.
macro ff ( x ) == x ^2 + 1
z2 + 1 (4)
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.
6.2. MACROS 151
13 w2 − 24 w + 36
(6)
9 w2
Fraction (Polynomial( Integer ))
0 (9)
Integer
future : Integer := 1
1 (10)
Integer
1 (11)
Integer
2 (12)
Integer
Stream(Integer)
Stream(Integer)
An easier way to compute these numbers is to use the library operation fibonacci.
[ fibonacci i for i in 1..]
Stream(Integer)
22 3 (1)
Factored( Integer )
7 (2)
PositiveInteger
The function + has two arguments. When you give it more than two arguments, FriCAS groups the
arguments to the left. This expression is equivalent to (1 + 2) + 7.
1 + 2 + 7
10 (3)
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 + takes only two arguments.
Prefix operations are generally applied before the infix operation. Thus factorial 3 + 1 means
factorial(3)+ 1 producing 7, and - 2 + 5 means (-2) + 5 producing 3. An example of a prefix
operator is prefix -. 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 (“&”) before
the name. Thus D(2*x,x) can be written as 2*x &D x returning 2.
Every function in FriCAS is identified by a name and type.1 The type of a function is always a mapping
of the form Source →Target where Source and Target are types. To enter a type from the keyboard,
enter the arrow by using a hyphen “-” followed by a greater-than sign “>”, e.g. Integer→Integer.
Let’s go back to +. There are many + functions in the FriCAS library: one for integers, one for floats,
another for rational numbers, and so on. These + functions have different types and thus are different
functions. You’ve seen examples of this overloading before—using the same name for different functions.
Overloading is the rule rather than the exception. You can add two integers, two polynomials, two
matrices or two power series. These are all done with the same function name but with different
functions.
where Source and Target can be any type. A common type for Source is (T1 , . . . , Tn ), to indicate
a function of n arguments.
If g takes an Integer, a Float and another Integer, and returns a String, the declaration is written
this way.
1 An exception is an “anonymous function” discussed in Section 6.17 on page 179.
154 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
The types need not be written fully; using abbreviations, the above declaration is:
g : ( INT , FLOAT , INT ) -> STRING
It is possible for a function to take no arguments. If h takes no arguments but returns a Polynomial
Integer, any of the following declarations is acceptable.
h : () -> POLY INT
Functions can also be declared when they are being defined. The syntax for combined declara-
tion/definition is:
functionName(parm1 : parmType1 , ..., parmN : parmTypeN ): functionReturnType
The following definition fragments show how this can be done for the functions g and h above.
A current restriction on function declarations is that they must involve fully specified types (that is,
cannot include modes involving explicit or implicit “?”). For more information on declaring things in
general, see Section 2.3 on page 74.
fac 10
Compiling function fac with type Integer -> Integer
3628800 (2)
PositiveInteger
s 50
Compiling function s with type P os it i ve In te g er -> Fraction ( Integer )
6.6. DECLARED VS. UNDECLARED FUNCTIONS 155
13943237577224054960759
(4)
3099044504245996706400
Fraction ( Integer )
mersenne i == 2i − 1 (6)
FunctionCalled(mersenne)
Stream(Integer)
Stream( PositiveInteger )
mersennePrime 5
Compiling function mersennePrime with type Po si t iv eI nt e ge r -> Integer
8191 (10)
PositiveInteger
10 (2)
PositiveInteger
−1 (3)
Integer
To make the function over a wide range of types, do not declare its type. Give the same definition
with no declaration.
g x == x + 1
10 (5)
PositiveInteger
A version of g with different argument types get compiled for each new kind of argument used.
g (2/3)
Compiling function g with type Fraction ( Integer ) -> Fraction ( Integer )
5
(6)
3
Fraction ( Integer )
Perhaps you should use " @ " to indicate the required return type , or " $ " to
specify which version of the function you need .
FriCAS will attempt to step through and interpret the code .
There are 13 exposed and 11 unexposed library operations named + having 2
argument ( s ) but none was determined to be applicable . Use HyperDoc Browse ,
or issue
) display op +
to learn more about the available operations . Perhaps package - calling the
operation or using coercions on the arguments will allow you to apply the
operation .
Cannot find a definition or applicable library operation named + with argument
type ( s )
String
P os it iv e In te ge r
Perhaps you should use " @ " to indicate the required return type , or " $ " to
specify which version of the function you need .
As you will see in Chapter 12, FriCAS has a formal idea of categories for what “makes sense.”
You must use the parentheses (“()”) to evaluate it. Like a delayed assignment, the right-hand-side of
a function evaluation is not evaluated until the left-hand-side is used.
sin24 ()
Compiling function sin24 with type () -> Float
− 0.90557836200662384514 (2)
Float
If you omit the parentheses, you just get the function definition.
sin24
FunctionCalled(sin24)
0.42417900733699697594 (5)
Float
The only syntactic difference between delayed assignments and nullary functions is that you use “()”
in the latter case.
sin 4.3
Compiling function sin with type Float -> Float
1.0 (2)
Float
If you want the library operation, we have to package-call it (see Section 2.9 on page 89 for more
information).
sin (4.3) $ Float
− 0.91616593674945498404 (3)
Float
sin (34.6) $ Float
− 0.042468034716950101543 (4)
Float
Even worse, say we accidentally used the same name as a library function in the function.
sin x == sin x
Compiled code for sin has been cleared .
1 old definition ( s ) deleted for function or rule sin
− 0.91616593674945498404 (7)
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 FriCAS 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.
8. No + for arguments of types Variable(x) and Fraction(Integer) are found in either domain.
9. FriCAS resolves (see Section 2.10 on page 92) the types and gets Polynomial (Fraction
(Integer)).
10. The x and the 2/3 are converted to objects of this type and + is applied, yielding the answer, an
object of type Polynomial (Fraction (Integer)).
If FriCAS decides that it cannot compile the code, it issues a message stating the problem and
then the following message:
We will attempt to step through and interpret the code.
This is not a time to panic. Rather, it just means that what you gave to FriCAS is somehow
ambiguous: either it is not specific enough to be analyzed completely, or it is beyond FriCAS’s
present interactive compilation abilities.
For vars equal to [’x, ’y, ’z], this function displays 1 three times.
varPolys [ ’x , ’y , ’ z ]
6.11. PIECE-WISE FUNCTION DEFINITIONS 161
The type of the argument to output changes in each iteration, so FriCAS cannot compile the function.
In this case, even the inner loop by itself would have a problem:
for var in [ ’x , ’y , ’ z ] repeat
output (1 :: U n i v a r i a t e P o l y n o m i a l ( var , Integer ) )
Cannot compile conversion for types involving local variables . In particular ,
could not compile the expression involving :: U n i v a r i a t e P o l y n o m i a l ( var ,
Integer )
FriCAS will attempt to step through and interpret the code .
1
1
1
Sometimes you can help a function to compile by using an extra conversion or by using pretend. See
Section 2.8 on page 86 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. The option is controlled via )set functions compile. Issue )set functions compile on to
compile all the way to machine code. With the default setting )set functions compile off, FriCAS
has its Common LISP code interpreted because the overhead of further compilation is larger than the
run-time of most of the functions our users have defined. You may find that selectively turning this
option on and off will 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 )set functions compile on.
There are many other ways to define a factorial function for nonnegative integers. You might say
factorial of 0 is 1, otherwise factorial of n is n times factorial of n-1. Here is one way to do this in
FriCAS. Here is the value for n = 0.
fact (0) == 1
Here is the value for n > 0. The vertical bar “|” means “such that”.
fact ( n | n > 0) == n * fact ( n - 1)
fact (3)
Compiling function fact with type Integer -> Integer
Compiling function fact as a recurrence relation .
6 (3)
PositiveInteger
5040 (7)
PositiveInteger
In general a piece-wise definition of a function consists of two or more parts. Each part gives a “piece”
of the entire definition. FriCAS collects the pieces of a function as you enter them. When you ask for
a value of the function, it then “glues” the pieces together to form a function.
The two piece-wise definitions for the factorial function are examples of recursive functions, that is,
functions that are defined in terms of themselves. Here is an interesting doubly-recursive function.
This function returns the value 11 for all positive integer arguments. Here is the first of two pieces.
eleven ( n | n < 1) == n + 11
6.11. PIECE-WISE FUNCTION DEFINITIONS 163
Stream(Integer)
11 (11)
PositiveInteger
Here are the details about how FriCAS creates a function from its pieces. FriCAS converts the ith
piece of a function definition into a conditional expression of the form: if predi then expressioni . If
any new piece has a predi that is identical2 to an earlier predj , the earlier piece is removed. Otherwise,
the new piece is always added at the end.
If there are n pieces to a function definition for f, the function defined f is:
if pred1 then expression1 else
. . .
if predn then expressionn else
error "You did not define f for argument <arg>."
You can give definitions of any number of mutually recursive function definitions, piece-wise or other-
wise. 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 eleven from the previous section.
eleven ( n | n < 1) == n + 11
A similar doubly-recursive function below produces -11 for all negative positive integers. If you haven’t
worked out why or how eleven works, the structure of this definition gives a clue. This definition
we write as a block.
minusEleven ( n ) ==
n >= 0 = > n - 11
minusEleven (5 + minusEleven ( n + 7) )
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.
s (0) == 1
[1, 1, 1, 1, 1, 1, 1, . . .] (6)
Stream(Fraction( Integer ))
FriCAS can create infinite streams in the positive direction (for example, for index values 0, 1, . . .) or
negative direction (for example, for index values 0, −1, −2, . . .). Here we would like a stream of values
of s(n) that is infinite in both directions. The function t(n) below returns the nth term of the infinite
stream [s(0), s(1), s(−1), s(2), s(−2), . . .]. Its definition has three pieces. Define the initial term.
t (1) == s (0)
The even numbered terms are the s(i) for positive i. We use quo rather than / since we want the
result to be an integer.
t ( n | even ?( n ) ) == s ( n quo 2)
Finally, the odd numbered terms are the s(i) for negative i. In piece-wise definitions, you can use
different variables to define different pieces. FriCAS will not get confused.
t ( p ) == s ( - p quo 2)
Look at the definition of t. In the first piece, the variable n was used; in the second piece, p. FriCAS
always uses your last variable to display your definitions back to you.
) display value t
CONCAT
Definition :
,
t 1 == s (0)
t ( p | even ?( p )) == s ( p quo 2)
t p == s ( - p quo 2)
6.11. PIECE-WISE FUNCTION DEFINITIONS 165
[1, 1, 1, 1, 1, 1, 1, . . .] (10)
Stream(Fraction( Integer ))
1 (11)
Fraction ( Integer )
6.11.3 Predicates
We have already seen some examples of predicates (Section 6.11.1 on page 161). Predicates are
Boolean-valued expressions and FriCAS uses them for filtering collections (see Section 5.5 on page
144) 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.
opposite ’ right == ’ left
Try it out.
for x in [ ’ right , ’ left ] repeat output opposite x
Compiling function opposite with type O r d e r e d V a r i a b l e L i s t ([ right , left ]) ->
Symbol
left
right
Explicit predicates tell FriCAS that the given function definition piece is to be applied if the predicate
evaluates to true for the arguments to the function. You can use such “constant” arguments for
integers, strings, and quoted symbols. The Boolean values true and false can also be used if
qualified with “@” or “$” and Boolean. The following are all valid function definition fragments using
constant arguments.
a(1) == ...
b("unramified") == ...
c(’untested) == ...
d(true@Boolean) == ...
166 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
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 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.
i n F i r s t H a l f Q u a d r a n t ( x | x > 0 , y | y < x ) == true
Try it out.
[ i n F i r s t H a l f Q u a d r a n t (i ,3) for i in 1..5]
Compiling function i n F i r s t H a l f Q u a d r a n t with type ( PositiveInteger ,
P os itiv e In te ge r ) -> Boolean
List (Boolean)
Remark: Very old versions of FriCAS allowed predicates to be given after a when keyword as
in inFirstHalfQuadrant(x ,y) == true when x >0 and y < x. This is no longer supported, is
WRONG, and will cause a syntax error or strange behavior.
20922789888000 (2)
PositiveInteger
This causes all other functions to have all computed values saved by default.
) set functions cache all
In general , interpreter functions will cache all values .
This causes all functions that have not been specifically cached in some way to have no computed
values saved.
) set functions cache 0
In general , functions will cache no returned values .
Be careful about caching functions that have side effects. Such a function might destructively
modify the elements of an array or issue a 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 Section 6.16 on
page 175 for an example.
fact(0) == 1
fact(n | n > 0) == n * fact(n-1)
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 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 second order recurrence relation. The library
function fibonacci computes Fibonacci numbers. It is obviously optimized for speed.
[ fibonacci ( i ) for i in 0..]
168 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
[0, 1, 1, 2, 3, 5, 8, . . .] (1)
Stream(Integer)
fib (2) == 1
139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125
(5)
PositiveInteger
Since this takes a short time to compute, it obviously didn’t do as many as 10104 operations! By default,
FriCAS transforms any recurrence relation it recognizes into an iteration. Iterations are efficient. To
compute the value of the nth term of a recurrence relation using an iteration requires only n function
calls.3
To turn off this special recurrence relation compilation, issue
library fibonacci uses a “powering algorithm” with a computing time proportional to log3 (n) to compute fibonacci(n).
4 For a more general k th order recurrence relation, FriCAS caches the last k values.
6.14. MAKING FUNCTIONS FROM OBJECTS 169
p (1) == x
− z3 + y2 − x (1)
Polynomial( Integer )
To make this into a function of no arguments that simply returns the polynomial, use the two argument
form of function.
function (p , ’ f0 )
f0 (2)
Symbol
To avoid possible conflicts (see below), it is a good idea to quote always this second argument.
f0
f 0 () == − z 3 + y 2 − x (3)
FunctionCalled(f0)
− z3 + y2 − x (4)
Polynomial( Integer )
To make a function in x, use a version of 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.
function (p , ’ f1 , ’ x )
f1 (5)
Symbol
f 1 x == − z 3 + y 2 − x (6)
FunctionCalled(f1)
This is the value of f1 at x = 3. Notice that the return type of the function is Polynomial (Integer),
the same as p.
f1 (3)
Compiling function f1 with type P o si ti ve I nt eg er -> Polynomial ( Integer )
− z3 + y2 − 3 (7)
Polynomial( Integer )
f2 (8)
Symbol
f2
f 2 (x, y) == − z 3 + y 2 − x (9)
FunctionCalled(f2)
− z3 − 3 (10)
Polynomial( Integer )
Finally, use all three variables as parameters. There is no five argument form of function, so use the
one with three arguments, the third argument being a list of the parameters.
function (p , ’ f3 ,[ ’ x , ’y , ’ z ])
f3 (11)
Symbol
Evaluate this using the same values for x and y as above, but let z be -6. The result type of f3 is
Integer.
f3
f 3 (x, y, z) == − z 3 + y 2 − x (12)
FunctionCalled(f3)
f3 (3 ,0 , -6)
Compiling function f3 with type ( PositiveInteger , NonNegativeInteger , Integer )
-> Integer
213 (13)
PositiveInteger
The four functions we have defined via p have been undeclared. To declare a function whose body is
to be generated by function, issue the declaration before the function is created.
g : ( Integer , Integer ) -> Float
D ( sin (x - y ) / cos ( x + y ) ,x )
Expression ( Integer )
function (% , ’g , ’x , ’ y )
g (16)
Symbol
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 function. In general, if x has a value and
you use x without a quote in a call to function, then FriCAS does not know what you are trying to do.
What kind of object is allowable as the first argument to function? Let’s use the Browse facility
of HyperDoc to find out. At the main Browse menu, enter the string function and then click on
Operations. The exposed operations called function all take an object whose type belongs to category
ConvertibleTo InputForm. What domains are those? Go back to the main Browse menu, erase
function, enter ConvertibleTo in the input area, and click on categories on the Constructors
line. At the bottom of the page, enter InputForm in the input area following S =. Click on Cross
Reference and then on Domains. The list you see contains over forty domains that belong to
the category ConvertibleTo InputForm. Thus you can use function for Integer, Float, String,
Complex, Expression, and so on.
The significance of swap is that it has a destructive effect on its first argument.
k := [1 ,2 ,3 ,4 ,5]
[1, 2, 3, 4, 5] (2)
List ( PositiveInteger )
swap (k ,2 ,4)
Compiling function swap with type ( List ( P os it i ve In te g er ) , PositiveInteger ,
P os itiv e In te ge r ) -> Po s it iv e In te ge r
2 (3)
PositiveInteger
You see that the second and fourth elements are interchanged.
k
[1, 4, 3, 2, 5] (4)
List ( PositiveInteger )
Using this, we write a couple of different sort functions. First, a simple bubble sort. The operation #
returns the number of elements in an aggregate.
6.15. FUNCTIONS DEFINED WITH BLOCKS 173
bubbleSort ( m ) ==
n := # m
for i in 1..( n -1) repeat
for j in n ..( i +1) by -1 repeat
if m . j < m .( j -1) then swap (m ,j ,j -1)
m
List ( Integer )
[−3, 4, 8, 9] (7)
List ( Integer )
[−3, 4, 8, 9] (8)
List ( Integer )
This function implements an insertion sort. The basic idea is to traverse the list and insert the ith
element in its correct position among the i-1 previous elements. Since we start at the beginning of
the list, the list elements before the ith element have already been placed in ascending order.
insertionSort ( m ) ==
for i in 2..# m repeat
j := i
while j > 1 and m . j < m .( j -1) repeat
swap (m ,j ,j -1)
j := j - 1
m
List ( Integer )
insertionSort ( m )
Compiling function swap with type ( List ( Integer ) , NonNegativeInteger , Integer )
-> Integer
Compiling function insertionSort with type List ( Integer ) -> List ( Integer )
174 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
[−3, 4, 8, 9] (11)
List ( Integer )
[−3, 4, 8, 9] (12)
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.
bubbleSort2 ( m : List Integer ) : List Integer ==
empty ?( m ) = > m
l := m
while not empty ?( 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 .
Try it out.
bubbleSort2 [3 ,7 ,2]
Compiling function bubbleSort2 with type List ( Integer ) -> List ( Integer )
[7, 3, 2] (14)
List ( Integer )
This definition is both recursive and iterative, and is tricky! Unless you are 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 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 while loop calls 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 rest of the original list must be updated to hold the result of the recursive call.
6.16. FREE AND LOCAL VARIABLES 175
0 (1)
NonNegativeInteger
1 (3)
PositiveInteger
counter
1 (4)
NonNegativeInteger
Usually FriCAS can tell that you mean to refer to a global variable and so free isn’t always necessary.
However, for clarity and the sake of self-documentation, we encourage you to use it.
Declare a variable to be “local” when you do not want to refer to a global variable by the same name.
7 (6)
PositiveInteger
1 (7)
NonNegativeInteger
Parameters to a function are local variables in the function. Even if you issue a 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 local or free?
Well, FriCAS decides on this basis:
1. FriCAS scans your function line-by-line, from top-to-bottom. The right-hand side of an assign-
ment is looked at before the left-hand side.
2. If x is referenced before it is assigned a value, it is a free (global) variable.
1 (8)
PositiveInteger
3 (10)
PositiveInteger
[3, 1] (11)
List ( PositiveInteger )
What happened? In the first line of the function body for h, a is referenced on the right-hand side
of the assignment. Thus a is a free variable. The variable b is not referenced in that line, but it is
assigned a value. Thus b is a local variable and is given the value a + 1 = 2. In the second line, the
free variable a is assigned the value b + a which equals 2 + 1 = 3. This is the value returned by the
function. Since a was free in h, the global variable a has value 3. Since b was local in h, the global
variable b is unchanged—it still has the value 1.
6.16. FREE AND LOCAL VARIABLES 177
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 Section 6.12 on page
166). Caching 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 p.
) set fun cache all p
function p will cache all values .
1 (13)
PositiveInteger
x (14)
Polynomial( Integer )
2 (15)
PositiveInteger
x (16)
Polynomial( Integer )
If caching had been turned off, the second evaluation would have reflected the changed value of N.
Turn off caching for p.
) set fun cache 0 p
Caching for function p is turned off
178 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
FriCAS does not allow fluid variables, that is, variables bound by a function f that can be referenced
by functions called by f.
Values are passed to functions by 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.
r : Record ( i : Integer ) := [1]
[i = 1] (17)
Record(i : Integer )
This function first modifies the one component of its record argument and then rebinds the parameter
to another record.
resetRecord rr ==
rr . i := 2
rr := [10]
[i = 10] (19)
Record(i : Integer )
The value of r was changed by the expression rr.i := 2 but not by rr := [10].
r
[i = 2] (20)
Record(i : Integer )
To conclude this section, we give an iterative definition of a function that computes Fibonacci num-
bers. This definition approximates the definition into which FriCAS transforms the recurrence relation
definition of fib in Section 6.13 on page 167.
Global variables past and present are used to hold the last computed Fibonacci numbers.
past := present := 1
1 (21)
PositiveInteger
2 (22)
6.17. ANONYMOUS FUNCTIONS 179
PositiveInteger
Stream( PositiveInteger )
434665576869374564356885276750406258025646605173717804024817290895365554179490518904038798400792551692959225930803
(25)
PositiveInteger
As an exercise, we suggest you write a function in an iterative style that computes the value of the
recurrence relation p(n) = p(n − 1) − 2 p(n − 2) + 4 p(n − 3) having the initial values p(1) = 1, p(2) = 3,
and p(3) = 9, How would you write the function using an element OneDimensionalArray or Vector
to hold the previously computed values?
An anonymous function is a function that is defined by giving a list of parameters, the “maps-to”
compound symbol “+->”(from the mathematical symbol 7→), and by an expression involving the
parameters, the evaluation of which determines the return value of the function.
1. Place the anonymous function definition in parentheses directly followed by a list of arguments.
2. Assign the anonymous function to a variable and then use the variable name when you would
normally use a function name.
180 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
3. Use “==” to use the anonymous function definition as the arguments and body of a regular
function definition.
4. Have a named function contain a declared anonymous function and use the result returned by
the named function.
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.
x + - > if x < 0 then -x else x
AnonymousFunction
abs1 := %
AnonymousFunction
This function returns true if the absolute value of the first argument is greater than the absolute value
of the second, false otherwise.
(x , y ) + - > abs1 ( x ) > abs1 ( y )
AnonymousFunction
List ( Integer )
AnonymousFunction
We create a four-by-four matrix containing 1 or -1 depending on whether the row plus the column
index is even or not.
matrix ([[ ev ( row , col ) for row in 1..4] for col in 1..4])
1 −1 1 −1
−1 1 −1 1
(6)
1 −1 1 −1
−1 1 −1 1
Matrix( Integer )
This function returns true if a polynomial in x has multiple roots, false otherwise. It is defined and
applied in the same expression.
( p + - > not one ?( gcd (p , D (p , x ) ) ) ) ( x ^2+4* x +4)
true (7)
Boolean
If you declare any of the arguments you must declare all of them. Thus,
is not legal.
This is an example of a fully declared anonymous function. The output shown just indicates that the
object you created is a particular kind of map, that is, function.
( x : INT , y : INT ) : FRAC INT + - > ( x + 2* y ) /( y - 1)
theMap(anonymousFunction) (1)
FriCAS allows you to declare the arguments and not declare the return type.
( x : INT , y : INT ) + - > ( x + 2* y ) /( y - 1)
182 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
theMap(anonymousFunction) (2)
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,
is not legal.
This and the next expression are equivalent.
h ( x : INT , y : INT ) : FRAC INT == ( x + 2* y ) /( y - 1)
Function declaration h : ( Integer , Integer ) -> Fraction ( Integer ) has been added
to workspace .
1. If you use an anonymous function and FriCAS can’t figure out what you are trying to do, declare
the function.
2. If the function has nontrivial argument types or a nontrivial return type that FriCAS may be
able to determine eventually, but you are not willing to wait that long, declare the function.
3. 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.
4. If you are using the anonymous function as an argument to another function (such as map or
sort), consider declaring the function.
5. If you define an anonymous function inside a named function, you must declare the anonymous
function.
theMap(?) (6)
( Integer → Integer )
Try it out.
6.18. EXAMPLE: A DATABASE 183
g 3
13 (7)
PositiveInteger
g ( -4)
6 (8)
PositiveInteger
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.
To find the parentOf someone, you have to scan the database of people applying children.
parentOf ( x ) ==
for y in people repeat
( if childOf (x , y ) then return y )
" unknown "
Suppose you want to make a list of all great-grandparents. Well, a great-grandparent is a grandparent
of a person who has children.
g r e a t G r a n d P a r e n t s == [ x for x in people |
reduce ( _or ,[ not empty ? children ( y ) for y in grandchildren ( x ) ] , false ) ]
Finally, we need a list of people. Since all people are descendants of “albert”, let’s say so.
people == descendants " albert "
We have used “==” to define the database and some functions to query the database. But no compu-
tation is done until we ask for some information. Then, once and for all, the functions are analyzed
and compiled to machine code for run-time efficiency. Notice that no types are given anywhere in this
example. They are not needed.
Who are the grandchildren of “richard”?
grandchildren " richard "
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 )
List ( String )
["albert"] (13)
List ( String )
Define the values along the first row and any column i.
pascal (1 , i ) == 1
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.
pascal (n , n ) == 1
Now that we have defined the coefficients in Pascal’s triangle, let’s write a couple of one-liners to
display it. First, define a function that gives the nth row.
pascalRow ( n ) == [ pascal (i , n ) for i in 1.. n ]
Next, we write the function displayRow to display the row, separating entries by blanks and center-
ing.
displayRow ( n ) == output center blankSeparate pascalRow ( n )
Here we have used three output operations. Operation output displays the printable form of objects
on the screen, center centers a printable form in the width of the screen, and blankSeparate takes a list
of printable forms and inserts a blank between successive elements. Look at the result.
for i in 1..7 repeat displayRow i
Compiling function pascal with type ( Integer , Integer ) -> Po s it iv eI n te ge r
Compiling function pascalRow with type Po s it iv eI n te ge r -> List ( Po si t iv eI nt e ge r )
Compiling function displayRow with type P os it i ve In te g er -> 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
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 pascalRow to right adjust the entries within the triangle within a width of four characters.
pascalRow ( n ) == [ right ( pascal (i , n ) ,4) for i in 1.. n ]
Compiled code for pascalRow has been cleared .
Compiled code for displayRow has been cleared .
1 old definition ( s ) deleted for function or rule pascalRow
1 6 15 20 15 6 1
Here is palAux?. It works by comparing elements that are equidistant from the start and end of the
object.
palAux ?( s ,i , j ) ==
j > i =>
( s . i = s . j ) and palAux ?( s , i +1 ,j -1)
true
false (3)
Boolean
A list of polynomials.
pal ? [4 ,a ,x -1 ,0 , x -1 ,a ,4]
Compiling function palAux ? with type ( List ( Polynomial ( Integer )) , Integer ,
Integer ) -> Boolean
Compiling function pal ? with type List ( Polynomial ( Integer )) -> Boolean
true (4)
Boolean
true (5)
Boolean
true (6)
Boolean
Stream( PositiveInteger )
Stream( PositiveInteger )
[true, true, true, true, true, true, true, true, false, . . .] (9)
Stream(Boolean)
The presence of “∀” indicates that x and y can stand for arbitrary mathematical expressions in the
above formula. You can use such mathematical formulas in FriCAS to specify “rewrite rules”. Rewrite
rules are objects in FriCAS 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. For example, a rewrite rule for the above formula is:
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 matches A by B.” The left-hand side of a rewrite rule is
called a pattern; its right-side side is called its substitution.
Create a rewrite rule named logrule. The generated symbol beginning with a “%” is a place-holder
for any other terms that might occur in the sum.
logrule := rule log ( x ) + log ( y ) == log ( x * y )
Expression ( Integer )
Apply logrule to f.
logrule f
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, log and +) and variables (here,
x and y). By default, every operation name stands for itself. Thus log matches only “log” and not
any other operation such as sin. On the other hand, variables do not stand for themselves. Rather, a
variable denotes a pattern variable that is free to match any expression whatsoever.
When a rewrite rule is applied, a process called pattern matching goes to work by systematically
scanning the subexpressions of the argument. When a subexpression is found that “matches” the
pattern, the subexpression is replaced by the right-hand side of the rule. The details of what happens
will be covered later.
The customary FriCAS notation for patterns is actually a shorthand for a longer, more general notation.
Pattern variables can be made explicit by using a percent (“%”) 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 (“’”).
Although the current FriCAS parser does not let you quote an operation name, this more general
notation gives you an alternate way of giving the same rewrite rule:
This longer notation gives you patterns that the standard notation won’t handle. For example, the
rule
means “for all f and c, replace f(y) by c * f(x) when y is the product of c and the explicit variable
x.”
Thus the pattern can have several adornments on the names that appear there. Normally, all these
adornments are dropped in the substitution on the right-hand side.
To summarize:
The leftHandSide is a pattern to be matched and the rightHandSide is its substitution. The rule
is an object of type 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(xy ) ∀ x 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 ruleset. Like rules, rulesets are objects in FriCAS 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.
logrules := rule
log ( x ) + log ( y ) == log ( x * y )
y * log x == log ( x ^ y )
Expression ( Integer )
sin(x)a
log (6)
x2
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(xy )
190 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
only when y is an integer. The way to restrict a pattern variable y by a predicate f(y) is by using
a vertical bar “|”, which means “such that,” in much the same way it is used in function definitions.
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.
logrules2 := rule
log ( x ) + log ( y ) == log ( x * y )
( y | integer ? y ) * log x == log ( x ^ y )
Compare this with the result of applying the previous set of rules.
f
Expression ( Integer )
logrules2 f
1
a log(sin(x)) + log (9)
x2
Expression ( Integer )
You should be aware that you might need to apply a function like integer within your predicate
expression to actually apply the test function. Here we use integer because n has type Expression
Integer but even? is an operation defined on integers.
evenRule := rule cos ( x ) ^( n | integer ? n and even ? integer n ) ==(1 - sin ( x ) ^2) ^( n /2)
n2
cos(x)n == −sin(x)2 + 1 (10)
− sin(x)2 + 1 (11)
Expression ( Integer )
This is an example of some of the usual identities involving products of sines and cosines.
sinC osProduc ts == rule
sin ( x ) * sin ( y ) == ( cos (x - y ) - cos ( x + y ) ) /2
cos ( x ) * cos ( y ) == ( cos (x - y ) + cos ( x + y ) ) /2
sin ( x ) * cos ( y ) == ( sin (x - y ) + sin ( x + y ) ) /2
Expression ( Integer )
sinC osProduc ts g
Compiling body of rule sinCos Products to compute value of type Ruleset ( Integer ,
Integer , Expression ( Integer ))
sin(4 a) + 2 cos(b − a)
(14)
2
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.
exprule := rule exp ( a + b ) == exp ( a ) * exp ( b )
eb+a == ea eb (15)
This rule would cause infinite rewriting on this if either a or b were allowed to match 0.
exprule exp x
ex (16)
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 “?” whenever it appears in a left-hand side of a rule. For example, consider the
following rule for the exponential integral:
y + ex
Z Z
y
dx = dx + Ei(x) ∀ x and y.
x x
This rule is valid for y = 0. One solution is to create a Ruleset with two rules, one with and one
without y. A better solution is to use an “optional” pattern variable. Define rule eirule with a
pattern variable ?y to indicate that an expression may or may not occur.
eirule := rule integral ((? y + exp x ) /x , x ) == integral ( y /x , x ) + Ei x
x x
e%D + y
Z Z
y
d%D == d%D + Ei(x) (17)
%D %D
RewriteRule( Integer , Integer , Expression ( Integer ))
Ei(u) (18)
Expression ( Integer )
Z u
sin(%D)
d%D + Ei(u) (19)
%D
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 + . . . + 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 “:” before the pattern variable that you want
to match multiple terms. The remaining rules involve operators u and v.
u := operator ’u
u (20)
BasicOperator
These definitions tell FriCAS that u and v are formal operators to be used in expressions.
v := operator ’v
v (21)
BasicOperator
Expression ( Integer )
Define myOtherRule to match several terms so that the rule gets applied recursively.
myOtherRule := rule u (: x + y ) == u x + v y
6.21. RULES AND PATTERN MATCHING 193
Expression ( Integer )
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.
First, pattern matching slows down as the number of rules you have to apply increases. Thus it is good
practice to organize the sets of rules you use optimally so that irrelevant rules are never included.
Second, careless use of pattern matching can lead to wrong answers. You should avoid using pattern
matching to handle hidden algebraic relationships that can go undetected by other programs. As a
simple example, a symbol such as “J” can easily be used to represent the square root of -1 or some
other important algebraic quantity. Many algorithms branch on whether an expression is zero or not,
then divide by that expression if it is not. If you fail to simplify an expression involving powers of J to
-1, algorithms may incorrectly assume an expression is non-zero, take a wrong branch, and produce a
meaningless result.
Pattern matching should also not be used as a substitute for a domain. In FriCAS, objects of one
domain are transformed to objects of other domains using well-defined coerce operations. Pattern
matching should be used on objects that are all the same type. Thus if your application can be
handled by type Expression in FriCAS and you think you need pattern matching, consider this
choice carefully. You may well be better served by extending an existing domain or by building a new
domain of objects for your application.
194 CHAPTER 6. USER-DEFINED FUNCTIONS, MACROS AND RULES
Chapter 7
Graphics
This chapter shows how to use the FriCAS graphics facilities under the X Window System. FriCAS
has two-dimensional and three-dimensional drawing and rendering packages that allow the drawing,
coloring, transforming, mapping, clipping, and combining of graphic output from FriCAS 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 control-panel that uses interactive mouse
commands. PostScript and other output forms are available so that FriCAS images can be printed or
used by other programs.1
1 PostScript is a trademark of Adobe Systems Incorporated, registered in the United States.
195
196 CHAPTER 7. GRAPHICS
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.
The first kind of two-dimensional graph is that of a curve defined by a function y = f(x) over a finite
interval of the x axis.
The general format for drawing a function defined by a formula f(x) is:
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 “=”, and the range of
values.
Display this formula over the range 0 ≤ x ≤ 6. FriCAS converts your formula to a compiled function
so that the results can be computed quickly and efficiently.
draw ( sin ( tan ( x ) ) - tan ( sin ( x ) ) ,x = 0..6)
(-1)*tan(sin(x))+sin(tan(x))
7.1. TWO-DIMENSIONAL GRAPHICS 197
Notice that FriCAS compiled the function before the graph was put on the screen.
Here is the same graph on a different interval. This time we give the graph a title.
draw ( sin ( tan ( x ) ) - tan ( sin ( x ) ) , x = 10..16 , title ==" Shifted view ")
Shifted view
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.
f ( x ) == (x -1) *( x -2) *( x -3)
To draw the function, the first argument is its name and the second is just the range with no independent
variable.
draw (f , 0..4)
FriCAS2D
The second kind of two-dimensional graph is that of curves produced by parametric equations. 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 curve takes the two functions f and g as its parameters.
198 CHAPTER 7. GRAPHICS
The general format for drawing a two-dimensional plane curve defined by parametric formulas
x = f(t) and y = g(t) is:
draw(curve(f(t), g(t)), t = a..b, options)
where a..b defines the range of the independent variable t, and where options prescribes zero or
more options as described in Section 7.2.4 on page 225. An example of an option is curveColor
== bright red().
Here’s an example:
Define a parametric curve using a range involving %pi, FriCAS’s way of saying π. For parametric
curves, FriCAS compiles two functions, one for each of the functions f and g.
draw ( curve ( sin ( t ) * sin (2* t ) * sin (3* t ) , sin (4* t ) * sin (5* t ) * sin (6* t ) ) , t = 0..2*% pi )
sin(t)*sin(2*t)*sin(3*t)
The title may be an arbitrary string and is an optional argument to the draw command.
draw ( curve ( cos ( t ) , sin ( t ) ) , t = 0..2*% pi , title ==" Circle ")
Circle
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.
7.1. TWO-DIMENSIONAL GRAPHICS 199
Give to curve the names of the functions, then write the range without the name of the independent
variable.
draw ( curve (f , g ) ,0..% pi )
FriCAS2D
Here is another look at the same curve but over a different range. Notice that f and g are not
recompiled. Also note that FriCAS provides a default title based on the first function specified in
curve.
draw ( curve (f , g ) , -4*% pi ..4*% pi )
FriCAS2D
A third kind of two-dimensional graph is a non-singular “solution curve” in a rectangular region of the
plane. A solution curve is a curve defined by a polynomial equation p(x,y) = 0. Non-singular means
200 CHAPTER 7. GRAPHICS
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
∂p ∂p
derivatives ∂x (x, y) and ∂y (x, y) are not both zero.
The general format for drawing a non-singular solution curve given by a polynomial of the form
p(x,y) = 0 is:
We require that the polynomial has rational or integral coefficients. Here is an algebraic curve example
(“Cartesian ovals”):
p := (( x ^2 + y ^2 + 1) - 8* x ) ^2 - (8*( x ^2 + y ^2 + 1) -4*x -1)
y 4 + 2 x2 − 16 x − 6 y 2 + x4 − 16 x3 + 58 x2 − 12 x − 6
(1)
Polynomial( Integer )
The first argument is always expressed as an equation of the form p = 0 where p is a polynomial.
draw ( p = 0 , x , y , range == [ -1..11 , -7..7])
FriCAS2D
The draw commands take an optional list of options, such as title shown above. Each option is given
by the syntax: name == value. Here is a list of the available options in the order that they are described
below.
adaptive clip unit
clip curveColor range
toScale pointColor coordinates
7.1. TWO-DIMENSIONAL GRAPHICS 201
The adaptive option turns adaptive plotting on or off. 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. The adaptive option
is normally on. Here we turn it off.
draw ( sin (1/ x ) ,x = -2*% pi ..2*% pi , adaptive == false )
sin(1/x)
The clip option turns clipping on or off. If on, large values are cut off according to clipPointsDefault.
draw ( tan ( x ) ,x = -2*% pi ..2*% pi , clip == true )
tan(x)
Option toScale does plotting to scale if true or uses the entire viewport if false. The default can be
determined using drawToScale.
draw ( sin ( x ) ,x = -% pi ..% pi , toScale == true , unit == [1.0 ,1.0])
202 CHAPTER 7. GRAPHICS
sin(x)
3
-1
-2
-3 -3 -2 -1 0 1 2 3
Option clip with a range sets point clipping of a graph within the ranges specified in the list [x
range,y range]. If only one range is specified, clipping applies to the y-axis.
draw ( sec ( x ) ,x = -2*% pi ..2*% pi , clip == [ -2*% pi ..2*% pi , -% pi ..% pi ] , unit == [1.0 ,1.0])
sec(x)
-1
-2
-6 -4 -2 0 2 4 6
Option curveColor sets the color of the graph curves or lines to be the indicated palette color (see
Section 7.1.5 on page 205 and Section 7.1.6 on page 206).
draw ( sin ( x ) ,x = -% pi ..% pi , curveColor == bright red () )
sin(x)
7.1. TWO-DIMENSIONAL GRAPHICS 203
Option pointColor sets the color of the graph points to the indicated palette color (see Section 7.1.5
on page 205 and Section 7.1.6 on page 206).
draw ( sin ( x ) ,x = -% pi ..% pi , pointColor == pastel yellow () )
sin(x)
Option unit sets the intervals at which the axis units are plotted according to the indicated steps [x
interval, y interval].
draw ( curve (9* sin (3* t /4) ,8* sin ( t ) ) , t = -4*% pi ..4*% pi , unit == [2.0 ,1.0])
9*sin((3*t)/4)
8
7
6
5
4
3
2
1
0
-1
-2
-3
-4
-5
-6
-7
-10 -8 -6 -4 -2 0 2 4 6 8 10
-8
Option range sets the range of variables in a graph to be within the ranges for solving plane algebraic
curve plots.
draw ( y ^2 + y - ( x ^3 - x ) = 0 , x , y , range == [ -2..2 , -2..1] , unit ==[1.0 ,1.0])
204 CHAPTER 7. GRAPHICS
FriCAS2D
1
-1
-2 -1 0 1 2
-2
FriCAS2D
1.5
0.5
-0.5
-1
Option coordinates indicates the coordinate system in which the graph is plotted. The default is to
use the Cartesian coordinate system. For more details, see Section 7.2.7 on page 235.
draw ( curve ( sin (5* t ) ,t ) ,t =0..2*% pi , coordinates == polar )
sin(5*t)
7.1. TWO-DIMENSIONAL GRAPHICS 205
7.1.5 Color
The domain Color provides operations for manipulating colors in two-dimensional graphs. Colors are
objects of Color. Each color has a hue and a weight. Hues are represented by integers that range from
1 to the numberOfHues(), normally 27. Weights are floats and have the value 1.0 by default.
color (integer)
creates a color of hue integer and weight 1.0.
hue (color)
returns the hue of color as an integer.
red (), blue() green(), and yellow()
create colors of that hue with weight 1.0.
color1 + color2 returns the color that results from additively combining the indicated color1 and color2 .
Color addition is not commutative: changing the order of the arguments produces different
results.
integer * color changes the weight of color by integer without affecting its hue. For example, red() +
3*yellow() produces a color closer to yellow than to red. Color multiplication is not associative:
changing the order of grouping produces different results.
These functions can be used to change the point and curve colors for two- and three-dimensional
graphs. Use the pointColor option for points.
draw ( x ^2 , x = -1..1 , pointColor == green () )
x^2
x^2
7.1.6 Palette
Domain Palette is the domain of shades of colors: dark, dim, bright, pastel, and light, designated by
the integers 1 through 5, respectively. Colors are normally “bright.”
shade red ()
3 (1)
PositiveInteger
1 (3)
PositiveInteger
x^2
Once you have created a viewport, move your mouse to the viewport and click with your left mouse
button to display a control-panel. The panel is displayed on the side of the viewport closest to where
you clicked. Each of the buttons which toggle on and off show the current state of the graph.
Transformations
Object transformations are executed from the control-panel by mouse-activated potentiometer win-
dows.
Scale: To scale a graph, click on a mouse button within the Scale window in the upper left corner
of the control-panel. The axes along which the scaling is to occur are indicated by setting the
toggles above the arrow. With X On and Y On appearing, both axes are selected and scaling is
uniform. If either is not selected, for example, if X Off appears, scaling is non-uniform.
208 CHAPTER 7. GRAPHICS
Translate: To translate a graph, click the mouse in the Translate window in the direction you wish
the graph to move. This window is located in the upper right corner of the control-panel. Along
the top of the Translate window are two buttons for selecting the direction of translation.
Translation along both coordinate axes results when X On and Y On appear or along one axis
when one is on, for example, X On and Y Off appear.
Messages
The window directly below the transformation potentiometer windows is used to display system mes-
sages relating to the viewport and the control-panel. The following format is displayed:
The two values to the left show the scale factor along the X and Y coordinate axes. The two values to
the right show the distance of translation from the center in the X and 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.
Multiple Graphs
The Graphs window contains buttons that allow the placement of two-dimensional graphs into one of
nine available slots in any other two-dimensional 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 transfor-
mation. 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.
Clear: The Clear button deselects every viewport graph slot. A graph slot is reselected by selecting
the button below its number.
Query: The Query button is used to display the scale and 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 Graphs window. The scaling factor and translation offset of the graph
are then displayed in the message window.
Pick: The Pick button is used to select a graph 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 Drop in some other graph.
Drop: Once a graph has been picked up using the Pick button, the Drop button places it into a
new viewport slot. The message “Click on the graph to drop” appears in the message window
when the Drop button is selected. By selecting one of the slot number buttons in the Graphs
window, the graph currently being held is dropped into this slot and displayed.
7.1. TWO-DIMENSIONAL GRAPHICS 209
Buttons
Box encloses the area of the viewport graph in a bounding box, or removes the box if already enclosed.
PS writes the current viewport contents to a file fricas2D.ps. The file is placed in the directory from
which FriCAS or the viewAlone program was invoked.
Reset resets the object transformation characteristics and attributes back to their initial states.
Hide makes the control-panel disappear.
Here is a summary of useful FriCAS operations for two-dimensional 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, integer). If appropriate, a default value for an argument is
given in parentheses immediately following the name.
adaptive ([boolean(true)])
sets or indicates whether graphs are plotted according to the adaptive refinement algorithm.
axesColorDefault ([color(dark blue())])
sets or indicates the default color of the axes in a two-dimensional graph viewport.
clipPointsDefault ([boolean(false)])
sets or indicates whether point clipping is to be applied as the default for graph plots.
drawToScale ([boolean(false)])
sets or indicates whether the plot of a graph is “to scale” or uses the entire viewport space as
the default.
lineColorDefault ([color(pastel yellow())])
sets or indicates the default color of the lines or curves in a two-dimensional graph viewport.
maxPoints ([integer(500)])
sets or indicates the default maximum number of possible points to be used when constructing a
two-dimensional graph.
minPoints ([integer(21)])
sets or indicates the default minimum number of possible points to be used when constructing a
two-dimensional graph.
210 CHAPTER 7. GRAPHICS
viewPosDefault ([list([100,100])])
sets or indicates the default position of the upper left-hand corner of a two-dimensional viewport,
relative to the display root window. The upper left-hand corner of the display is considered to
be at the (0, 0) position.
viewSizeDefault ([list([200,200])])
sets or indicates the default size in which two dimensional viewport windows are shown. It is
defined by a width and then a height.
viewWriteAvailable ([list(["pixmap", "bitmap", "postscript", "image")])
indicates the possible file types that can be created with the ‘write‘ function.
viewWriteDefault ([list([])])
sets or indicates the default types of files, in addition to the data file, that are created when a
write function is executed on a viewport.
units (viewport, integer(1), string("off"))
turns the units on or off for the graph with index integer.
key (viewport)
returns the process ID number for viewport.
move (viewport, integerx (viewPosDefault), integery (viewPosDefault))
moves viewport on the screen so that the upper left-hand corner of viewport is at the position
(x,y).
options (viewport)
returns a list of all the DrawOptions used by viewport.
points (viewport, integer(1), string("on"))
specifies whether the graph points for graph integer are to be displayed or not.
region (viewport, integer(1), string("off"))
declares whether graph integer is or is not to be displayed with a bounding rectangle.
reset (viewport)
resets all the properties of viewport.
resize (viewport, integerwidth , integerheight )
resizes viewport with a new width and height.
scale (viewport, integern (1), integerx (0.9), integery (0.9))
scales values for the x and y coordinates of graph n.
show (viewport, integern (1), string("on"))
indicates if graph n is shown or not.
title (viewport, string("FriCAS 2D"))
designates the title for viewport.
translate (viewport, integern (1), floatx (0.0), floaty (0.0))
causes graph n to be moved x and y units in the respective directions.
write (viewport, stringdirectory , [strings])
if no third argument is given, writes the data file onto the directory with extension data. The
third argument can be a single string or a list of strings with some or all the entries "pixmap",
"bitmap", "postscript", and "image".
In this section we demonstrate how to create two-dimensional graphs from lists of points and give an
example showing how to read the lists of points from a file.
FriCAS creates lists of points in a two-dimensional viewport by utilizing the GraphImage and
TwoDimensionalViewport domains. In this example, the makeGraphImage 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 FriCAS and made into a two-dimensional viewport.
p1 := point [1 ,1] $ ( Point DFLOAT )
212 CHAPTER 7. GRAPHICS
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
[[[1.0, 1.0] , [0.0, 1.0]] , [[0.0, 1.0] , [0.0, 0.0]] , [[0.0, 0.0] , [1.0, 0.0]] , [[1.0, 0.0] , [1.0, 1.0]] , [[1.0,
(13)
0.5] , [0.5, 0.0]] , [[0.5, 0.0] , [0.0, 0.5]] , [[0.0, 0.5] , [0.5, 1.0]] , [[0.5, 1.0] , [1.0, 0.5]] , [[0.25, 0.25] ,
[0.25, 0.75]] , [[0.25, 0.75] , [0.75, 0.75]] , [[0.75, 0.75] , [0.75, 0.25]] , [[0.75, 0.25] , [0.25, 0.25]]]
Now we set the point sizes for all components of the graph.
size1 := 6:: P os i ti ve In t eg er
6 (14)
PositiveInteger
size2 := 8:: P os i ti ve In t eg er
8 (15)
PositiveInteger
size3 := 10:: P o si ti ve I nt eg er
10 (16)
PositiveInteger
lsize := [ size1 , size1 , size1 , size1 , size2 , size2 , size2 , size2 , size3 , size3 ,
size3 , size3 ]
List ( PositiveInteger )
Palette
pc2 := dim green ()
Palette
pc3 := pastel yellow ()
Palette
lpc := [ pc1 , pc1 , pc1 , pc1 , pc2 , pc2 , pc2 , pc2 , pc3 , pc3 , pc3 , pc3 ]
List ( Palette )
List ( Palette )
Now the GraphImage is created according to the component specifications indicated above.
g := makeGr aphImage ( llp , lpc , lc , lsize ) $ GRIMAGE
The makeViewport2D function now creates a TwoDimensionalViewport for this graph according to
the list of options specified within the brackets.
make Viewport 2D (g ,[ title (" Lines ") ]) $ VIEW2D
Lines
This example demonstrates the use of the GraphImage functions component and appendPoint in
adding points to an empty GraphImage.
) clear all
All user variables and function definitions have been cleared .
g := graphImage () $ GRIMAGE
216 CHAPTER 7. GRAPHICS
GraphImage
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
component (g , p1 ) $ GRIMAGE
component (g , p2 ) $ GRIMAGE
appendPoint (g , p3 ) $ GRIMAGE
appendPoint (g , p4 ) $ GRIMAGE
appendPoint (g , p5 ) $ GRIMAGE
Graph Points
A list of points can also be made into a GraphImage by using the operation coerce. It is equivalent
to adding each point to g2 using component.
g2 := coerce ([[ p1 ] ,[ p2 ] ,[ p3 ] ,[ p4 ] ,[ p5 ]]) $ GRIMAGE
GraphImage
TwoDimensionalViewport
TwoDimensionalViewport
Take a look.
make Viewport 2D ( v ) $ VIEW2D
218 CHAPTER 7. GRAPHICS
Just Points
The following three functions read a list of points from a file and then draw the points and the con-
necting lines. The points are stored in the file in readable form as floating point numbers (specifically,
DoubleFloat values) as an alternating stream of x- and y-values. For example,
This command will actually create the viewport and the graph if the point data is in the file "file.
data".
1 plotData2D (" file . data " , "2 D Data Plot ")
7.1. TWO-DIMENSIONAL GRAPHICS 219
This section demonstrates how to append a two-dimensional graph to a viewport already containing
other graphs. The default draw command places a graph into the first GraphImage slot position of
the TwoDimensionalViewport.
This graph is in the first slot in its viewport.
v1 := draw ( sin ( x ) ,x =0..2*% pi )
Compiling function % C with type DoubleFloat -> DoubleFloat
TwoDimensionalViewport
So is this graph.
v2 := draw ( cos ( x ) ,x =0..2*% pi , curveColor == light red () )
Compiling function % E with type DoubleFloat -> DoubleFloat
TwoDimensionalViewport
The operation getGraph retrieves the GraphImage g1 from the first slot position in the viewport v1.
g1 := getGraph ( v1 ,1)
GraphImage
Now putGraph places g1 into the the second slot position of v2.
putGraph ( v2 , g1 ,2)
cos(x)
220 CHAPTER 7. GRAPHICS
Instead of using draw to draw a graph and then extract graph data we can use makeObject. First
graph.
g3 := makeObject ( sin ( x ) ,x = -1..% pi ,[])
Compiling function % G with type DoubleFloat -> DoubleFloat
TwoDimensionalViewport
Now putGraph places g3 into the the second slot position of v3.
putGraph ( v3 , g3 ,2)
cos(x)
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.
The simplest three-dimensional graph is that of a surface defined by a function of two variables, z =
f(x,y).
The general format for drawing a surface defined by a formula f(x,y) of two variables x and y is:
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 “=” sign. Notice that FriCAS uses the
text of your function as a default title.
draw ( cos ( x * y ) ,x = -3..3 , y = -3..3)
cos(x*y)
X Y
If you intend to use a function more than once, or it is long and complex, then first give its definition
to FriCAS.
f (x , y ) == sin ( x ) * cos ( y )
To draw the function, just give its name and drop the variables from the range specifications. FriCAS
compiles your function for efficient computation of data for the graph.
draw (f , -% pi ..% pi , -% pi ..% pi )
222 CHAPTER 7. GRAPHICS
FriCAS3D
X Y
A second kind of three-dimensional graph is a three-dimensional space curve defined by the parametric
equations for x(t), y(t), and z(t) as a function of an independent variable t.
The general format for drawing a three-dimensional space curve defined by parametric formulas
x = f(t), y = g(t), and z = h(t) is:
If you use explicit formulas to draw a space curve, always precede the range specification with the
variable name and an “=” sign.
draw ( curve (5* cos ( t ) , 5* sin ( t ) ,t ) , t = -12..12)
5*cos(t)
X Y
Give the names of the functions and drop the variable name specification in the second argument.
Again, FriCAS supplies a default title.
draw ( curve ( i1 , i2 , i3 ) ,0..15*% pi )
FriCAS3D
X Y
A third kind of three-dimensional graph is a surface defined by parametric equations for x(u,v),
y(u,v), and z(u,v) of two independent variables u and v.
The general format for drawing a three-dimensional graph defined by parametric formulas x = f
(u,v), y = g(u,v), and z = h(u,v) is:
This example draws a graph of a surface plotted using the parabolic cylindrical coordinate system
option. The values of the functions supplied to surface are interpreted in coordinates as given by a
coordinates option, here as parabolic cylindrical coordinates (see Section 7.2.7 on page 235).
224 CHAPTER 7. GRAPHICS
u*cos(v)
X Y
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 DoubleFloat.
n1 ( u : DFLOAT , v : DFLOAT ) : DFLOAT == u * cos ( v )
Function declaration n1 : ( DoubleFloat , DoubleFloat ) -> DoubleFloat has been
added to workspace .
In either case, FriCAS compiles the functions when needed to graph a result.
n3 ( u : DFLOAT , v : DFLOAT ) : DFLOAT == u
Function declaration n3 : ( DoubleFloat , DoubleFloat ) -> DoubleFloat has been
added to workspace .
Without these declarations, you have to suffix floats with @DFLOAT to get a DoubleFloat result.
However, a call here with an unadorned float produces a DoubleFloat.
n3 (0.5 ,1.0)
Compiling function n3 with type ( DoubleFloat , DoubleFloat ) -> DoubleFloat
0.5 (4)
DoubleFloat
Draw the surface by referencing the function names, this time choosing the toroidal coordinate system.
FriCAS3D
X Y
The draw commands optionally take an optional list of options such as coordinates as shown in the
last example. Each option is given by the syntax: name == value. Here is a list of the available options
in the order that they are described below:
title coordinates var1Steps
style tubeRadius var2Steps
colorFunction tubePoints space
The option title gives your graph a title.
draw ( cos ( x * y ) ,x =0..2*% pi , y =0..% pi , title == " Title of Graph ")
Title of Graph
X Y
The style determines which of four rendering algorithms is used for the graph. The choices are
"wireMesh", "solid", "shade", and "smooth".
draw ( cos ( x * y ) ,x = -3..3 , y = -3..3 , style ==" smooth " , title ==" Smooth Option ")
226 CHAPTER 7. GRAPHICS
Smooth Option
X Y
In all but the wire-mesh style, polygons in a surface or tube plot are normally colored in a graph
according to their z-coordinate value. Space curves are colored according to their parametric variable
value. To change this, you can give a coloring function. The coloring function is sampled across the
range of its arguments, then normalized onto the standard FriCAS colormap.
A function of one variable makes the color depend on the value of the parametric variable specified for
a tube plot.
color1 ( t ) == t
sin(t)
X Y
A function of two variables makes the color depend on the values of the independent variables.
color2 (u , v ) == u ^2 - v ^2
cos(u*v)
X Y
With a three variable function, the color also depends on the value of the function.
color3 (x ,y , fxy ) == sin ( x * fxy ) + cos ( y * fxy )
cos(x*y)
X Y
Normally the Cartesian coordinate system is used. To change this, use the coordinates option. For
details, see Section 7.2.7 on page 235.
m ( u : DFLOAT , v : DFLOAT ) : DFLOAT == 1
Function declaration m : ( DoubleFloat , DoubleFloat ) -> DoubleFloat has been
added to workspace .
FriCAS3D
X Y
Space curves may be displayed as tubes with polygonal cross sections. Two options, tubeRadius and
tubePoints, control the size and shape of this cross section. The tubeRadius option specifies the
radius of the tube that encircles the specified space curve.
draw ( curve ( sin ( t ) , cos ( t ) ,0) ,t =0..2*% pi , style ==" shade " , tubeRadius == .3)
sin(t)
X Y
The tubePoints option specifies the number of vertices 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.
draw ( curve ( sin ( t ) , cos ( t ) , 0) , t =0..2*% pi , style ==" shade " , tubeRadius == .25 ,
tubePoints == 3)
7.2. THREE-DIMENSIONAL GRAPHICS 229
sin(t)
X Y
Options var1Steps and var2Steps 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).
draw ( cos ( x * y ) ,x = -3..3 , y = -3..3 , style ==" shade " , var1Steps == 30 , var2Steps == 30)
cos(x*y)
X Y
The space option of a draw command lets you build multiple graphs in three space. To use this option,
first create an empty three-space object, then use the space option thereafter. There is no restriction
as to the number or kinds of graphs that can be combined this way. Create an empty three-space
object.
s := create3Space () $ ( ThreeSpace DFLOAT )
ThreeSpace(DoubleFloat)
Add a graph to this three-space object. The new graph destructively inserts the graph into s.
draw (m ,0..% pi ,0..2*% pi , coordinates == spherical , space == s )
230 CHAPTER 7. GRAPHICS
FriCAS3D
X Y
FriCAS3D
X Y
A three-space object can also be obtained from an existing three-dimensional viewport using the
subspace command. You can then use makeViewport3D to create a viewport window. Assign to
subsp the three-space object in viewport v.
subsp := subspace v
An alternate way to create multiple graphs is to use makeObject. The makeObject command is similar
to the draw command, except that it returns a three-space object rather than a ThreeDimension-
alViewport. In fact, makeObject is called by the draw command to create the ThreeSpace then
makeViewport3D to create a viewport window.
7.2. THREE-DIMENSIONAL GRAPHICS 231
Do the last example a new way. First use makeObject to create a three-space object sph.
sph := makeObject (m , 0..% pi , 0..2*% pi , coordinates == spherical )
Compiling function m with type ( DoubleFloat , DoubleFloat ) -> DoubleFloat
ThreeSpace(DoubleFloat)
ThreeSpace(DoubleFloat)
Note that an undefined ThreeSpace parameter declared in a makeObject or draw command results in
an error. Use the create3Space function to define a ThreeSpace, or obtain a ThreeSpace that has
been previously generated before including it in a command line.
Rather than using the draw and makeObject commands, you can create three-dimensional graphs from
primitives. Operation create3Space creates a three-space object to which points, curves and polygons
can be added using the operations from the ThreeSpace domain. The resulting object can then be
displayed in a viewport using makeViewport3D.
Create the empty three-space object space.
space := create3Space () $ ( ThreeSpace DFLOAT )
ThreeSpace(DoubleFloat)
Objects can be sent to this space using the operations exported by the ThreeSpace domain. The
following examples place curves into space.
Add these eight curves to the space.
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]])
232 CHAPTER 7. GRAPHICS
ThreeSpace(DoubleFloat)
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]])
ThreeSpace(DoubleFloat)
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]])
ThreeSpace(DoubleFloat)
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]])
ThreeSpace(DoubleFloat)
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]])
ThreeSpace(DoubleFloat)
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]])
ThreeSpace(DoubleFloat)
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]])
ThreeSpace(DoubleFloat)
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]])
ThreeSpace(DoubleFloat)
Create and display the viewport using makeViewport3D. Options may also be given but here are dis-
played as a list with values enclosed in parentheses.
make Viewport 3D ( space , title == " Letters ")
Letters
X Y
Cube Example
As a second example of the use of primitives, we generate a cube using a polygon mesh. It is important
to use a consistent orientation of the polygons for correct generation of three-dimensional objects.
Again start with an empty three-space object.
spaceC := create3Space () $ ( ThreeSpace DFLOAT )
ThreeSpace(DoubleFloat)
1.0 (11)
DoubleFloat
y : DFLOAT := -1
− 1.0 (12)
DoubleFloat
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Point(DoubleFloat)
Add the faces of the cube as polygons to the space using a consistent orientation.
polygon ( spaceC ,[ d ,c ,g , h ])
ThreeSpace(DoubleFloat)
polygon ( spaceC ,[ d ,h ,e , a ])
ThreeSpace(DoubleFloat)
polygon ( spaceC ,[ c ,d ,a , b ])
ThreeSpace(DoubleFloat)
polygon ( spaceC ,[ g ,c ,b , f ])
ThreeSpace(DoubleFloat)
polygon ( spaceC ,[ h ,g ,f , e ])
ThreeSpace(DoubleFloat)
polygon ( spaceC ,[ e ,f ,b , a ])
ThreeSpace(DoubleFloat)
Cube
X Y
The CoordinateSystems package provides coordinate transformation functions that map a given
data point from the coordinate system specified into the Cartesian coordinate system. The default
236 CHAPTER 7. GRAPHICS
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.
m ( u : DFLOAT , v : DFLOAT ) : DFLOAT == u ^2
Function declaration m : ( DoubleFloat , DoubleFloat ) -> DoubleFloat has been
added to workspace .
FriCAS3D
X Y
The z coordinate comes first since the first argument of the draw command gives its values. In general,
the coordinate systems FriCAS provides, or any that you make up, must provide a map to an (x, y, z)
triplet in order to be compatible with the coordinates DrawOption. Here is an example.
Define the identity function.
cartesian ( point : Point DFLOAT ) : Point DFLOAT == point
Function declaration cartesian : Point ( DoubleFloat ) -> Point ( DoubleFloat ) has
been added to workspace .
FriCAS3D
X Y
7.2. THREE-DIMENSIONAL GRAPHICS 237
What happened? The option coordinates == cartesian directs FriCAS to treat the dependent
variable m defined by m = u2 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 cylindrical transform takes input of the form (w,u,v), interprets it in
the order (r,θ,z) and maps it to the Cartesian coordinates x = r cos(θ), y = r sin(θ), z = z in which r
is the radius, θ is the angle and z is the z-coordinate. An example using the cylindrical coordinates
for the constant r = 3.
f ( u : DFLOAT , v : DFLOAT ) : DFLOAT == 3
Function declaration f : ( DoubleFloat , DoubleFloat ) -> DoubleFloat has been
added to workspace .
FriCAS3D
X Y
Suppose you would like to specify z as a function of r and θ instead of just r? Well, you still can
use the cylindrical FriCAS 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.
col := 5
5 (4)
PositiveInteger
Point(DoubleFloat)
The reordering you want is (z, r, θ) to (r, θ, 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 reorder to reorder the point elements.
reorder ( p : Point DFLOAT ) : Point DFLOAT == point [ p .2 , p .3 , p .1 , p .4]
238 CHAPTER 7. GRAPHICS
The function moves the second and third elements forward but the color does not change.
reorder pt
Compiling function reorder with type Point ( DoubleFloat ) -> Point ( DoubleFloat )
Point(DoubleFloat)
The function newmap converts our reordered version of the cylindrical coordinate system to the
standard (x, y, z) Cartesian system.
newmap ( pt : Point DFLOAT ) : Point DFLOAT == cylindrical ( reorder pt )
Function declaration newmap : Point ( DoubleFloat ) -> Point ( DoubleFloat ) has been
added to workspace .
newmap pt
Compiling function newmap with type Point ( DoubleFloat ) -> Point ( DoubleFloat )
Point(DoubleFloat)
Graph the same function f using the coordinate mapping of the function newmap, so it is now interpreted
as z = 3:
draw (f ,0..3 ,0..2*% pi , coordinates == newmap )
FriCAS3D
X Y
The CoordinateSystems package exports the following operations: bipolar, bipolarCylindrical, carte-
sian, conical, cylindrical, elliptic, ellipticCylindrical, oblateSpheroidal, parabolic, parabolicCylindrical,
paraboloidal, polar, prolateSpheroidal, spherical, and toroidal. Use Browse or the )show system com-
mand to get more information.
A three-dimensional graph can be explicitly clipped within the draw command by indicating a minimum
and maximum threshold for the given function definition. These thresholds can be defined using the
7.2. THREE-DIMENSIONAL GRAPHICS 239
Here is an example that clips the gamma function in order to eliminate the extreme divergence it
creates.
draw ( gamma , -% pi ..% pi , -% pi ..% pi , var1Steps ==50 , var2Steps ==50)
FriCAS3D
X Y
Once you have created a viewport, move your mouse to the viewport and click with your left mouse
button. This displays a control-panel on the side of the viewport that is closest to where you clicked.
Transformations
We recommend you first select the Bounds button while executing transformations since the bounding
box displayed indicates the object’s position as it changes.
Rotate: A rotation transformation occurs by clicking the mouse within the Rotate window in the
upper left corner of the control-panel. The rotation is computed in spherical coordinates, using
the horizontal mouse position to increment or decrement the value of the longitudinal angle θ
within the range of 0 to 2π and the vertical mouse position to increment or decrement the value
of the latitudinal angle φ within the range of -π to π. 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.
origin: The origin button indicates that the rotation is to occur with respect to the origin of
the viewing space, that is indicated by the axes.
object: The 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.
Scale: A scaling transformation occurs by clicking the mouse within the Scale window in the upper
center of the control-panel, containing a zoom arrow. The axes along which the scaling is to occur
are indicated by selecting the appropriate button above the zoom arrow window. The selected
axes are displayed in green on a color monitor or in clear text on a black and white monitor,
while the unselected axes are displayed in red for a color display or a mottled pattern for black
and white.
uniform: Uniform scaling along the x, y and z axes occurs when all the axes buttons are selected.
non-uniform: If any of the axes buttons are not selected, non-uniform scaling occurs, that is,
scaling occurs only in the direction of the axes that are selected.
Translate: Translation occurs by indicating with the mouse in the Translate window the direction
you want the graph to move. This window is located in the upper right corner of the control-panel
and contains a potentiometer with crossed arrows pointing up, down, left and right. Along the top
of the Translate window are three buttons (XY, XZ, and 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.
Messages
The window directly below the potentiometer windows for transformations is used to display system
messages relating to the viewport, the control-panel and the current graph displaying status.
Colormap
Directly below the message window is the colormap range indicator window. The FriCAS 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
7.2. THREE-DIMENSIONAL GRAPHICS 241
in monochromatic smooth shading of the graph when Smooth mode is selected. At each end of the
Colormap are + and - buttons. When clicked on, these increment or decrement the top or bottom
marker.
Buttons
Below the Colormap window and to the left are located various buttons that determine the character-
istics 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.
Wire displays surface and tube plots as a 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.
Solid displays the graph with hidden 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.
Shade displays the graph with hidden 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.
Smooth displays the graph using a 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 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 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. 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.
Bounds encloses the entire volume of the viewgraph within a bounding box, or removes the box if
previously selected. The region that encloses the entire volume of the viewport graph is displayed.
Axes displays Cartesian coordinate axes of the space, or turns them off if previously selected.
Outline causes quadrilateral polygons forming the graph surface to be outlined in black when the
graph is displayed in Shade mode.
BW converts a color viewport to black and white, or vice-versa. When this button is selected the
control-panel and viewport switch to an immutable colormap composed of a range of grey scale
patterns or tiles that are used wherever shading is necessary.
Light takes you to a control-panel described below.
242 CHAPTER 7. GRAPHICS
Reset returns the object transformation characteristics back to their initial states.
Hide causes the control-panel for the corresponding viewport to disappear from the screen.
Quit queries whether the current viewport session should be terminated.
Light
The Light button changes the control-panel into the Lighting Control-Panel. At the top of this
panel, the three axes are shown with the same orientation as the object. A light vector from the origin
of the axes shows the current position of the light source relative to the object. At the bottom of the
panel is an Abort button that cancels any changes to the lighting that were made, and a Return
button that carries out the current set of lighting changes on the graph.
XY: The XY lighting axes window is below the Lighting Control-Panel title and to the left. This
changes the light vector within the XY view plane.
Z: The Z lighting axis window is below the Lighting Control-Panel title and in the center. This
changes the Z location of the light vector.
Intensity: Below the Lighting Control-Panel title 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.
View Volume
The View Volume button changes the control-panel into the Viewing Volume Panel. At the
bottom of the viewing panel is an Abort button that cancels any changes to the viewing volume that
were made and a Return button that carries out the current set of viewing changes to the graph.
Eye Reference: At the top of this panel is the 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
Hither window. By moving the slider in this window the hither clipping plane sets 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 Eye Distance slider to the right of the Hither slider is
used to change the degree of perspective in the image.
7.2. THREE-DIMENSIONAL GRAPHICS 243
Clip Volume: The Clip Volume window is at the bottom of the Viewing Volume Panel. On
the right is a Settings menu. In this menu are buttons to select viewing attributes. Selecting
the Perspective button computes the image using perspective projection. The Show Region
button indicates whether the clipping region of the volume is to be drawn in the viewport and
the Clipping On button shows whether the view volume clipping is to be in effect when the
image is drawn. The left side of the Clip Volume window shows the clipping boundary of the
graph. Moving the knobs along the X, Y, and Z sliders adjusts the volume of the clipping region
accordingly.
Here is a summary of useful FriCAS operations for three-dimensional 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, integer). If appropriate, a default value for an argument is
given in parentheses immediately following the name.
adaptive3D? ()
tests whether space curves are to be plotted according to the adaptive refinement algorithm.
axes (viewport, string("on"))
turns the axes on and off.
close (viewport)
closes the viewport.
colorDef (viewport, color1 (1), color2 (27))
sets the colormap range to be from color1 to color2 .
controlPanel (viewport, string("off"))
declares whether the control-panel for the viewport is to be displayed or not.
diagonals (viewport, string("off"))
declares whether the polygon outline includes the diagonals or not.
drawStyle (viewport, style)
selects which of four drawing styles are used: "wireMesh", "solid", "shade", or "smooth".
eyeDistance (viewport,float(500))
sets the distance of the eye from the origin of the object for use in the ‘perspective‘.
key (viewport)
returns the operating system process ID number for the viewport.
lighting (viewport, floatx (-0.5), floaty (0.5), floatz (0.5))
sets the Cartesian coordinates of the light source.
modifyPointData (viewport,integer,point)
replaces the coordinates of the point with the index integer with point.
move (viewport, integerx (viewPosDefault), integery (viewPosDefault))
moves the upper left-hand corner of the viewport to screen position (integerx , integery ).
244 CHAPTER 7. GRAPHICS
options (viewport)
returns a list of all current draw options.
outlineRender (viewport, string("off"))
turns polygon outlining off or on when drawing in "shade" mode.
perspective (viewport, string("on"))
turns perspective viewing on and off.
reset (viewport)
resets the attributes of a viewport to their initial settings.
resize (viewport, integerwidth (viewSizeDefault), integerheight (viewSizeDefault))
resets the width and height values for a viewport.
rotate (viewport, numberθ (viewThetaDefault), numberφ (viewPhiDefault))
rotates the viewport by rotation angles for longitude (θ) and latitude (φ). Angles designate
radians if given as floats, or degrees if given as integers.
setAdaptive3D (boolean(true))
sets whether space curves are to be plotted according to the adaptive refinement algorithm.
setMaxPoints3D (integer(1000))
sets the default maximum number of possible points to be used when constructing a three-di-
mensional space curve.
setMinPoints3D (integer(49))
sets the default minimum number of possible points to be used when constructing a three-dimen-
sional space curve.
setScreenResolution3D (integer(500))
sets the default screen resolution constant used in setting the computation limit of adaptively
generated three-dimensional space curve plots.
showRegion (viewport, string("off"))
declares whether the bounding box of a graph is shown or not.
subspace (viewport)
returns the space component.
subspace (viewport, subspace)
resets the space component to subspace.
intensity (viewport,float(1.0))
resets the intensity I of the light source, 0 ≤ I ≤ 1.
tubePointsDefault ([integer(6)])
sets or indicates the default number of vertices defining the polygon that is used to create a tube
around a space curve.
7.2. THREE-DIMENSIONAL GRAPHICS 245
tubeRadiusDefault ([float(0.5)])
sets or indicates the default radius of the tube that encircles a space curve.
var1StepsDefault ([integer(27)])
sets or indicates the default number of increments into which the grid defining a surface plot is
subdivided with respect to the first parameter declared in the surface function.
var2StepsDefault ([integer(27)])
sets or indicates the default number of increments into which the grid defining a surface plot is
subdivided with respect to the second parameter declared in the surface function.
viewPhiDefault ([float(-π/4)])
resets the default latitudinal view angle, or returns the current default angle if no argument is
given. φ is set to this value.
viewpoint (viewport, floatx , floaty , floatz )
sets the viewing position in Cartesian coordinates.
viewPosDefault ([list([0,0])])
sets or indicates the position of the upper left-hand corner of a two-dimensional viewport, relative
to the display root window (the upper left-hand corner of the display is [0, 0]).
viewSizeDefault ([list([400,400])])
sets or indicates the width and height dimensions of a viewport.
viewThetaDefault ([float(π/4)])
resets the default longitudinal view angle, or returns the current default angle if no argument is
given. When a parameter is specified, the default longitudinal view angle θ is set to this value.
viewWriteAvailable ([list(["pixmap", "bitmap", "postscript", "image")])
indicates the possible file types that can be created with the ‘write‘ function.
viewWriteDefault ([list([])])
sets or indicates the default types of files that are created in addition to the data file when a
‘write‘ command is executed on a viewport.
246 CHAPTER 7. GRAPHICS
Both the two-dimensional and three-dimensional drawing facilities consult the .Xdefaults file for
various defaults. The list of defaults that are recognized by the graphing routines is discussed in
this section. These defaults are preceded by FriCAS.3D. for three-dimensional viewport defaults,
FriCAS.2D. for two-dimensional viewport defaults, or FriCAS* (no dot) for those defaults that are
acceptable to either viewport type.
FriCAS*buttonFont: font
This indicates which font type is used for the button text on the control-panel. The default value
is "Rom11".
FriCAS*titleFont font
This indicates which font type is used for the title text and, for three-dimensional graphs, in the
lighting and viewing-volume control-panel windows. The default value is "Rom14".
249
Chapter 8
In this chapter we describe techniques useful in solving advanced problems with FriCAS.
The handling of roots depends on whether the floating-point type is real or complex: for the real
floating-point types, DoubleFloat and Float, if a real root exists the one with the same sign as the
radicand is returned; for the complex floating-point types, the principal value is returned. Also, for
real floating-point types the inverse functions produce errors if the results are not real. This includes
cases such as asin(1.2), log(-3.2), sqrt(-1.1). The default floating-point type is Float so to
evaluate functions using Float or Complex Float, just use normal decimal notation.
251
252 CHAPTER 8. ADVANCED PROBLEM SOLVING
exp (3.1)
22.197951281441633405 (1)
Float
exp (3.1 + 4.5 * % i )
Complex(Float)
Complex(DoubleFloat)
Complex(DoubleFloat)
A number of special functions are provided by the package DoubleFloatSpecialFunctions for the
machine-precision floating-point types. The special functions provided are listed below, where F stands
for the types DoubleFloat and Complex DoubleFloat. The real versions of the functions yield an
error if the result is not real.
Gamma: F → F
Gamma(z) is the Euler gamma function, Γ(z), defined by
Z ∞
Γ(z) = tz−1 e−t dt.
0
Beta: F → F
Beta(u, v) is the Euler Beta function, B(u, v), defined by
Z 1
B(u, v) = tu−1 (1 − t)v−1 dt.
0
logGamma: F → F
logGamma(z) is the natural logarithm of Γ(z). This can often be computed even if Γ(z) cannot.
digamma: F → F
digamma(z), also called psi(z), is the function ψ(z), defined by
ψ(z) = Γ′ (z)/Γ(z).
8.1. NUMERIC FUNCTIONS 253
besselY: (F,F) → F
besselY(v,z) is the Bessel function of the second kind, Yν (z). This function satisfies the same
differential equation as besselJ. The implementation simply uses the relation
besselI: (F,F) → F
besselI(v,z) is the modified Bessel function of the first kind, Iν (z). This function satisfies the
differential equation
z 2 w′′ (z) + zw′ (z) − (z 2 + ν 2 )w(z) = 0.
besselK: (F,F) → F
besselK(v,z) is the modified Bessel function of the second kind, Kν (z). This function satisfies the
same differential equation as besselI. The implementation simply uses the relation
airyAi: F → F
airyAi(z) is the Airy function Ai(z). This function satisfies the differential equation w′′ (z) − zw(z) =
0. The implementation simply uses the relation
1√ 2 2
Ai(−z) = z(J−1/3 ( z 3/2 ) + J1/3 ( z 3/2 )).
3 3 3
airyBi: F → F
airyBi(z) is the Airy function Bi(z). This function satisfies the same differential equation as airyAi.
The implementation simply uses the relation
1√ 2 2
Bi(−z) = 3z(J−1/3 ( z 3/2 ) − J1/3 ( z 3/2 )).
3 3 3
hypergeometric0F1: (F,F) → F
hypergeometric0F1(c,z) is the hypergeometric function 0 F1 (; c; z).
The package FloatSpecialFunctions provides the implementation of some special functions for Float
or Complex Float arguments, including Gamma, Beta, logGamma, digamma. If you give Float or
Complex Float arguments to a special function that has not yet defined to accept Float arguments,
these are respectively converted to DoubleFloat or Complex DoubleFloat arguments.
Gamma (0.5) ^2
254 CHAPTER 8. ADVANCED PROBLEM SOLVING
3.1415926535897932385 (5)
Float
a := 2.1; b := 1.1; besselI ( a + % i *b , b * a + 1)
Complex(DoubleFloat)
A number of additional operations may be used to compute numerical values. These are special poly-
nomial functions that can be evaluated for values in any commutative ring R, and in particular for
values in any floating-point type. The following operations are provided by the package Orthogo-
nalPolynomialFunctions:
chebyshevT: (NonNegativeInteger, R)→R
chebyshevT(n,z) is the nth Chebyshev polynomial of the first kind, Tn (z). These are defined by
∞
1 − tz X
= Tn (z)tn .
1 − 2tz + t2 n=0
These operations require non-negative integers for the indices, but otherwise the argument can be given
as desired.
8.1. NUMERIC FUNCTIONS 255
1, z, 2 z 2 − 1, 4 z 3 − 3 z, 8 z 4 − 8 z 2 + 1, 16 z 5 − 20 z 3 + 5 z
(7)
The expression chebyshevT(n,z) evaluates to the nth Chebyshev polynomial of the first kind.
chebyshevT (3 , 5.0 + 6.0*% i )
Complex(Float)
485.0 (9)
DoubleFloat
The expression chebyshevU(n,z) evaluates to the nth Chebyshev polynomial of the second kind.
[ chebyshevU (i , z ) for i in 0..5]
1, 2 z, 4 z 2 − 1, 8 z 3 − 4 z, 16 z 4 − 12 z 2 + 1, 32 z 5 − 32 z 3 + 6 z
(10)
chebyshevU (3 , 0.2)
− 0.736 (11)
Float
− 0.1448706729337934088E93 (13)
Float
1, −z + 1, z 2 − 4 z + 2, −z 3 + 9 z 2 − 18 z + 6, z 4 − 16 z 3 + 72 z 2 − 96 z + 24
(14)
256 CHAPTER 8. ADVANCED PROBLEM SOLVING
laguerreL (4 , 1.2)
− 13.0944 (15)
Float
[ laguerreL (j , 3 , z ) for j in 0..4]
3
−z + 9 z 2 − 18 z + 6, −3 z 2 + 18 z − 18, −6 z + 18, −6, 0
(16)
laguerreL (1 , 3 , 2.1)
6.57 (17)
Float
3 1 5 3 35 4 15 2 3 63 5 35 3 15
1, z, z 2 − , z 3 − z, z − z + , z − z + z (18)
2 2 2 2 8 4 8 8 4 8
legendreP (3 , 3.0*% i )
− 72.0 i (19)
Complex(Float)
Finally, three number-theoretic polynomial operations may be evaluated. The following operations are
provided by the package NumberTheoreticPolynomialFunctions. .
bernoulliB: (NonNegativeInteger, R)→R
bernoulliB(n,z) is the nth Bernoulli polynomial, Bn (z). These are defined by
∞
tezt X tn
= Bn (z)
et − 1 n=0 n!
precisely the primitive nth roots of unity. This polynomial has degree given by the Euler totient
function φ(n).
The expression bernoulliB(n,z) evaluates to the nth Bernoulli polynomial.
bernoulliB (3 , z )
3 2 1
z3 − z + z (20)
2 2
Polynomial(Fraction ( Integer ))
Complex(Float)
3 2 1
z3 − z + (22)
2 4
Polynomial(Fraction ( Integer ))
Complex(Float)
z2 + z + 1 (24)
Polynomial( Integer )
0.0 (25)
Complex(Float)
Drawing complex functions in FriCAS is presently somewhat awkward compared to drawing real func-
tions. It is necessary to use the draw operations that operate on functions rather than expressions.
This is the complex exponential function (rotated interactively). 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.
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 ")
258 CHAPTER 8. ADVANCED PROBLEM SOLVING
exp(x+%i*y)
X Y
This is the complex arctangent function. 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.
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
atan(x+%i*y)
Gamma(x+%i*y)
X Y
Beta(x,y)
Z
X Y
This is the Bessel function Jα (x) for index α in the range -6..4 and argument x in the range 2..14.
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)
besselJ(alpha,x)
X Y
260 CHAPTER 8. ADVANCED PROBLEM SOLVING
This is the modified Bessel function Iα (x) evaluated for various real values of the index α and fixed
argument x = 5.
draw ( besselI ( alpha , 5) , alpha = -12..12 , unit ==[5 ,20])
besselI(alpha,5)
20
-20
-40
-60 -10 -5 0 5 10
This is similar to the last example except the index α takes on complex values in a 6 x 6 rectangle
centered on the origin.
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 ")
besselI(x+i*y,5)
X Y
− 2 x3 y 3 + 24 x5 + 24 y 2 + −4 x6 − x3 y + 48 x8 + 12 x5 + 48 x3 + 12
(1)
Polynomial( Integer )
factor v
− x3 y − 12 x5 − 12 2 y 2 + 4 x3 + 1
(2)
Factored(Polynomial( Integer ))
35 5 95 3
48 x8 + 8 x7 − 2 x6 + x + x + 8 x2 + 12 (3)
3 2
Polynomial(Fraction ( Integer ))
factor w
1 2 1 1 3
48 x3 + x + x5 − x +1 (4)
6 4 24
3 x4 + 2 x2 + 15 x + 18 (1)
Polynomial(PrimeField(19))
These include the integers mod p, where p is prime, and extensions of these fields.
factor u
3 (x + 18) x3 + x2 + 8 x + 13
(2)
Factored(Polynomial(PrimeField(19)))
Convert this to have coefficients in the finite field with 193 elements. See Section 8.11 on page 303 for
more information about finite fields.
factor ( u :: POLY FFX ( PF 19 ,3) )
262 CHAPTER 8. ADVANCED PROBLEM SOLVING
Polynomials with coefficients in simple algebraic extensions of the rational numbers can be factored.
Here, aa and bb are symbolic roots of polynomials.
aa := rootOf ( aa ^2+ aa +1)
aa (1)
AlgebraicNumber
+ (−aa − 1) x7 + (−2 aa − 2) x6 − x5 + 2 aa x4 + aa x3
Polynomial(AlgebraicNumber)
Note that the second argument to factor can be a list of algebraic extensions to factor over.
factor (p ,[ aa ])
2
(−aa − 1) y + x3 + (−aa − 1) x y 2 + x2 + x
(3)
Factored(Polynomial(AlgebraicNumber))
x2 + 3 (4)
Factored(Polynomial( Integer ))
Factor the same polynomial over the field obtained by adjoining aa to the rational numbers.
factor ( x ^2+3 ,[ aa ])
(x + 2 aa + 1) (x − 2 aa − 1) (5)
Factored(Polynomial(AlgebraicNumber))
x3 + 12 aa + 6 x3 − 12 aa − 6
(6)
Factored(Polynomial(AlgebraicNumber))
bb := rootOf ( bb ^3 -2)
bb (7)
AlgebraicNumber
factor ( x ^6+108 ,[ bb ])
Factored(Polynomial(AlgebraicNumber))
Factor again over the field obtained by adjoining both aa and bb to the rational numbers.
factor ( x ^6+108 ,[ aa , bb ])
(x + (aa + 2) bb) (x + (−2 aa − 1) bb) (x + (aa − 1) bb) (x + (−aa + 1) bb) (x + (2 aa + 1) bb) (x + (−aa − 2) bb)
(9)
Factored(Polynomial(AlgebraicNumber))
Since fractions of polynomials form a field, every element (other than zero) divides any other, so there
is no useful notion of irreducible factors. Thus the factor operation is not very useful for fractions of
polynomials.
There is, instead, a specific operation factorFraction that separately factors the numerator and denom-
inator and returns a fraction of the factored results.
fact orFracti on (( x ^2 -4) /( y ^2 -4) )
(x − 2) (x + 2)
(1)
(y − 2) (y + 2)
You can also use map. This expression applies the factor operation to the numerator and denominator.
map ( factor ,( x ^2 -4) /( y ^2 -4) )
(x − 2) (x + 2)
(2)
(y − 2) (y + 2)
Use rootOf to get a symbolic root of a polynomial: rootOf(p, x) returns a root of p(x).
This creates an algebraic number a.
a := rootOf ( a ^4+1 , a )
a (1)
Expression ( Integer )
a4 + 1 (2)
Expression ( Integer )
b (3)
Expression ( Integer )
b+a (4)
Expression ( Integer )
% ^ 5
10 a3 + 11 a2 + 2 a − 4 b + 15 a3 + 10 a2 + 4 a − 10
(5)
Expression ( Integer )
The operation zeroOf is similar to rootOf, except that it may express the root using radicals in some
cases.
rootOf ( c ^2+ c +1 , c )
8.3. MANIPULATING SYMBOLIC ROOTS OF A POLYNOMIAL 265
c (6)
Expression ( Integer )
zeroOf ( d ^2+ d +1 , d )
√
−3 − 1
(7)
2
Expression ( Integer )
rootOf ( e ^5 -2 , e )
e (8)
Expression ( Integer )
zeroOf ( f ^5 -2 , f )
√
5
2 (9)
Expression ( Integer )
Use 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 appears n times in the list.
Compute all the roots of x^4 + x + 1.
l := rootsOf ( x ^4 + x + 1 , x )
As a side effect, the variables %x0, %x1 and %x2 are bound to the first three roots of x^4 + x + 1.
% x0 ^5
Expression ( Integer )
Although they all satisfy x^4 + x + 1 = 0, %x0, %x1, and %x2 are different algebraic numbers. To
find the algebraic relation that defines each of them, use definingPolynomial.
d e f i n i n g P o l y n o m i a l % x0
Expression ( Integer )
d e f i n i n g P o l y n o m i a l % x1
Expression ( Integer )
d e f i n i n g P o l y n o m i a l % x2
Expression ( Integer )
We can check that the sum and product of the roots of x^4 + x + 1 are its trace and norm.
x3 := last l
Expression ( Integer )
% x0 + % x1 + % x2 + x3
0 (7)
Expression ( Integer )
% x0 * % x1 * % x2 * x3
1 (8)
Expression ( Integer )
Note, that in general roots are expressions in new symbols. For example for x^4 + 1 the second root
is a product.
rootsOf ( x ^4 + 1 , x )
Corresponding to the pair of operations rootOf/zeroOf in Section 8.5.2 on page 272, there is an operation
zerosOf that, like rootsOf, computes all the roots of a given polynomial, but which expresses some of
them in terms of radicals.
zerosOf ( y ^4 + y + 1 , y )
" p
−3 %x12 − 2 %x0 %x1 − 3 %x02 − %x1 − %x0
%x0, %x1, ,
2 (10)
p #
− −3 %x12 − 2 %x0 %x1 − 3 %x02 − %x1 − %x0
2
8.4. COMPUTATION OF EIGENVALUES AND EIGENVECTORS 267
As you see, only two implicit algebraic numbers were created (%y0,%y1), and its defining equations are
below. The other two roots are expressed in radicals.
d e f i n i n g P o l y n o m i a l % y0
Expression ( Integer )
d e f i n i n g P o l y n o m i a l % y1
Expression ( Integer )
√ √ √ √
−1 + 1 −1 − 1 − −1 − 1 − −1 + 1
√ , √ , √ , √ (13)
2 2 2 2
List (AlgebraicNumber)
1 2 1
2 1 −2 (1)
1 −2 4
Matrix( Integer )
5, %P | %P 2 − %P − 5
(2)
0
1
−
2
(3)
1
The operation eigenvectors returns a list of pairs of values and vectors. When an eigenvalue is rational,
FriCAS 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 eigen-
vector using the eigenvalue. This means that if you ask FriCAS to solve the minimal polynomial, then
you can substitute these roots into the parametric form of the corresponding eigenvectors.
You must be aware that unless an exact eigenvalue has been computed, the eigenvector may be badly
in error.
eigenvectors ( m1 )
0
1
eigval = 5, eigmult = 1, eigvec = − ,
2
1 (4)
%R
2
eigval = %R | %R − %R − 5 , eigmult = 1, eigvec = 2
1
Another possibility is to use the operation radicalEigenvectors tries to compute explicitly the eigenvec-
tors in terms of radicals.
r a d i c a l E i g e n v e c t o r s ( m1 )
√21+1
√ √
radval = 21 + 1 2 − 21 + 1
, radmult = 1, radvect = 2 , radval = ,
2 2 (5)
1
−√21+1
2
0
radmult = 1, radvect = 2 , radval = 5, radmult = 1, radvect = − 1
2
1 1
List (Record(radval : Expression ( Integer ) , radmult: Integer , radvect : List (Matrix(Expression ( Integer )))))
Alternatively, FriCAS can compute real or complex approximations to the eigenvectors and eigenvalues
using the operations realEigenvectors or complexEigenvectors. They each take an additional argument ϵ
to specify the “precision” required. In the real case, this means that each approximation will be within
±ϵ of the actual result. In the complex case, this means that each approximation will be within ±ϵ of
the actual result in each of the real and imaginary parts.
The precision can be specified as a Float if the results are desired in floating-point notation, or as
Fraction Integer if the results are to be expressed using rational (or complex rational) numbers.
r e a l E i g e n v e c t o rs ( m1 ,1/1000)
8.4. COMPUTATION OF EIGENVALUES AND EIGENVECTORS 269
0
outval = 5, outmult = 1, outvect = − 1 , outval = 5717 , outmult = 1,
2
2048 (6)
1
5717 3669
2048
− 2048
3669
outvect = 2 , outval = − , outmult = 1, outvect = 2
2048
1 1
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 eigenMatrix
gives you a matrix of the eigenvectors.
eigenMatrix ( m1 )
√21+1 √
− 21+1
2 2
0
1 (7)
2 2 −2
1 1 1
−5 −2
(8)
18 7
Matrix( Integer )
eigenMatrix ( m2 )
"failed" (9)
If a symmetric matrix has a basis of orthonormal eigenvectors, then orthonormalBasis computes a list
of these vectors.
m3 := matrix [[1 ,2] ,[2 ,1]]
1 2
(10)
2 1
Matrix( Integer )
o r t h o n o r m a l B a s is ( m3 )
"" # " ##
− √12 √1
2
√1
, √1
(11)
2 2
You can use the operation solve to solve systems of linear equations.
The operation 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:
x + y + z = 8
3x − 2y + z = 0
x + 2y + 2z = 17
evaluate this expression.
solve ([ x + y + z =8 ,3* x -2* y + z =0 , x +2* y +2* z =17] ,[ x ,y , z ])
Parameters are given as new variables starting with a percent sign and “%” 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
x + 2y + 3z = 2
2x + 3y + 4z = 2
3x + 4y + 5z = 2
[[x = %W − 2, y = −2 %W + 2, z = %W ]] (2)
The system can also be presented as a matrix and a vector. The matrix contains the coefficients of
the linear equations and the vector contains the numbers appearing on the right-hand sides of the
equations. You may input the matrix as a list of rows and the vector as a list of its elements.
To solve the system:
x + y + z = 8
3x − 2y + z = 0
x + 2y + 2z = 17
in matrix form you would evaluate this expression.
solve ([[1 ,1 ,1] ,[3 , -2 ,1] ,[1 ,2 ,2]] ,[8 ,0 ,17])
8.5. SOLUTION OF LINEAR AND POLYNOMIAL EQUATIONS 271
Record( particular : Union(Vector(Fraction( Integer )) , ” failed ”), basis : List (Vector( Fraction ( Integer ))))
The solutions are presented as a Record with two components: the component particular contains
a particular solution of the given system or the item "failed" if there are no solutions, the compo-
nent 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 basis
component contains non-trivial vectors.
This happens when you solve the linear system
x + 2y + 3z = 2
2x + 3y + 4z = 2
3x + 4y + 5z = 2
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 basis vectors.
When no solution exists then "failed" is returned as the particular component.
For example:
solve ([[1 ,2 ,3] ,[2 ,3 ,4] ,[3 ,4 ,5]] ,[2 ,3 ,2])
Record( particular : Union(Vector(Fraction( Integer )) , ” failed ”), basis : List (Vector( Fraction ( Integer ))))
When you want to solve a system of homogeneous equations (that is, a system where the numbers on
the right-hand sides of the equations are all zero) in the matrix form you can omit the second argument
and use the nullSpace operation.
This computes the solutions of the following system of equations:
x + 2y + 3z = 0
2x + 3y + 4z = 0
3x + 4y + 5z = 0
The result is given as a list of vectors and these vectors form a basis for the solution space.
nullSpace ([[1 ,2 ,3] ,[2 ,3 ,4] ,[3 ,4 ,5]])
FriCAS can solve polynomial equations producing either approximate or exact solutions. Exact solu-
tions 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.
solve ( x ^3 = 8,x)
x = 2, x2 + 2 x + 4 = 0
(1)
If you want solutions expressed in terms of radicals you would use this instead.
radicalSolve ( x ^3 = 8,x)
√ √
x = − −3 − 1, x = −3 − 1, x = 2 (2)
The solve command always returns a value but radicalSolve returns only the solutions that it is able to
express in terms of radicals.
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” ϵ. This means that each approxi-
mation will be within ±ϵ of the actual result.
Notice that the type of second argument controls the type of the result.
solve ( x ^4 - 10* x ^3 + 35* x ^2 - 50* x + 25 ,.0001)
List (Equation(Polynomial(Float)))
If you give a floating-point precision you get a floating-point result; if you give the precision as a
rational number you get a rational result.
solve ( x ^3 -2 ,1/1000)
2581
x= (4)
2048
If you want approximate complex results you should use the command complexSolve that takes the
same precision argument ϵ.
complexSolve ( x ^3 -2 ,.0001)
8.5. SOLUTION OF LINEAR AND POLYNOMIAL EQUATIONS 273
[x = 1.259921049815602600574493408203125,
(5)
x = −0.62996052473711410282 − 1.0911236358806490898 i,
x = −0.62996052473711410282 + 1.091123635880649089813232421875 i]
List (Equation(Polynomial(Complex(Float))))
Each approximation will be within ±ϵ of the actual result in each of the real and imaginary parts.
complexSolve ( x ^2 -2*% i +1 ,1/100)
294134286731975036665549444025970722793320109632199 10670475
x=− − i, (6)
374144419156711147060143317175368453031918731001856 8388608
294134286731975036665549444025970722793320109632199 10670475
x= + i
374144419156711147060143317175368453031918731001856 8388608
List (Equation(Polynomial(Complex(Fraction(Integer)))))
Note that if you omit the = from the first argument FriCAS 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.
FriCAS can also solve equations involving rational functions. Solutions where the denominator vanishes
are discarded.
radicalSolve (1/ x ^3 + 1/ x ^2 + 1/ x = 0 , x )
√ √
− −3 − 1 −3 − 1
x= , x= (7)
2 2
Symbolic solutions can be presented using “implicit” algebraic numbers defined as roots of irreducible
polynomials or in terms of radicals. FriCAS can also find approximations to the real or complex roots
of a system of polynomial equations to any user-specified accuracy.
274 CHAPTER 8. ADVANCED PROBLEM SOLVING
The operation solve for systems is used in a way similar to 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 Section 8.5.2 on page 272.
Use the operation solve if you want implicitly presented solutions.
solve ([3* x ^3 + y + 1 , y ^2 -4] ,[ x , y ])
[x = −1, y = 2] , x2 − x + 1 = 0, y = 2 , 3 x3 − 1 = 0, y = −2
(1)
3 z2 + z + 9
z
x= ,y= , 9 z 4 + 6 z 3 + 55 z 2 + 15 z − 90 = 0 (2)
3 3
√ √ √ √
−3 + 1 − −3 + 1 − −1 3 − 1
x= , y=2 , x= , y=2 , x= √3
, (3)
2 2 2 3
√ √
−1 3 − 1 1
y = −2 , x = √
3
, y = −2 , x = √
3
, y = −2 , [x = −1, y = 2]
2 3 3
List ( List (Equation(Expression( Integer ))))
To get numeric solutions you only need to give the list of equations and the precision desired. The list
of variables would be redundant information since there can be no parameters for the numerical solver.
If the precision is expressed as a floating-point number you get results expressed as floats.
solve ([ x ^2* y - 1 , x * y ^2 - 2] ,.01)
To get complex numeric solutions, use the operation complexSolve, which takes the same arguments as
in the real case.
complexSolve ([ x ^2* y - 1 , x * y ^2 - 2] ,1/1000)
8.6. LIMITS 275
27925854633327 27925854633327
y= , x= ,
17592186044416 35184372088832
9279956946215592179803150679423538973037814343717 3023062441857
y=− − i,
11692013098647223345629478661730264157247460343808 2199023255552
9279956946215592179803150679423538973037814343717 3023062441857
(5)
x=− − i ,
23384026197294446691258957323460528314494920687616 4398046511104
9279956946215592179803150679423538973037814343717 3023062441857
y=− + i,
11692013098647223345629478661730264157247460343808 2199023255552
9279956946215592179803150679423538973037814343717 3023062441857
x=− + i
23384026197294446691258957323460528314494920687616 4398046511104
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.
solve ([ x ^2/ a = a , a = a * x ] ,.001)
When solving equations with denominators, all solutions where the denominator vanishes are dis-
carded.
radicalSolve ([ x ^2/ a + a + y ^3 - 1 , a * y + a + 1] ,[ x , y ])
"" r # " r ##
−a4 + 2 a3 + 3 a2 + 3 a + 1 −a − 1 −a4 + 2 a3 + 3 a2 + 3 a + 1 −a − 1
x=− ,y= , x= ,y= (7)
a2 a a2 a
8.6 Limits
To compute a limit, you must specify a functional expression, a variable, and a limiting value for that
variable. If you do not specify a direction, FriCAS attempts to compute a two-sided limit.
Issue this to compute the limit
x2 − 3x + 2
lim .
x→1 x2 − 1
limit (( x ^2 - 3* x + 2) /( x ^2 - 1) ,x = 1)
1
− (1)
2
Union(OrderedCompletion(Fraction(Polynomial(Integer))) , ...)
Sometimes the limit when approached from the left is different from the limit from the right and, in
this case, you may wish to ask for a one-sided limit. Also, if you have a function that is only defined
on one side of a particular value, you can compute a one-sided limit.
276 CHAPTER 8. ADVANCED PROBLEM SOLVING
The function log(x) is real only to the right of zero, that is, for x > 0. Thus, when computing limits
of functions involving log(x), you probably want a “right-hand” limit.
limit ( x * log ( x ) ,x = 0 ," right ")
0 (2)
Union(OrderedCompletion(Expression(Integer)) , ...)
When you do not specify "right" or "left" as the optional fourth argument, limit tries to compute a
two-sided limit. Here the limit from the left does not exist, as FriCAS indicates when you try to take
a two-sided limit.
limit ( sin (1/ x ) * exp (1/ x ) , x =0)
A function can be defined on both sides of a particular value, but tend to different limits as its variable
approaches
p that value from the left and from the right. We p can construct an example of this as follows:
Since y 2 is simply the absolute value
p of y, the function y 2p
/y is simply the sign (+1 or -1) of the
nonzero real number y. Therefore, y /y = −1 for y < 0 and y 2 /y = +1 for y > 0. This is what
2
happens when we take the limit at y = 0. The answer returned by FriCAS gives both a “left-hand”
and a “right-hand” limit.
limit ( sqrt ( y ^2) /y , y = 0)
1 1
lef tHandLimit = − √ , rightHandLimit = √ (5)
2 2
Union(Record(leftHandLimit: Union(OrderedCompletion(Expression(Integer)) , ” failed ”), rightHandLimit: Union(
OrderedCompletion(Expression(Integer)) , ” failed ”)) , ...)
You can compute limits at infinity by passing either +∞ or −∞ as the third argument of limit. To
do this, use the constants %plusInfinity and %minusInfinity.
limit ( sqrt (3* x ^2 + 1) /(5* x ) ,x = % plusInfinity )
√
3
(6)
5
8.6. LIMITS 277
Union(OrderedCompletion(Expression(Integer)) , ...)
√
3
− (7)
5
Union(OrderedCompletion(Expression(Integer)) , ...)
You can take limits of functions with parameters. As you can see, the limit is expressed in terms of
the parameters.
limit ( sinh ( a * x ) / tan ( b * x ) ,x = 0)
a
(8)
b
Union(OrderedCompletion(Expression(Integer)) , ...)
When you use limit, you are taking the limit of a real function of a real variable. When you compute
this, FriCAS 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.
limit ( z * sin (1/ z ) ,z = 0)
0 (9)
Union(OrderedCompletion(Expression(Integer)) , ...)
However, as a function of a complex variable, sin(1/z) is badly behaved near 0 (one says that sin
(1/z) has an essential singularity at z = 0). 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. FriCAS indicates
this when we call complexLimit.
complexLimit ( z * sin (1/ z ) ,z = 0)
"failed" (10)
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 complexLimit.
complexLimit ((2 + z ) /(1 - z ) ,z = % infinity )
−1 (11)
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.
limit ( sin ( x ) /x , x = % plusInfinity )
278 CHAPTER 8. ADVANCED PROBLEM SOLVING
0 (12)
Union(OrderedCompletion(Expression(Integer)) , ...)
"failed" (13)
4 a3
(1)
s4 + 4 a4
Expression ( Integer )
Expression ( Integer )
log s2 + a2 − 2 log(s)
(3)
Expression ( Integer )
1
(4)
b s2 + 2 a b s + b3 + a2 b
Expression ( Integer )
log s2 + b2 − log s2 + a2
(5)
2
8.8. INTEGRATION 279
Expression ( Integer )
eb log s+c−a
c
(6)
s−a
Expression ( Integer )
laplace ( a * Ci ( b * t ) + c * Si ( d * t ) , t , s )
s2 +b2 d
a log b2
+ 2 c arctan s
(7)
2s
Expression ( Integer )
When FriCAS does not know about a particular transform, it keeps it as a formal transform in the
answer.
laplace ( sin ( a * t ) - a * t * cos ( a * t ) + exp ( t ^2) , t , s )
2
s4 + 2 a2 s2 + a4 laplace et , t, s + 2 a3
(8)
s4 + 2 a2 s2 + a4
Expression ( Integer )
8.8 Integration
Integration is the reverse process of differentiation, that is, an 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 FunctionSpaceIntegration
provides the top-level integration operation, integrate, for integrating real-valued elementary functions.
√
Z x log b + %BH a + 1
d%BH (2)
%BH
280 CHAPTER 8. ADVANCED PROBLEM SOLVING
Given an elementary function to integrate, FriCAS 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 that look quite different because the form of the antiderivative depends on
the sign of a constant that appears in the function.
integrate (1/( x ^2 - 2) ,x )
√
(x2 +2) 2−4 x
log x2 −2
√ (3)
2 2
Union(Expression( Integer ) , ...)
integrate (1/( x ^2 + 2) ,x )
√
arctan x 2 2
√ (4)
2
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 FriCAS 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 the
answer involving the square root of -a when a < 0.
integrate ( x ^2 / ( x ^4 - a ^2) , x )
√ √ 2 √ √
(x2 −a)
−a+2 a x (x +a) a−2 a x
log x2 +a
− 2 arctan x a−a log x2 −a
+ 2 arctan x a
a
√ , √ (5)
4 −a 4 a
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 complexIntegrate, which is
provided by the package FunctionSpaceComplexIntegration.
This operation is used for integrating complex-valued elementary functions.
c o m p l e x I n t e g r a te ( x ^2 / ( x ^4 - a ^2) , x )
q q q q q q q q
− 41a log 2 a 41a + x + − 41a log 2 a − 41a + x − − 41a log −2 a − 41a + x + 41a log −2 a 41a + x
(6)
2
Expression ( Integer )
As with the real case, antiderivatives for most complex-valued functions cannot be expressed in terms
of elementary functions.
8.8. INTEGRATION 281
c o m p l e x I n t e g r a te ( log (1 + sqrt ( a * x + b ) ) / x , x )
√
Z x log b + %BH a + 1
d%BH (7)
%BH
Expression ( Integer )
Sometimes integrate can involve symbolic algebraic numbers such as those returned by rootOf. To see
how to work with these strange generated symbols (such as %%a0), see Section 8.3.2 on page 265.
Definite integration is the process of computing the area between 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 RationalFunctionDefiniteIntegration provides the top-level definite integration op-
eration, integrate, for integrating real-valued rational functions.
integrate (( x ^4 - 3* x ^2 + 6) /( x ^6 -5* x ^4+5* x ^2+4) , x = 1..2)
1
2 arctan(8) + 2 arctan(5) + 2 arctan(2) + 2 arctan 2
−π
(8)
2
Union(f1: OrderedCompletion(Expression(Integer)) , ...)
FriCAS 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:
integrate(1/(x^2-2), x = 1..2)
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, FriCAS issues a warning that a pole might lie in the path of integration, and does
not compute the integral.
integrate (1/( x ^2 - a ) , x = 1..2)
"potentialPole" (9)
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 "noPole" as a third argument to integrate:
The value here is, of course, incorrect if sqrt(a) is between 1 and 2.
integrate (1/( x ^2 - a ) , x = 1..2 , " noPole ")
282 CHAPTER 8. ADVANCED PROBLEM SOLVING
√ √
(−4 a2 −4 a) a+a3 +6 a2 +a (−8 a2 −32 a) a+a3 +24 a2 +16 a
√ √
− log + log 2 −a
a2 −2 a+1 a2 −8 a+16 − arctan a
+ arctan a−a
√ , √
4 a −a
(10)
This is the easiest way to create a power series. This tells FriCAS that x is to be treated as a power
series, so functions of x are again power series.
x := series ’x
x (1)
We didn’t say anything about the coefficients of the power series, so the coefficients are general ex-
pressions 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
numbers).
1/(1 - x - x ^2)
1 + x + 2 x2 + 3 x3 + 5 x4 + 8 x5 + 13 x6 + 21 x7 + O x8
(2)
1 3 1 5 1
x7 + O x9
x− x + x − (3)
6 120 5040
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
When you enter this expression you introduce the symbolic constants sin(1) and cos(1).
sin (1 + x )
When you enter the expression the variable a appears in the resulting series expansion.
sin ( a * x )
a3 3 a5 5 a7 7
x + O x9
ax − x + x − (5)
6 120 5040
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 Section 8.9.5 on page 288.
series (1/ log ( y ) ,y = 1)
1 1 1 19
(y − 1)−1 + − (y − 1) + (y − 1)2 − (y − 1)3 (6)
2 12 24 720
3 863 275
(y − 1)4 − (y − 1)5 + (y − 1)6 + O (y − 1)7
+
160 60480 24192
UnivariatePuiseuxSeries ( Expression ( Integer ) , y, 1)
You can create power series with more general coefficients. You normally accomplish this via a type
declaration (see Section 2.3 on page 74). See Section 8.9.4 on page 286 for some warnings about
working with declared series.
We declare that y is a one-variable Taylor series (UTS is the abbreviation for UnivariateTay-
lorSeries) in the variable z with FLOAT (that is, floating-point) coefficients, centered about 0.
Then, by assignment, we obtain the Taylor expansion of exp(z) with floating-point coefficients.
y : UTS ( FLOAT , ’z ,0) := exp ( z )
You can also create a power series by giving an explicit formula for its nth coefficient. For details and
more examples, see Section 8.9.6 on page 290.
284 CHAPTER 8. ADVANCED PROBLEM SOLVING
To create a series about w = 0 whose nth Taylor coefficient is 1/n!, you can evaluate this expression.
This is the Taylor expansion of exp(w) at w = 0.
series (1/ factorial ( n ) ,n , w = 0)
1 2 1 3 1 4 1 1 1
w5 + w6 + w7 + O w8
1+w+ w + w + w + (8)
2 6 24 120 720 5040
UnivariatePuiseuxSeries ( Expression ( Integer ) , w, 0)
You can extract any coefficient from a power series—even one that hasn’t been computed yet. This is
possible because in FriCAS, 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 lazy evaluation.) When you ask for a coefficient that hasn’t yet been computed, FriCAS computes
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.
x := series ( x )
x (1)
y := exp ( x ) * sin ( x )
1 3 1 5 1 6 1 7
x + x2 + x + O x9
x − x − x − (2)
3 30 90 630
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
1
− (3)
90
Expression ( Integer )
1
− (4)
10216206000
Expression ( Integer )
If you look at y then you see that the coefficients up to order 15 have all been computed.
) set stream showall on
8.9. WORKING WITH POWER SERIES 285
1 3 1 5 1 6 1 7 1 1
x + x2 + x − x − x − x + x9 + x10 (5)
3 30 90 630 22680 113400
1 1 1 1
x11 − x13 − x14 − x15 + O x16
+
1247400 97297200 681080400 10216206000
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
You can manipulate power series using the usual arithmetic operations +, -, *, and /.
The results of these operations are also power series.
x := series x
x (1)
(3 + x ) / (1 + 7* x )
You can also compute f(x) ^ g(x), where f(x) and g(x) are two power series.
base := 1 / (1 - x )
1 + x + x2 + x3 + x4 + x5 + x6 + x7 + O x8
(3)
expon := x * base
x + x2 + x3 + x4 + x5 + x6 + x7 + x8 + O x9
(4)
base ^ expon
3 3 7 4 43 5 649 6 241 7
1 + x2 + x + O x8
x + x + x + x + (5)
2 3 12 120 30
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
286 CHAPTER 8. ADVANCED PROBLEM SOLVING
Once you have created a power series, you can apply transcendental functions (for example, exp, log,
sin, tan, cosh, etc.) to it.
To demonstrate this, we first create the power series expansion of the rational function x2
1 − 6x + x2
about x = 0.
x := series ’x
x (1)
rat := x ^2 / (1 - 6* x + x ^2)
7133 6 80711 8
x2 + 6 x3 + 35 x4 + 204 x5 + x + 6927 x7 + x + 235068 x9 + O x10
(3)
6 2
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
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 (UTS is the abbreviation for
UnivariateTaylorSeries) in the variable y with FRAC INT (that is, fractions of integer) coefficients,
centered about 0.
y : UTS ( FRAC INT ,y ,0) := y
y (4)
You can now compute certain power series in y, provided that these series have rational coefficients.
exp ( y )
1 2 1 3 1 4 1 5 1 6 1
y7 + O y8
1+y+ y + y + y + y + y + (5)
2 6 24 120 720 5040
8.9. WORKING WITH POWER SERIES 287
You can get examples of such series by applying transcendental functions to series in y that have no
constant terms.
tan ( y ^2)
1 6
y2 + y + O y8
(6)
3
UnivariateTaylorSeries ( Fraction ( Integer ) , y, 0)
cos ( y + y ^5)
1 2 1 4 721 6
y + O y8
1− y + y − (7)
2 24 720
UnivariateTaylorSeries ( Fraction ( Integer ) , y, 0)
Similarly, you can compute the logarithm of a power series with rational coefficients if the constant
coefficient is 1.
log (1 + sin ( y ) )
1 2 1 3 1 4 1 5 1 6 61 7
y + O y8
y− y + y − y + y − y + (8)
2 6 12 24 45 5040
UnivariateTaylorSeries ( Fraction ( Integer ) , y, 0)
If you wanted to apply, say, the operation exp to a power series with a nonzero constant coefficient a0 ,
then the constant coefficient of the result would be ea0 , which is 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 exp defined for it. An example of such a domain is Expression Integer, the
type of formal functional expressions over the integers. When working with coefficients of this type,
z : UTS ( EXPR INT ,z ,0) := z
z (9)
e2 2 e2 3 3 e2 4 37 e2 5 59 e2 6 137 e2 7
e2 + e2 z + z + O z8
z + z + z + z + z + (10)
2 2 8 120 240 720
UnivariateTaylorSeries ( Expression ( Integer ) , z, 0)
Another way to create Taylor series whose coefficients are expressions over the integers is to use taylor
which works similarly to series. This is equivalent to the previous computation, except that now we
are using the variable w instead of z.
w := taylor ’w
288 CHAPTER 8. ADVANCED PROBLEM SOLVING
w (11)
exp (2 + tan ( w ) )
e2 2 e2 3 3 e2 4 37 e2 5 59 e2 6 137 e2 7
e2 + e2 w + w + O w8
w + w + w + w + w + (12)
2 2 8 120 240 720
UnivariateTaylorSeries ( Expression ( Integer ) , w, 0)
1 3 1 5 1
x7 + O x8
x− x + x − (1)
6 120 5040
UnivariateTaylorSeries ( Expression ( Integer ) , x, 0)
π
Here is the Taylor expansion of sin x about x = 6:
taylor ( sin ( x ) ,x = % pi /6)
√ √
1 3 π 1 π 2 3 π 3 1 π 4
+ x− − x− − x− + x− (2)
2 √2 6 4 6 12 √ 6 48 6
3 π 5 1 π 6 3 π 7 π 8
+ x− − x− − x− +O x−
240 6 1440 6 10080 6 6
The function to be expanded into a series may have variables other than the series variable. For
example, we may expand tan(x*y) as a Taylor series in x
taylor ( tan ( x * y ) ,x = 0)
y 3 3 2 y 5 5 17 y 7 7
x + O x8
yx+ x + x + (3)
3 15 315
UnivariateTaylorSeries ( Expression ( Integer ) , x, 0)
or as a Taylor series in y.
taylor ( tan ( x * y ) ,y = 0)
8.9. WORKING WITH POWER SERIES 289
x3 3 2 x5 5 17 x7 7
y + O y8
xy + y + y + (4)
3 15 315
UnivariateTaylorSeries ( Expression ( Integer ) , y, 0)
xt
te
A more interesting function is .
et − 1
When we expand this function as a Taylor series in t the nth order coefficient is the nth Bernoulli
polynomial divided by n!.
bern := taylor ( t * exp ( x * t ) /( exp ( t ) - 1) ,t = 0)
2x − 1 6 x2 − 6 x + 1 2 2 x3 − 3 x2 + x 3
1+ t+ t + t
2 12 12
30 x4 − 60 x3 + 30 x2 − 1 4 6 x5 − 15 x4 + 10 x3 − x 5 (5)
+ t + t
720 720
6 5 4 2
42 x − 126 x + 105 x − 21 x + 1 6 6 x − 21 x + 21 x5 − 7 x3 + x 7
7 6
t + O t8
+ t +
30240 30240
UnivariateTaylorSeries ( Expression ( Integer ) , t , 0)
Therefore, this and the next expression produce the same result.
factorial (6) * coefficient ( bern ,6)
42 x6 − 126 x5 + 105 x4 − 21 x2 + 1
(6)
42
Expression ( Integer )
bernoulliB (6 , x )
5 4 1 2 1
x6 − 3 x5 + x − x + (7)
2 2 42
Polynomial(Fraction ( Integer ))
Technically, a series with terms of negative degree is not considered to be a Taylor series, but, rather,
a Laurent series. If you try to compute a Taylor series expansion of logx x at x = 1 via taylor(x/log
(x),x = 1) you get an error message. The reason is that the function has a 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.
laurent ( x / log ( x ) ,x = 1)
3 5 1 11
(x − 1)−1 + + (x − 1) − (x − 1)2 + (x − 1)3 (8)
2 12 24 720
11 271 13
(x − 1)4 + (x − 1)5 − (x − 1)6 + O (x − 1)7
−
1440 60480 4480
290 CHAPTER 8. ADVANCED PROBLEM SOLVING
Similarly, a series with terms of fractional degree is neither a Taylor series nor a Laurent series. Such a
series is called a 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.
puiseux ( sqrt ( sec ( x ) ) ,x = 3 * % pi /2)
− 1 3 7 !
3π 2 1 3π 2 3π 2
x− + x− +O x− (9)
2 12 2 2
Finally, consider the case of functions that do not have Puiseux expansions about certain points. An
example of this is xx 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 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.
series ( x ^x , x =0)
The operation 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.
The GenerateUnivariatePowerSeries package enables you to create power series from explicit for-
mulas for their nth coefficients. In what follows, we construct series expansions for certain transcen-
dental 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. See
Section 8.9.5 on page 288 for more information.
Consider the Taylor expansion of ex about x = 0:
x2 x3
ex = 1+x+ + + ···
2 6
∞
X xn
=
n=0
n!
The nth Taylor coefficient is 1/n!. This is how you create this series in FriCAS.
series ( n + - > 1/ factorial ( n ) ,x = 0)
8.9. WORKING WITH POWER SERIES 291
1 2 1 3 1 4 1 5 1 6 1
x7 + O x8
1+x+ x + x + x + x + x + (1)
2 6 24 120 720 5040
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
The first argument specifies a formula for the nth 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 Section 6.17 on page 179.
Consider the Taylor expansion of log x about x = 1:
(x − 1)2 (x − 1)3
log(x) = (x − 1) − + − ···
2 3
∞
X (x − 1)n
= (−1)n−1
n=1
n
If you were to evaluate the expression series(n 7→ (-1)^(n-1)/ n, x = 1) you would get an error
message because FriCAS 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.
series ( n + - > ( -1) ^( n -1) /n , x = 1 ,1..)
1 1 1 1 1 1 1
(x − 1)2 + (x − 1)3 − (x − 1)4 + (x − 1)5 − (x − 1)6 + (x − 1)7 − (x − 1)8 + O (x − 1)9
(x − 1) −
2 3 4 5 6 7 8
(2)
x3 x5
sin(x) = x − + − ···
3! 5!
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.
series ( n + - > ( -1) ^(( n -1) /2) / factorial ( n ) ,x = 0 ,1.. ,2)
1 3 1 5 1
x7 + O x9
x− x + x − (3)
6 120 5040
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
The initial degree and the increment do not have to be integers. For example, this expression produces
1
a series expansion of sin(x 3 ).
series ( n + - > ( -1) ^((3* n -1) /2) / factorial (3* n ) ,x = 0 ,1/3.. ,2/3)
292 CHAPTER 8. ADVANCED PROBLEM SOLVING
1 1 1 5 1 7
x 3 + O x3
x3 − x+ x3 − (4)
6 120 5040
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.
cscx := series ( n + - > ( -1) ^(( n -1) /2) * 2 * (2^ n -1) * bernoulli ( numer ( n +1) ) /
factorial ( n +1) , x =0 , -1.. ,2)
1 7 3 31
x−1 + x5 + O x7
x+ x + (5)
6 360 15120
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
Of course, the reciprocal of this power series is the Taylor expansion of sin(x).
1/ cscx
1 3 1 5 1
x7 + O x9
x− x + x − (6)
6 120 5040
UnivariatePuiseuxSeries ( Expression ( Integer ) , x, 0)
1 3 3 5 5 7
x + O x9
x+ x + x + (7)
6 40 112
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).
sin ( asinx )
x + O x9
(8)
As we discussed in Section 8.9.5 on page 288, you can also use the operations taylor, laurent and puiseux
instead of series if you know ahead of time what kind of exponents a series has. You can’t go wrong
using series, though.
Use eval to substitute a numerical value for a variable in 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.
f := taylor ( exp ( x ) )
8.9. WORKING WITH POWER SERIES 293
1 2 1 3 1 4 1 5 1 6 1
x7 + O x8
1+x+ x + x + x + x + x + (1)
2 6 24 120 720 5040
UnivariateTaylorSeries ( Expression ( Integer ) , x, 0)
Then you evaluate the series at the value 1.0. The result is a sequence of the partial sums.
eval (f ,1.0)
Stream(Expression(Float))
25333 (1)
PositiveInteger
You can also compute a formula for the sum of the first k fourth powers, where k is an unspecified
positive integer.
sum4 := sum ( m ^4 , m = 1.. k )
6 k5 + 15 k4 + 10 k3 − k
(2)
30
Fraction (Polynomial( Integer ))
This formula is valid for any positive integer k. For instance, if we replace k by 10, we obtain the
number we computed earlier.
eval ( sum4 , k = 10)
25333 (3)
You can compute a formula for the sum of the first k nth powers in a similar fashion. Just replace the
4 in the definition of sum4 by any expression not involving k. FriCAS computes these formulas using
Bernoulli polynomials; we use the rest of this section to describe this method.
First consider this function of t and x.
f := t * exp ( x * t ) / ( exp ( t ) - 1)
294 CHAPTER 8. ADVANCED PROBLEM SOLVING
t et x
(4)
et − 1
Expression ( Integer )
Since the expressions involved get quite large, we tell FriCAS to show us only terms of degree up to
5.
) set streams calculate 5
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.
ff := taylor (f , t = 0)
2x − 1 6 x2 − 6 x + 1 2 2 x3 − 3 x2 + x 3
1+ t+ t + t (5)
2 12 12
30 x − 60 x + 30 x − 1 4 6 x − 15 x + 10 x3 − x 5
4 3 2 5 4
t + O t6
+ t +
720 720
UnivariateTaylorSeries ( Expression ( Integer ) , t , 0)
In fact, the nth coefficient in this series is essentially the nth Bernoulli polynomial: the nth coefficient of
1
the series is n! Bn (x), where Bn (x) is the nth Bernoulli polynomial. Thus, to obtain the nth Bernoulli
polynomial, we multiply the nth coefficient of the series ff by n!. For example, the sixth Bernoulli
polynomial is this.
factorial (6) * coefficient ( ff ,6)
42 x6 − 126 x5 + 105 x4 − 21 x2 + 1
(6)
42
Expression ( Integer )
We derive some properties of the function f(x,t). First we compute f(x + 1,t)- f(x,t).
g := eval (f , x = x + 1) - f
t et x+t − t et x
(7)
et − 1
Expression ( Integer )
t et x (8)
Expression ( Integer )
From this it follows that the nth coefficient in the Taylor expansion of g(x,t) at t = 0 is 1
(n−1)! xn−1 .
If you want to check this, evaluate the next expression.
taylor (g , t = 0)
8.9. WORKING WITH POWER SERIES 295
x2 3 x3 4 x4 5
t + x t2 + t + O t6
t + t + (9)
2 6 24
UnivariateTaylorSeries ( Expression ( Integer ) , t , 0)
Pb
When we add these equations we find that the sum of the left-hand sides is m=a mn−1 ,the sum of
the (n − 1)st powers from a to b. The sum of the right-hand sides is a “telescoping series.” After
cancellation, the sum is simply n1 (Bn (b + 1) − Bn (a)).
Replacing n by n + 1, we have shown that
b
X 1
mn = (Bn+1 (b + 1) − Bn+1 (a)).
m=a
n+1
Let’s use this to obtain the formula for the sum of fourth powers. First we obtain the Bernoulli
polynomial B5 .
B5 := factorial (5) * coefficient ( ff ,5)
6 x5 − 15 x4 + 10 x3 − x
(10)
6
Expression ( Integer )
To find the sum of the first k 4th powers, we multiply 1/5 by B5 (k + 1) − B5 (1).
1/5 * ( eval ( B5 , x = k + 1) - eval ( B5 , x = 1) )
6 k5 + 15 k4 + 10 k3 − k
(11)
30
Expression ( Integer )
6 k5 + 15 k4 + 10 k3 − k
(12)
30
296 CHAPTER 8. ADVANCED PROBLEM SOLVING
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.
For a discussion of the solution of systems of linear and polynomial equations, see Section 8.5 on page
270.
A differential equation is an equation involving an unknown function and one or more of its derivatives.
The equation is called ordinary if derivatives with respect to only one dependent variable appear in
the equation (it is called partial otherwise). The package ElementaryFunctionODESolver provides
the top-level operation solve for finding closed-form solutions of ordinary differential equations.
To solve a differential equation, you must first create an operator for the unknown function. We let
y be the unknown function in terms of x.
y := operator ’y
y (1)
BasicOperator
You then type the equation using D to create the derivatives of the unknown function y(x) where x
is any symbol you choose (the so-called dependent variable). This is how you enter the equation
y’’ + y’ + y = 0.
deq := D ( y x , x , 2) + D ( y x , x ) + y x = 0
Equation(Expression( Integer ))
The simplest way to invoke the solve command is with three arguments.
√ √
x 3 −x −x x 3
particular = 0, basis = cos e , e
2 2 sin (3)
2 2
Union(Record( particular : Expression ( Integer ) , basis : List ( Expression ( Integer ))) , ...)
Since linear ordinary differential equations have infinitely many solutions, solve returns a particular
solution fp and a basis f1 , . . . , fn for the solutions of the corresponding homogenuous equation. Any
expression of the form fp + c1 f1 + . . . cn fn where the ci 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 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 solve tries to find it. To specify initial conditions to solve, use an 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.
deq := D ( y x , x , 2) + y x
Expression ( Integer )
You can omit the = 0 when you enter the equation to be solved.
solve ( deq , y , x = 0 , [1 , 1])
FriCAS 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, FriCAS
is not limited by the order of the equation. FriCAS can solve the following third order equations
with polynomial coefficients.
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
Equation(Expression( Integer ))
solve ( deq , y , x )
x5 − 10 x3 + 20 x2 + 4
3
2 x − 3 x2 + 1 x3 − 1 x3 − 3 x2 − 1
particular = , basis = , , (7)
15 x x x x
298 CHAPTER 8. ADVANCED PROBLEM SOLVING
Union(Record( particular : Expression ( Integer ) , basis : List ( Expression ( Integer ))) , ...)
Expression ( Integer )
solve ( deq , y , x )
" " √ √ ##
x x e− 91 log(x) x e 91 log(x)
particular = 0, basis = , , (9)
x6 + 1 x6 + 1 x6 + 1
Union(Record( particular : Expression ( Integer ) , basis : List ( Expression ( Integer ))) , ...)
On the other hand, and in contrast with the operation integrate, it can happen that FriCAS finds no
solution and that some closed-form solution still exists. While it is mathematically complicated to
describe exactly when the solutions are guaranteed to be found, the following statements are correct
and form good guidelines for linear ordinary differential equations:
If the coefficients are constants, FriCAS finds a complete basis of solutions (i,e, all solutions).
If the coefficients are rational functions in the dependent variable, FriCAS at least finds all
solutions that do not involve algebraic functions.
Note that this last statement does not mean that FriCAS 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.
deq := ( x ^2 + 1) * D ( y x , x , 2) + 3 * x * D ( y x , x ) + y x = 0
Equation(Expression( Integer ))
solve ( deq , y , x )
" " √ ##
1 log x2 + 1 − x
particular = 0, basis = √ , √ (11)
x2 + 1 x2 + 1
Union(Record( particular : Expression ( Integer ) , basis : List ( Expression ( Integer ))) , ...)
This is an example that shows how to solve a non-linear first order ordinary differential equation
manually when an integrating factor can be found just by integration. At the end, we show you how
to solve it directly.
8.10. SOLUTION OF DIFFERENTIAL EQUATIONS 299
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.
m := -y
−y (1)
Polynomial( Integer )
n := x + y * log y
y log(y) + x (2)
Expression ( Integer )
−2 (3)
Expression ( Integer )
This is not zero, so the equation is not exact. Therefore we must look for an integrating factor: a
function µ(x,y) such that d(µ m)/dy = d(µ n)/dx. Normally, we first search for µ(x,y) depending
only on x or only on y. Let’s search for such a µ(x) first.
mu := operator ’ mu
mu (4)
BasicOperator
a := D ( mu ( x ) * m , y ) - D ( mu ( x ) * n , x )
Expression ( Integer )
If the above is zero for a function µ that does not depend on y, then µ(x) is an integrating factor.
solve ( a = 0 , mu , x )
1
particular = 0, basis = (6)
y 2 log(y)2 + 2 x y log(y) + x2
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.
b := D ( mu ( y ) * m , y ) - D ( mu ( y ) * n , x )
Expression ( Integer )
sb := solve ( b = 0 , mu , y )
1
particular = 0, basis = (8)
y2
Union(Record( particular : Expression ( Integer ) , basis : List ( Expression ( Integer ))) , ...)
We’ve found one! The above µ(y) is an integrating factor. We must multiply our initial equation
(that is, m and n) by the integrating factor.
intFactor := sb . basis .1
1
(9)
y2
Expression ( Integer )
m := intFactor * m
1
− (10)
y
Expression ( Integer )
n := intFactor * n
y log(y) + x
(11)
y2
Expression ( Integer )
0 (12)
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.
h := operator ’h
h (13)
BasicOperator
sol := h y + integrate (m , x )
y h(y) − x
(14)
y
8.10. SOLUTION OF DIFFERENTIAL EQUATIONS 301
Expression ( Integer )
y 2 h′ (y) + x
(15)
y2
Expression ( Integer )
log(y)2
particular = , basis = [1] (16)
2
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.
eval ( sol , h y = nsol . particular )
y log(y)2 − 2 x
(17)
2y
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 solve
operation. First define y to be an operator.
y := operator ’y
y (18)
BasicOperator
y(x)
y ′ (x) = (19)
y(x) log(y(x)) + x
Equation(Expression( Integer ))
y(x) log(y(x))2 − 2 x
(20)
2 y(x)
302 CHAPTER 8. ADVANCED PROBLEM SOLVING
The command to solve differential equations in power series around a particular initial point with
specific initial conditions is called 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.
) 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 FriCAS that the symbol ’y denotes a new operator.
y := operator ’y
y (1)
BasicOperator
Equation(Expression( Integer ))
1 3 e 4 e2 − 1 5 e3 − 2 e 6 e4 − 8 e2 + 4 e + 1 7
x + O x8
1+ x + x + x + x + (3)
6 24 120 720 5040
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 FriCAS that x is also an operator.
x := operator ’x
Compiled code for % JJ has been cleared .
x (4)
8.11. FINITE FIELDS 303
BasicOperator
Equation(Expression( Integer ))
eq2 := D ( y ( t ) , t ) = x ( t ) * y ( t )
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 [series for
x(t), series for y(t)].
seriesSolve ([ eq2 , eq1 ] , [x , y ] , t = 0 , [ y (0) = 1 , x (0) = 0])
Compiling function % JP with type List ( U n i v a r i a t e T a y l o r S e r i e s ( Expression ( Integer
) ,t ,0)) -> U n i v a r i a t e T a y l o r S e r i e s ( Expression ( Integer ) ,t ,0)
Compiling function % JQ with type List ( U n i v a r i a t e T a y l o r S e r i e s ( Expression ( Integer
) ,t ,0)) -> U n i v a r i a t e T a y l o r S e r i e s ( Expression ( Integer ) ,t ,0)
1 3 2 5 17 7 8 1 2 5 4 61 6 8
t+ t + t + t +O t , 1+ t + t + t +O t (7)
3 15 315 2 24 720
The order in which we give the equations and the initial conditions has no effect on the order of the
solution.
not take as an argument an object of the field. See Section 2.9 on page 89 for more information on
package-calling.
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 modulo n or, more simply mod n. In
FriCAS, you use IntegerMod to do such arithmetic.
(a , b ) : IntegerMod 12
(a , b ) := (16 , 7)
7 (2)
IntegerMod(12)
[a - b, a * b]
[9, 4] (3)
List (IntegerMod(12))
Perhaps you should use " @ " to indicate the required return type , or " $ " to
specify which version of the function you need .
recip a
"failed" (4)
Here 7 and 12 are relatively prime, so 7 has a multiplicative inverse modulo 12.
recip b
7 (5)
8.11. FINITE FIELDS 305
Union(IntegerMod(12), ...)
If we take n to be a prime number p, then taking inverses and, therefore, division are generally defined.
Use PrimeField instead of IntegerMod for n prime.
c : PrimeField 11 := 8
8 (6)
PrimeField(11)
inv c
7 (7)
PrimeField(11)
You can also use 1/c and c^(-1) for the inverse of c.
9/ c
8 (8)
PrimeField(11)
PrimeField (abbreviation 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), InnerPrimeField (abbreviation
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 PrimeField 2 and its extensions.
In the following examples, we work with the finite field with p = 101 elements.
GF101 := PF 101
PrimeField(101) (9)
Type
Like many domains in FriCAS, finite fields provide an operation for returning a random element of the
domain.
x := random () $ GF101
9 (10)
PrimeField(101)
y : GF101 := 37
37 (11)
PrimeField(101)
z := x / y
306 CHAPTER 8. ADVANCED PROBLEM SOLVING
33 (12)
PrimeField(101)
z * y - x
0 (13)
PrimeField(101)
2 (14)
PrimeField(101)
[1, 2, 4, 8, 16, 32, 64, 27, 54, 7, 14, 28, 56, 11, 22, 44, 88, 75, 49, 98, 95, 89, 77, 53, 5, 10,
20, 40, 80, 59, 17, 34, 68, 35, 70, 39, 78, 55, 9, 18, 36, 72, 43, 86, 71, 41, 82, 63, 25, 50, 100, (15)
99, 97, 93, 85, 69, 37, 74, 47, 94, 87, 73, 45, 90, 79, 57, 13, 26, 52, 3, 6, 12, 24, 48, 96, 91,
81, 61, 21, 42, 84, 67, 33, 66, 31, 62, 23, 46, 92, 83, 65, 29, 58, 15, 30, 60, 19, 38, 76, 51]
List (PrimeField(101))
If every nonzero element is a power of a primitive element, how do you determine what the exponent
is? Use discreteLog.
ex := discreteLog ( y )
56 (16)
PositiveInteger
pe ^ ex
37 (17)
PrimeField(101)
25 (18)
PositiveInteger
order pe
100 (19)
PositiveInteger
When you want to work with an extension of a finite field in FriCAS, you have three choices to make:
1. Do you want to generate an extension of the prime field (for example, PrimeField 2) or an
extension of a given field?
2. 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 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.
3. 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?
This illustrates one of the most important features of FriCAS: you can choose exactly the right data-
type and representation to suit your application best.
We first tell you what domain constructors to use for each case above, and then give some examples.
Constructors that automatically generate extensions of the prime field:
FiniteField
FiniteFieldCyclicGroup
FiniteFieldNormalBasis
Constructors that generate extensions of an arbitrary field:
FiniteFieldExtension
FiniteFieldExtensionByPolynomial
FiniteFieldCyclicGroupExtension
FiniteFieldCyclicGroupExtensionByPolynomial
FiniteFieldNormalBasisExtension
FiniteFieldNormalBasisExtensionByPolynomial
Constructors that use a cyclic group representation:
FiniteFieldCyclicGroup
FiniteFieldCyclicGroupExtension
FiniteFieldCyclicGroupExtensionByPolynomial
Constructors that use a normal basis representation:
FiniteFieldNormalBasis
FiniteFieldNormalBasisExtension
FiniteFieldNormalBasisExtensionByPolynomial
308 CHAPTER 8. ADVANCED PROBLEM SOLVING
All finite field extension constructors discussed in this section use a representation that performs arith-
metic with univariate (one-variable) polynomials modulo an irreducible polynomial. This polynomial
may be given explicitly by you or automatically generated. The ground field may be the prime field or
one you specify. See Section 8.11.2 on page 307 for general information about finite field extensions.
For FiniteField (abbreviation FF) you provide a prime number p and an extension degree n. This
degree can be 1. FriCAS uses the prime field PrimeField(p), here PrimeField 2, and it chooses
an irreducible polynomial of degree n, here 12, over the ground field.
GF4096 := FF (2 ,12) ;
Type
The objects in the generated field extension are polynomials of degree at most n − 1 with coefficients
in the prime field. The polynomial indeterminate is automatically chosen by FriCAS 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 operation index enumerates the elements of the field extension and accepts as argument the integers
from 1 to pn . The expression index(p) always gives the indeterminate.
a := index (2) $ GF4096
2 For more information on the implementation aspects of finite fields, see J. Grabmeier, A. Scheerhorn, Finite Fields
%JR (2)
b ^ 1000
c := a / b
1 (6)
PrimeField(2)
trace c
0 (7)
PrimeField(2)
Since any nonzero element is a power of a primitive element, how do we discover what the exponent
is? The operation discreteLog calculates the exponent and, if it is called with only one argument,
always refers to the primitive element returned by primitiveElement.
dL := discreteLog a
1729 (8)
PositiveInteger
g ^ dL
g 1729 (9)
310 CHAPTER 8. ADVANCED PROBLEM SOLVING
Polynomial( Integer )
r := ( random () $ GF4096 ) ^ 20
norm ( r )
FiniteField (2, 4)
For 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.
GF4096 := FFP ( GF4 , f ) ;
Type
3438 (17)
PositiveInteger
In every finite field there exist elements whose powers are all the nonzero elements of the field. Such
an element is called a primitive element.
8.11. FINITE FIELDS 311
In FiniteFieldCyclicGroup (abbreviation FFCG) the nonzero elements are represented by the pow-
ers of a fixed primitive element of the field (that is, a generator of its cyclic multiplicative group). Mul-
tiplication (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 Section 8.11.7 on page 317 for examples of how to compute such a polynomial.
To use FiniteFieldCyclicGroup you provide a prime number and an extension degree.
GF81 := FFCG (3 ,4) ;
Type
FriCAS uses the prime field, here PrimeField 3, as the ground field and it chooses a primitive
polynomial of degree n, here 4, over the prime field.
a := p r im i t i v e E l e m e n t () $ GF81
%JW 1 (2)
FiniteFieldCyclicGroup (3, 4)
%JW 72 (3)
FiniteFieldCyclicGroup (3, 4)
In this representation of finite fields the discrete logarithm of an element can be seen directly in its
output form.
b
%JW 72 (4)
FiniteFieldCyclicGroup (3, 4)
discreteLog b
72 (5)
PositiveInteger
r := ( random () $ GF729 ) ^ 20
312 CHAPTER 8. ADVANCED PROBLEM SOLVING
trace ( r )
2 (9)
FiniteField (3, 2)
We use a utility operation to generate an irreducible primitive polynomial (see Section 8.11.7 on page
317). The polynomial has one variable that is “anonymous”: it displays as a question mark.
f := c r e a t e P r i m i t i v e P o l y (4) $ FFPOLY ( GF3 )
?4 + ? + 2 (11)
SparseUnivariatePolynomial (PrimeField(3))
%JW 67 (13)
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 normal over F if the elements
2 n−1
1, xq , xq , . . . , xq
form a basis of K as a vector space over F . Such a basis is called a normal basis.3
If x is normal over F , its minimal polynomial is also said to be normal over F . There exist normal
bases for all finite extensions of arbitrary finite fields.
3 This agrees with the general definition of a normal basis because the n distinct powers of the automorphism x 7→ xq
In FiniteFieldNormalBasis (abbreviation 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.
K := FFNB (3 ,8)
FiniteFieldNormalBasis(3, 8) (1)
Type
FriCAS uses the prime field PrimeField(p), here 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 FriCAS and is typically
something like %A or %D. These (strange) variables are only for output display; there are several ways
i
to construct elements of this field. The output of the basis elements is something like %Aq .
a := normalElement () $ K
%JZ (2)
FiniteFieldNormalBasis (3, 8)
7 5
2 %JZ q + %JZ q + %JZ q (3)
FiniteFieldNormalBasis (3, 8)
r := random () $ GF729
r + r ^3 + r ^9 + r ^27
2
2 %KA %KB q + (2 %KAq + %KA) %KB q + (2 %KAq + %KA) %KB (7)
We use a utility operation to generate an irreducible normal polynomial (see Section 8.11.7 on page
317). The polynomial has one variable that is “anonymous”: it displays as a question mark.
f := c r ea t e N o r m a l P o l y (4) $ FFPOLY ( GF3 )
?4 + 2 ?3 + 2 (9)
SparseUnivariatePolynomial (PrimeField(3))
2
2 %KC q + 2 %KC q + %KC (11)
FiniteFieldNormalBasisExtensionByPolynomial(PrimeField(3) , ?ˆ4+2*?ˆ3+2)
r * r ^3 * r ^9 * r ^27
3 2
%KC q + %KC q + %KC q + %KC (12)
FiniteFieldNormalBasisExtensionByPolynomial(PrimeField(3) , ?ˆ4+2*?ˆ3+2)
norm r
1 (13)
PrimeField(3)
PrimeField(3) (1)
Type
Kn
|
Km ⇐⇒ m|n
|
K
8 (2)
PositiveInteger
FiniteFieldExtension(PrimeField(3), 4) (3)
Type
FiniteFieldExtension(PrimeField(3), 8) (4)
Type
a1 := random () $ Km
2 %KD2 (5)
FiniteFieldExtension (PrimeField(3) , 4)
b1 := random () $ Km
FiniteFieldExtension (PrimeField(3) , 4)
FiniteFieldExtension (PrimeField(3) , 8)
%KE 4 (8)
FiniteFieldExtension (PrimeField(3) , 8)
0 (9)
FiniteFieldExtension (PrimeField(3) , 4)
a1 * b1 - (( a2 * b2 ) :: Km )
0 (10)
FiniteFieldExtension (PrimeField(3) , 4)
There are also conversions available for the situation, when Km and Kn are represented in different
ways (see Section 8.11.2 on page 307). For example let’s choose Km where the representation is 0 plus
the cyclic multiplicative group and Kn with a normal basis representation.
Km := FFCGX (K , m )
FiniteFieldCyclicGroupExtension(PrimeField(3), 4) (11)
Type
Kn := FFNBX (K , n )
FiniteFieldNormalBasisExtension(PrimeField(3), 8) (12)
Type
( a1 , b1 ) := ( random () $ Km , random () $ Km )
%JW 72 (13)
FiniteFieldCyclicGroupExtension (PrimeField(3) , 4)
a2 := a1 :: Kn
6 5 4 2
%KF q + %KF q + 2 %KF q + %KF q + %KF q + 2 %KF (14)
FiniteFieldNormalBasisExtension (PrimeField(3) , 8)
b2 := b1 :: Kn
6 5 4 2
2 %KF q + %KF q + %KF q + 2 %KF q + %KF q + %KF (15)
FiniteFieldNormalBasisExtension (PrimeField(3) , 8)
a1 + b1 - (( a2 + b2 ) :: Km )
0 (16)
FiniteFieldCyclicGroupExtension (PrimeField(3) , 4)
a1 * b1 - (( a2 * b2 ) :: Km )
0 (17)
FiniteFieldCyclicGroupExtension (PrimeField(3) , 4)
A polynomial is primitive if its roots are primitive elements in an extension of the coefficient field
of degree equal to the degree of the polynomial.
A polynomial is normal over its coefficient field if its roots are linearly independent elements in
an extension of the coefficient field of degree equal to the degree of the polynomial.
In what follows, many of the generated polynomials have one “anonymous” variable. This indetermi-
nate is displayed as a question mark (“?”).
To fix ideas, let’s use the field with five elements for the first few examples.
GF5 := PF 5;
Type
You can generate irreducible polynomials of any (positive) degree (within the storage capabilities of
the computer and your ability to wait) by using createIrreduciblePoly.
f := c r e a t e I r r e d u c i b l e P o l y (8) $ FFPOLY ( GF5 )
?8 + ?4 + 2 (2)
SparseUnivariatePolynomial (PrimeField(5))
Does this polynomial have other important properties? Use primitive? to test whether it is a primitive
polynomial.
primitive ?( f ) $ FFPOLY ( GF5 )
false (3)
Boolean
false (4)
Boolean
Note that this is actually a trivial case, because a normal polynomial of degree n must have a nonzero
term of degree n − 1. We will refer back to this later.
To get a primitive polynomial of degree 8 just issue this.
p := c r e a t e P r i m i t i v e P o l y (8) $ FFPOLY ( GF5 )
?8 + ?3 + ?2 + ? + 2 (5)
SparseUnivariatePolynomial (PrimeField(5))
true (6)
Boolean
false (7)
Boolean
?8 + 4 ?7 + ?3 + 1 (8)
SparseUnivariatePolynomial (PrimeField(5))
false (9)
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.4
What about polynomials that are both primitive and normal? The existence of such a polynomial is
by no means obvious. 5 If you really need one use either createPrimitiveNormalPoly or createNormal-
PrimitivePoly.
c r e a t e P r i m i t i v e N o r m a l P o l y (8) $ FFPOLY ( GF5 )
4 Cf.Lidl, R. & Niederreiter, H., Finite Fields, Encycl. of Math. 20, (Addison-Wesley, 1983), p.90, Th. 3.18.
5 The existence of such polynomials is proved in Lenstra, H. W. & Schoof, R. J., Primitive Normal Bases for Finite
Fields, Math. Comp. 48, 1987, pp. 217-231.
8.11. FINITE FIELDS 319
?8 + 4 ?7 + 2 ?5 + 2 (10)
SparseUnivariatePolynomial (PrimeField(5))
If you want to obtain additional polynomials of the various types above as given by the create...
operations above, you can use the next... operations. For instance, nextIrreduciblePoly 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.
GF5 := PF 5;
Type
Our first example irreducible polynomial, say of degree 3, must be “greater” than this.
h := monomial (1 ,8) $ SUP ( GF5 )
?8 (12)
SparseUnivariatePolynomial (PrimeField(5))
?8 + 2 (13)
Union(SparseUnivariatePolynomial(PrimeField(5)) , ...)
Notice that this polynomial is not the same as the one createIrreduciblePoly.
c r e a t e I r r e d u c i b l e P o l y (3) $ FFPOLY ( GF5 )
?3 + ? + 1 (14)
SparseUnivariatePolynomial (PrimeField(5))
You can step through all irreducible polynomials of degree 8 over the field with 5 elements by repeatedly
issuing this.
nh := n e x t Ir r e d u c i b l e P o l y ( nh ) $ FFPOLY ( GF5 )
?8 + 3 (15)
Union(SparseUnivariatePolynomial(PrimeField(5)) , ...)
624 (16)
320 CHAPTER 8. ADVANCED PROBLEM SOLVING
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 (lexi-
cographically), and lastly their coefficients (also lexicographically, and using the operation 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 FiniteFieldPolynomialPackage also provides similar operations for primitive and nor-
mal polynomials. With the exception of the number of primitive normal polynomials; we’re not aware
of any known formula for this.
n u m b e r O f P r i m i t i v e P o l y (3) $ FFPOLY ( GF5 )
20 (17)
PositiveInteger
Take these,
m := monomial (1 ,1) $ SUP ( GF5 )
? (18)
SparseUnivariatePolynomial (PrimeField(5))
f := m ^3 + 4* m ^2 + m + 2
?3 + 4 ?2 + ? + 2 (19)
SparseUnivariatePolynomial (PrimeField(5))
?3 + 4 ?2 + 4 ? + 2 (20)
Union(SparseUnivariatePolynomial(PrimeField(5)) , ...)
What happened?
n e x t P r i m i t i v e P o l y ( f1 ) $ FFPOLY ( GF5 )
?3 + 3 ? + 3 (21)
Union(SparseUnivariatePolynomial(PrimeField(5)) , ...)
Well, for the ordering used in nextPrimitivePoly we use as first criterion a comparison of the constant
terms of the polynomials. Analogously, in nextNormalPoly we first compare the monomials of degree 1
less than the degree of the polynomials (which is nonzero, by an earlier remark).
f := m ^3 + m ^2 + 4* m + 1
8.11. FINITE FIELDS 321
?3 + ?2 + 4 ? + 1 (22)
SparseUnivariatePolynomial (PrimeField(5))
?3 + ?2 + 4 ? + 3 (23)
Union(SparseUnivariatePolynomial(PrimeField(5)) , ...)
?3 + 2 ?2 + 1 (24)
Union(SparseUnivariatePolynomial(PrimeField(5)) , ...)
We don’t have to restrict ourselves to prime fields. Let’s consider, say, a field with 16 elements.
GF16 := FFX ( FFX ( PF 2 ,2) ,2) ;
Type
?5 + ? + %JU (26)
FriCAS also provides operations for producing random polynomials of a given degree
random (5) $ FFPOLY ( GF16 )
Type
Type
?6 + ? + 1 (31)
SparseUnivariatePolynomial (PrimeField(2))
We compute a root of f.
root := r o o t O f I r r e d u c i b l e P o l y ( f ) $ FFPOLY2 (F , GF2 )
1. the problem is solved for 0-dimensional ideals by “generic” projection on the last coordinate
2. a “reduction process” uses localization and ideal quotients to reduce the general case to the
0-dimensional one.
The FriCAS constructor PolynomialIdeal represents ideals with coefficients in any field and supports
the basic ideal operations, including intersection, sum and quotient. 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
x2 +y 2 −1 (which defines a circle in the (x,y)-plane) and the ideal generated by x2 −y 2 (corresponding
to the straight lines x = y and x = -y.
(n , m ) : List DMP ([ x , y ] , FRAC INT )
m := [ x ^2+ y ^2 -1]
x2 + y 2 − 1
(2)
8.12. PRIMARY DECOMPOSITION OF IDEALS 323
n := [ x ^2 - y ^2]
2
x − y2
(3)
We find the equations defining the intersection of the two loci. This correspond to the sum of the
associated ideals.
id := ideal m + ideal n
1 2 1
x2 − , y − (4)
2 2
We can check if the locus contains only a finite number of points, that is, if the ideal is zero-dimensional.
zeroDim ? id
true (5)
Boolean
zeroDim ?( ideal m )
false (6)
Boolean
dimension ideal m
1 (7)
PositiveInteger
We can find polynomial relations among the generators (f and g are the parametric equations of the
knot).
(f , g ) : DMP ([ x , y ] , FRAC INT )
f := x ^2 -1
x2 − 1 (9)
g := x *( x ^2 -1)
x3 − x (10)
324 CHAPTER 8. ADVANCED PROBLEM SOLVING
rela tionsIde al [f , g ]
x2 + 2 y 2 , x z 2 − y z, z 2 − 4
(12)
ld := primaryDecomp ( ideal l ) $ I d e a l D e c o m p o s i t i o n P a c k a g e ([ x ,y , z ])
1 1
x+ y, y 2 , z + 2 , x − y, y 2 , z − 2 (13)
2 2
1 2 2
x − y z, y , z − 4 (14)
4
x, y, z 2 − 4
(15)
x, y, z 2 − 4
(16)
x5 − 5 x + 12 (1)
Polynomial( Integer )
We would like to construct a polynomial f (x) such that the 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 Q(a, b) is equal to Q(a + kb) for an appropriately chosen integer k. In our case, we construct
the minimal polynomial of ai − aj , where ai and aj are two roots of p(x). We construct this polynomial
using resultant. The main result we need is the following: If f (x) is a polynomial with roots ai . . . am and
g(x) is a polynomial with roots bi . . . bn , then the polynomial h(x) = resultant(f(y), g(x-y), y)
is a polynomial of degree m ∗ n with roots ai + bj , i = 1 . . . m, j = 1 . . . n.
For f (x) we use the polynomial p(x). For g(x) we use the polynomial −p(−x). Thus, the polynomial
we first construct is resultant(p(y), -p(y-x), y).
q := resultant ( eval (p ,x , y ) ,- eval (p ,x ,y - x ) ,y )
x25 − 50 x21 − 2375 x17 + 90000 x15 − 5000 x13 + 2700000 x11 + 250000 x9 + 18000000 x7 + 64000000 x5 (2)
Polynomial( Integer )
The roots of q(x) are ai − aj , i ≤ 1, j ≤ 5. Of course, there are five pairs (i, j) with i = j, so 0 is a
5-fold root of q(x). Let’s get rid of this factor.
q1 := exquo (q , x ^5)
x20 − 50 x16 − 2375 x12 + 90000 x10 − 5000 x8 + 2700000 x6 + 250000 x4 + 18000000 x2 + 64000000 (3)
Union(Polynomial(Integer) , ...)
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.6 Note that the type of factoredQ is FR POLY INT, that is, Factored Polynomial Integer.
6 See McKay, Soicher, Computing Galois Groups over the Rationals, Journal of Number Theory 20, 273-281 (1983).
We do not assume the results of this paper, however, and we continue with the computation.
326 CHAPTER 8. ADVANCED PROBLEM SOLVING
This is a special data type for recording factorizations of polynomials with integer coefficients (see
‘Factored’ on page 405). We can access the individual factors using the operation factorList.
r := factorList ( factoredQ ) .1. factor
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.)
beta : AN := rootOf ( eval (r ,x , b ) )
b (6)
AlgebraicNumber
We next tell FriCAS to view p(x) as a univariate polynomial in x with algebraic number coefficients.
This is accomplished with this type declaration.
p := p :: UP (x , INT ) :: UP (x , AN )
x5 − 5 x + 12 (7)
Factor p(x) over the field Q(β). (This computation will take some time!)
algFactors := factor (p ,[ beta ])
x
−85 b9 − 116 b8 + 780 b7 + 2640 b6 + 14895 b5 − 8820 b4 − 127050 b3 − 327000 b2 − 405200 b + 2062400
+ x
1339200
143 b8 − 2100 b6 − 10485 b4 + 290550 b2 + 334800 b − 960800
+ x
669600
143 b8 − 2100 b6 − 10485 b4 + 290550 b2 − 334800 b − 960800
+ x
669600
−17 b8 + 156 b6 + 2979 b4 − 25410 b2 − 14080
+ x
66960
85 b9 − 116 b8 − 780 b7 + 2640 b6 − 14895 b5 − 8820 b4 + 127050 b3 − 327000 b2 + 405200 b + 2062400
+
1339200
(8)
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 factor, the field over which the polynomial is factored is the field generated by
8.13. COMPUTATION OF GALOIS GROUPS 327
1. the algebraic numbers that appear in the coefficients of the polynomial, and
2. the algebraic numbers that appear in a list passed as an optional second argument of the opera-
tion.
In our case, the coefficients of p are all rational integers and only beta appears in the list, so the field
is simply Q(β). 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.
factor ( p )
x5 − 5 x + 12 (9)
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 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 variables. We can obtain an individual root by
negating the constant coefficient of one of the factors of p(x).
factor1 := factorList ( algFactors ) .1. factor
−85 b9 − 116 b8 + 780 b7 + 2640 b6 + 14895 b5 − 8820 b4 − 127050 b3 − 327000 b2 − 405200 b + 2062400
x+
1339200
(10)
List (AlgebraicNumber)
The expression
- coefficient(j.factor, 0)}
is the ith root of p(x) and the elements of roots are the ith roots of p(x) as i ranges from 1 to 5.
Assign the roots as the values of the variables a1,...,a5.
( a1 , a2 , a3 , a4 , a5 ) := ( roots .1 , roots .2 , roots .3 , roots .4 , roots .5)
−85 b9 + 116 b8 + 780 b7 − 2640 b6 + 14895 b5 + 8820 b4 − 127050 b3 + 327000 b2 − 405200 b − 2062400
(13)
1339200
AlgebraicNumber
Next we express the roots of r(x) as polynomials in beta. We could obtain these roots by calling the
operation factor: factor(r, [beta]) factors r(x) over Q(β). 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 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).
eval (r ,x , a1 - a2 )
0 (14)
Polynomial(AlgebraicNumber)
eval (r ,x , a1 - a3 )
47905 b9 + 66920 b8 − 536100 b7 − 980400 b6 − 3345075 b5 − 5787000 b4 + 75572250 b3 + 161688000 b2 − 184600000 b − 710912000
(15)
4464
Polynomial(AlgebraicNumber)
eval (r ,x , a1 - a4 )
0 (16)
Polynomial(AlgebraicNumber)
eval (r ,x , a1 - a5 )
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.
8.13. COMPUTATION OF GALOIS GROUPS 329
bb := a1 - a4
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:
aa1 := subst ( a1 , beta = bb )
−85 b9 + 116 b8 + 780 b7 − 2640 b6 + 14895 b5 + 8820 b4 − 127050 b3 + 327000 b2 − 405200 b − 2062400
(19)
1339200
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).
( aa1 = a1 ) :: Boolean
false (24)
330 CHAPTER 8. ADVANCED PROBLEM SOLVING
Boolean
( aa1 = a2 ) :: Boolean
false (25)
Boolean
( aa1 = a3 ) :: Boolean
false (26)
Boolean
( aa1 = a4 ) :: Boolean
false (27)
Boolean
( aa1 = a5 ) :: Boolean
true (28)
Boolean
7
Proceeding in this fashion, you can find the values of aa2,...aa5. You have represented the au-
tomorphism 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:
1. Show that the Galois group of p(x) = x4 + 2x3 − 2x2 − 3x + 1 is the dihedral group of order √ eight.
(The splitting field of this polynomial is the Hilbert class field of the quadratic field Q( 145).)
2. Show that the Galois group of p(x) = x6 +108 has order 6 and is isomorphic to S3 , the symmetric
group on three letters. (The splitting field of this polynomial is the splitting field of x3 − 2.)
The segregation rates γi,j are the structural constants of an n-dimensional algebra. This is provided
in FriCAS by the constructor AlgebraGivenByStructuralConstants (abbreviation ALGSC).
Consider two coupled autosomal loci with alleles A,a, B, and b, building four different gametes a1 =
AB, a2 = Ab, a3 = aB, and a4 = ab. The zygotes ai aj produce gametes ai and aj with classical
Mendelian segregation. Zygote a1 a4 undergoes transition to a2 a3 and vice versa with probability
0 ≤ θ ≤ 12 .
k
Define a list [(γi,j )1 ≤ k ≤ 4] of four four-by-four matrices giving the segregation rates. We use the
value 1/10 for θ.
s e g r e g a t i o n R a t es : 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] ] ]
1 1 9 1 1 1 1 9
1 2 2 20
0 2
0 20
0 0 2 20
0 0 0 20
1 0 1
0 1
1 9 1
0 0 9
0 0 0 1 1
12 1
20 , 2
9
20 2 ,
1 9
20
1 ,
1
20 2
1 (1)
2 20
0 0 0 20
0 0 2 20
1 2
0
20
0 2
9 1 1 1 1 9 1 1
20
0 0 0 20 2
0 0 20
0 2
0 20 2 2
1
9 The interested reader can learn more about these aspects of the FriCAS library from the paper “Computations in
Algebras of Finite Rank,” by Johannes Grabmeier and Robert Wisbauer, Technical Report, IBM Heidelberg Scientific
Center, 1992.
10 Wörz-Busekros, A., Algebras in Genetics, Springer Lectures Notes in Biomathematics 36, Berlin e.a. (1980). In
What are the probabilities for zygote a1 a4 to produce the different gametes?
a := basis () $ A ; a .1* a .4
9 1 1 9
ab + aB + Ab + AB (4)
20 20 20 20
AlgebraGivenByStructuralConstants(Fraction ( Integer ) , 4, [AB, Ab, aB, ab], [[[1, 1/2, 1/2, 9/20], [1/2, 0, 1/20, 0],
[1/2, 1/20, 0, 0], [9/20, 0, 0, 0]], [[0, 1/2, 0, 1/20], [1/2, 1, 9/20, 1/2], [0, 9/20, 0, 0], [1/20, 1/2, 0, 0]],
[[0, 0, 1/2, 1/20], [0, 0, 9/20, 0], [1/2, 9/20, 1, 1/2], [1/20, 0, 1/2, 0]], [[0, 0, 0, 9/20], [0, 0, 1/20, 1/2],
[0, 1/20, 0, 1/2], [9/20, 1/2, 1/2, 1]]])
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 sex-dependent, as in our example.
commutative ?() $ A
true (5)
Boolean
false (6)
Boolean
), CONCAT(0, ., 5)], [0, CONCAT(0, ., CONCAT(0, 5)), 0, CONCAT(0, ., 5)], [CONCAT(0, ., CONCAT(4, 5)), CONCAT
(0, ., 5), CONCAT(0, ., 5), 1]]])
To compute directly the gametic distribution in the fifth generation, we use plenaryPower.
plenaryPower (x ,5)
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.
q := l e f t R a n k P o l y n o m i a l () $ GCNAALG ( FRAC INT , 4 , gametes , s e g r e g a t i o n R a t e s ) :: UP (Y ,
POLY FRAC INT )
3 29 29 29 29
Y + − %x4 − %x3 − %x2 − %x1 Y 2
20 20 20 20
9
9 9 9
9 (9)
+ %x42 + %x3 + %x2 + %x1 %x4 + %x32
20 10 10 10 20
9 9 9 9 9
+ %x2 + %x1 %x3 + %x22 + %x1 %x2 + %x12 Y
10 10 20 10 20
9
Because the coefficient 20 has absolute value less than 1, all distributions do converge, by a theorem
of this theory.
factor ( q :: POLY FRAC INT )
9 9 9 9
(Y − %x4 − %x3 − %x2 − %x1) Y − %x4 − %x3 − %x2 − %x1 Y (10)
20 20 20 20
9 1
%x1 %x4 + %x2 + %x1 %x3 + %x1 %x2 + %x12 − %x1,
10 10
1 9
%x2 + %x1 %x4 + %x2 %x3 + %x22 + (%x1 − 1) %x2, (11)
10 10
1 2 9
%x3 + %x1 %x4 + %x3 + %x2 + %x1 − 1 %x3,
10 10
9 1
%x42 + %x3 + %x2 + %x1 − 1 %x4 + %x2 %x3
10 10
%x4 + %x3 + %x2 + %x1 − 1, (%x2 + %x1) %x3 + %x1 %x2 + %x12 − %x1
(12)
Further analysis using the package PolynomialIdeal shows that there is a two-dimensional variety of
equilibrium states and all other solutions are contained in it.
Choose one equilibrium state by setting two indeterminates to concrete values.
sol := solve concat ( gbs .1 ,[% x1 -1/10 ,% x2 -1/10])
2 2 1 1
%x4 = , %x3 = , %x2 = , %x1 = (13)
5 5 10 10
2 2 1 1
ab + aB + Ab + AB (14)
5 5 10 10
AlgebraGivenByStructuralConstants(Fraction ( Integer ) , 4, [AB, Ab, aB, ab], [[[1, 1/2, 1/2, 9/20], [1/2, 0, 1/20, 0],
[1/2, 1/20, 0, 0], [9/20, 0, 0, 0]], [[0, 1/2, 0, 1/20], [1/2, 1, 9/20, 1/2], [0, 9/20, 0, 0], [1/20, 1/2, 0, 0]],
[[0, 0, 1/2, 1/20], [0, 0, 9/20, 0], [1/2, 9/20, 1, 1/2], [1/20, 0, 1/2, 0]], [[0, 0, 0, 9/20], [0, 0, 1/20, 1/2],
[0, 1/20, 0, 1/2], [9/20, 1/2, 1/2, 1]]])
0 (15)
AlgebraGivenByStructuralConstants(Fraction ( Integer ) , 4, [AB, Ab, aB, ab], [[[1, 1/2, 1/2, 9/20], [1/2, 0, 1/20, 0],
[1/2, 1/20, 0, 0], [9/20, 0, 0, 0]], [[0, 1/2, 0, 1/20], [1/2, 1, 9/20, 1/2], [0, 9/20, 0, 0], [1/20, 1/2, 0, 0]],
[[0, 0, 1/2, 1/20], [0, 0, 9/20, 0], [1/2, 9/20, 1, 1/2], [1/20, 0, 1/2, 0]], [[0, 0, 0, 9/20], [0, 0, 1/20, 1/2],
[0, 1/20, 0, 1/2], [9/20, 1/2, 1/2, 1]]])
8.15. MATRIX MANIPULATION 335
11 12 13 14
21 22 23 24 (1)
31 32 33 34
Matrix( Integer )
Select the top right two by two submatrix by slicing using segments:
m (1..2 , 3..4)
13 14
(2)
23 24
Matrix( Integer )
11 13
(3)
21 23
Matrix( Integer )
Indexing by lists works as expected, returning all elements having index pairs from the outer product
of both lists:
m ([1 ,3] , [2 ,4])
12 14
(4)
32 34
Matrix( Integer )
Selecting single elements by any index type other than Integer for both, the row and column index,
will not give the respective element but a 1 times 1 matrix containing it:
m (1 , 2)
12 (5)
336 CHAPTER 8. ADVANCED PROBLEM SOLVING
PositiveInteger
m ([1] , [2])
12 (6)
Matrix( Integer )
m (1 , [2])
12 (7)
Matrix( Integer )
m (1 , 2..2)
12 (8)
Matrix( Integer )
m (1 , [2..2])
12 (9)
Matrix( Integer )
It is possible to use lists of segments to select multiple submatrices which get stacked together forming
the result returned:
m ([1..2] , [1 , 3..4])
11 13 14
(10)
21 23 24
Matrix( Integer )
13 14 13 14
(11)
23 24 23 24
Matrix( Integer )
It is even possible to mix any of the valid index constructs in the selection of rows and columns:
m (2 , [1 ,4])
21 24 (12)
Matrix( Integer )
12 13
22 23 (13)
32 33
Matrix( Integer )
11 12 13 14
(14)
21 22 23 24
Matrix( Integer )
12
(15)
22
Matrix( Integer )
11 12 12 14
21 22 22 24 (16)
31 32 33 34
Matrix( Integer )
Note that assignment currently does not check for overlapping segments, and the last assignments
wins. However, overlapping case should be considered undefined anyway.
Another caveat shows up when assigning single elements.
Selecting the entry by any index type other than two times an Integer requires assignment of a matrix
type:
m ([2] , [2]) := matrix ([[4]])
4 (17)
Matrix( Integer )
11 12 12 14
21 4 22 24 (18)
31 32 33 34
Matrix( Integer )
By using the functions rowSlice and colSlice it is possible to obtain for a given matrix two special slicing
objects that when used will select all elements along a column or row respectively (rowSlice varies row
338 CHAPTER 8. ADVANCED PROBLEM SOLVING
index giving a column). The advantage of using these is that no information about the actual matrix
size in necessary.
It is easily possible to select the second and fourth columns of a given matrix:
r := rowSlice ( m )
1..3 (19)
Segment(Integer)
m (r , 2)
12
4 (20)
32
Matrix( Integer )
m (r , 4)
14
24 (21)
34
Matrix( Integer )
Assignment of course works the same way. The following snippet shows simple row operations as used
in Gaussian elimination:
c := colSlice ( m )
1..4 (22)
Segment(Integer)
11 12 12 14
21 4 22 24 (23)
31 32 33 34
Matrix(Fraction ( Integer ))
m (2 , c ) := m (2 , c ) - m (2 ,1) / m (1 ,1) * m (1 , c )
− 208 10
− 30
0 11
− 11 11
(24)
Matrix(Fraction ( Integer ))
m (3 , c ) := m (3 , c ) - m (3 ,1) / m (1 ,1) * m (1 , c )
− 20 9
− 60
0 11
− 11 11
(25)
8.15. MATRIX MANIPULATION 339
Matrix(Fraction ( Integer ))
m (3 , c ) := m (3 , c ) - m (3 ,2) / m (2 ,2) * m (2 , c )
19
− 135
0 0 − 26 26
(26)
Matrix(Fraction ( Integer ))
11 12 12 14
0 − 208
11
− 10
11
30
− 11 (27)
0 0 − 19
26
− 135
26
Matrix(Fraction ( Integer ))
1..3 (28)
Segment(Integer)
c := colSlice ( m )
1..4 (29)
Segment(Integer)
m (r , c )
11 12 12 14
0 − 208
11
− 10
11
30
− 11 (30)
0 0 − 19
26
− 135
26
Matrix(Fraction ( Integer ))
340 CHAPTER 8. ADVANCED PROBLEM SOLVING
Chapter 9
In this chapter we show examples of many of the most commonly used FriCAS domains and packages.
The sections are organized by constructor names.
9.1 AssociationList
The AssociationList constructor provides a general structure for associative storage. This type
provides association lists in which data objects can be saved according to keys of any type. For a
given association list, specific types must be chosen for the keys and entries. You can think of the
representation of an association list as a list of records with key and entry fields.
Association lists are a form of table and so most of the operations available for Table are also available
for AssociationList. They can also be viewed as lists and can be manipulated accordingly.
This is a Record type with age and gender fields.
Data := Record ( monthsOld : Integer , gender : String )
Type
In this expression, al is declared to be an association list whose keys are strings and whose entries are
the above records.
al : A s so ciat i on Li st ( String , Data )
table () (6)
341
342 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
You can use assignment syntax to add things to the association list.
al ." bob " := [407 ," male "] $ Data
Now look at what is in the association list. Note that the last-added (key, entry) pair is at the beginning
of the list.
al
Use delete! to destructively remove an element of the association list. Use delete to return a copy of the
association list with the element deleted. The second argument is the index of the element to delete.
delete !( al ,1)
9.2. BALANCEDBINARYTREE 343
For more information about tables, see ‘Table’ on page 589. For more information about lists, see
‘List’ on page 490. Issue the system command )show AssociationList to display the full list of
operations defined by AssociationList.
9.2 BalancedBinaryTree
BalancedBinaryTree(S) is the domain of balanced binary trees with elements of type S at the nodes.
A binary tree is either empty or else consists of a node having a value and two branches, each branch a
binary tree. A balanced binary tree is one that is balanced with respect its leaves. One with 2k leaves
is perfectly “balanced”: the tree has minimum depth, and the left and right branch of every interior
node is identical in shape.
Balanced binary trees are useful in algebraic computation for so-called “divide-and-conquer” algo-
rithms. Conceptually, the data for a problem is initially placed at the root of the tree. The original
data is then split into two subproblems, one for each subtree. And so on. Eventually, the problem is
solved at the leaves of the tree. A solution to the original problem is obtained by some mechanism
that can reassemble the pieces. In fact, an implementation of the Chinese Remainder Algorithm using
balanced binary trees was first proposed by David Y. Y. Yun at the IBM T. J. Watson Research Center
in Yorktown Heights, New York, in 1978. It served as the prototype for polymorphic algorithms in
FriCAS.
In what follows, rather than perform a series of computations with a single expression, the expression
is reduced modulo a number of integer primes, a computation is done with modular arithmetic for each
prime, and the Chinese Remainder Algorithm is used to obtain the answer to the original problem.
We illustrate this principle with the computation of 122 = 144.
A list of moduli.
lm := [3 ,5 ,7 ,11]
List ( PositiveInteger )
The expression modTree(n, lm) creates a balanced binary tree with leaf values n mod m for each
modulus m in lm.
modTree (12 , lm )
[0, 2, 5, 1] (5)
List ( Integer )
Operation modTree does this using operations on balanced binary trees. We trace its steps. Create a
balanced binary tree t of zeros with four leaves.
t := b a l a n c e d B i n a r y T r e e (# lm , 0)
344 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
BalancedBinaryTree(NonNegativeInteger)
BalancedBinaryTree(NonNegativeInteger)
Use mapUp! to do a bottom-up traversal of t, setting each interior node to the product of the values
at the nodes of its children.
mapUp !( t , _ *)
1155 (8)
PositiveInteger
The value at the node of every subtree is the product of the moduli of the leaves of the subtree.
t
BalancedBinaryTree(NonNegativeInteger)
BalancedBinaryTree(NonNegativeInteger)
The operation leaves returns the leaves of the resulting tree. In this case, it returns the list of 12 mod m
for each modulus m.
leaves %
[0, 2, 5, 1] (11)
List (NonNegativeInteger)
[0, 4, 4, 1] (12)
List (NonNegativeInteger)
Call the Chinese Remainder Algorithm to get the answer for 122 .
9.3. BASICOPERATOR 345
c h i n e s e R e m a i n d er (% , lm )
144 (13)
PositiveInteger
9.3 BasicOperator
A basic operator is an object that can be symbolically applied to a list of arguments from a set, the
result being a kernel over that set or an expression. In addition to this section, please see ‘Expression’
on page 400 and ‘Kernel’ on page 454 for additional information and examples.
You create an object of type BasicOperator by using the operator operation. This first form of this
operation has one argument and it must be a symbol. The symbol should be quoted in case the name
has been used as an identifier to which a value has been assigned.
A frequent application of BasicOperator is the creation of an operator to represent the unknown
function when solving a differential equation. Let y be the unknown function in terms of x.
y := operator ’y
y (4)
BasicOperator
Equation(Expression( Integer ))
√ √
x 3 x x x 3
particular = 0, basis = cos e− 2 , e− 2 sin (6)
2 2
Union(Record( particular : Expression ( Integer ) , basis : List ( Expression ( Integer ))) , ...)
See Section 8.10 on page 296 for this kind of use of BasicOperator.
Use the single argument form of operator (as above) when you intend to use the operator to create
functional expressions with an arbitrary number of arguments Nary means an arbitrary number of
arguments can be used in the functional expressions.
nary ? y
true (7)
346 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Boolean
unary ? y
false (8)
Boolean
Use the two-argument form when you want to restrict the number of arguments in the functional
expressions created with the operator. This operator can only be used to create functional expressions
with one argument.
opOne := operator ( ’ opOne , 1)
opOne (9)
BasicOperator
nary ? opOne
false (10)
Boolean
unary ? opOne
true (11)
Boolean
Use arity to learn the number of arguments that can be used. It returns "false" if the operator is
nary.
arity opOne
1 (12)
Union(NonNegativeInteger, ...)
opOne (13)
Symbol
false (14)
Boolean
true (15)
Boolean
You can attached named properties to an operator. These are rarely used at the top-level of the FriCAS
interactive environment but are used with FriCAS library source code. By default, an operator has
no properties.
properties y
table () (16)
The interface for setting and getting properties is somewhat awkward because the property values are
stored as values of type None. Attach a property by using setProperty.
setProperty (y , " use " , " unknown function " :: None )
y (17)
BasicOperator
properties y
String
y (20)
BasicOperator
properties y
table () (21)
9.4 BinaryExpansion
All rational numbers have repeating binary expansions. Operations to access the individual bits of a
binary expansion can be obtained by converting the value to RadixExpansion(2). More examples of
expansions are available in ‘DecimalExpansion’ on page 388, ‘HexadecimalExpansion’ on page 440,
and ‘RadixExpansion’ on page 542.
The expansion (of type BinaryExpansion) of a rational number is returned by the binary operation.
r := binary (22/7)
11.001 (4)
BinaryExpansion
Arithmetic is exact.
r + binary (6/7)
100 (5)
BinaryExpansion
0.000000101, 0.000000100111110001000101100101111001110010010101001, 0.000000100111011, (6)
0.000000100111, 0.00000010011010100100001110011111011001010110111100011
List (BinaryExpansion)
or very long.
binary (1/1007)
0.00000000010000010001010010010111100000111111000010111111001011000111110100010011100100110011000110010010101011110
(7)
BinaryExpansion
Polynomial(BinaryExpansion)
q := D (p , x )
Polynomial(BinaryExpansion)
g := gcd (p , q )
x + 1.01 (10)
Polynomial(BinaryExpansion)
9.5 BinarySearchTree
BinarySearchTree(R) is the domain of binary trees with elements of type R, ordered across the
nodes of the tree. A non-empty binary search tree has a value of type R, and right and left binary
search subtrees. If a subtree is empty, it is displayed as a period (“.”).
Define a list of values to be placed across the tree. The resulting tree has 8 at the root; all other
elements are in the left subtree.
lv := [8 ,3 ,5 ,4 ,6 ,2 ,1 ,5 ,7]
[8, 3, 5, 4, 6, 2, 1, 5, 7] (4)
List ( PositiveInteger )
A convenient way to create a binary search tree is to apply the operation binarySearchTree to a list of
elements.
t := b i na r y S e a r c h T r e e lv
BinarySearchTree( PositiveInteger )
[] (6)
BinarySearchTree( Integer )
Insert the value 8. This establishes 8 as the root of the binary search tree. Values inserted later that
are less than 8 get stored in the left subtree, others in the right subtree.
t1 := insert !(8 , emptybst )
8 (7)
BinarySearchTree( Integer )
Insert the value 3. This number becomes the root of the left subtree of t1. For optimal retrieval, it is
thus important to insert the middle elements first.
insert !(3 , t1 )
350 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
[3, 8, .] (8)
BinarySearchTree( Integer )
We go back to the original tree t. The leaves of the binary search tree are those which have empty left
and right subtrees.
leaves t
[1, 4, 5, 7] (9)
List ( PositiveInteger )
The operation split(k,t) returns a record containing the two subtrees: one with all elements “less”
than k, another with elements “greater” than k.
split (3 , t )
The new node puts the inserted value between its “less” tree and “greater” tree.
insertRoot (x , t ) ==
a := split (x , t )
node ( a . less , x , a . greater )
Function buildFromRoot builds a binary search tree from a list of elements ls and the empty tree
emptybst.
buildFromRoot ls == reduce ( insertRoot , ls , emptybst )
BinarySearchTree( Integer )
true (15)
9.6. CARDINALNUMBER 351
Boolean
9.6 CardinalNumber
The CardinalNumber domain can be used for values indicating the cardinality of sets, both finite
and infinite.
The non-negative integers have a natural construction as cardinals
The fact that 0 acts as a zero for the multiplication of cardinals is equivalent to the axiom of choice.
Cardinal numbers can be created by conversion from non-negative integers.
c0 := 0 :: Cardin alNumbe r
0 (4)
CardinalNumber
c1 := 1 :: Cardin alNumbe r
1 (5)
CardinalNumber
c2 := 2 :: Cardin alNumbe r
2 (6)
CardinalNumber
c3 := 3 :: Cardin alNumbe r
3 (7)
CardinalNumber
ℵ0 (8)
CardinalNumber
A1 := Aleph 1
ℵ1 (9)
352 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
CardinalNumber
The finite? operation tests whether a value is a finite cardinal, that is, a non-negative integer.
finite ? c2
true (10)
Boolean
finite ? A0
false (11)
Boolean
Similarly, the countable? operation determines whether a value is a countable cardinal, that is, finite
or Aleph(0).
countable ? c2
true (12)
Boolean
countable ? A0
true (13)
Boolean
countable ? A1
false (14)
Boolean
[4, ℵ1 ] (15)
List (CardinalNumber)
[ c0 * c2 , c1 * c2 , c2 * c2 , c0 * A1 , c1 * A1 , c2 * A1 , A0 * A1 ]
[0, 2, 4, 0, ℵ1 , ℵ1 , ℵ1 ] (16)
9.6. CARDINALNUMBER 353
List (CardinalNumber)
[ c2 ^ c0 , c2 ^ c1 , c2 ^ c2 , A1 ^ c0 , A1 ^ c1 , A1 ^ c2 ]
[1, 2, 4, 1, ℵ1 , ℵ1 ] (17)
List (CardinalNumber)
Subtraction is a partial operation: it is not defined when subtracting a larger cardinal from a smaller
one, nor when subtracting two equal infinite cardinals.
[ c2 - c1 , c2 - c2 , c2 - c3 , A1 - c2 , A1 - A0 , A1 - A1 ]
2^Aleph i = Aleph(i+1)
and is independent of the axioms of set theory.1 The CardinalNumber domain provides an
operation to assert whether the hypothesis is to be assumed.
g e n e r a l i z e d C o n t i n u u m H y p o t h e s i s A s s u m e d true
true (19)
Boolean
When the generalized continuum hypothesis is assumed, exponentiation to a transfinite power is al-
lowed.
[ c0 ^ A0 , c1 ^ A0 , c2 ^ A0 , A0 ^ A0 , A0 ^ A1 , A1 ^ A0 , A1 ^ A1 ]
[0, 1, ℵ1 , ℵ1 , ℵ2 , ℵ1 , ℵ2 ] (20)
List (CardinalNumber)
ℵ0 (21)
CardinalNumber
c := 2^ a
1 Goedel, The consistency of the continuum hypothesis, Ann. Math. Studies, Princeton Univ. Press, 1940.
354 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
ℵ1 (22)
CardinalNumber
f := 2^ c
ℵ2 (23)
CardinalNumber
9.7 CartesianTensor
CartesianTensor(i0,dim,R) provides Cartesian tensors with components belonging to a commuta-
tive ring R. Tensors can be described as a generalization of vectors and matrices. This gives a concise
tensor algebra for multilinear objects supported by the CartesianTensor domain. You can form the
inner or outer product of any two tensors and you can add or subtract tensors with the same number
of components. Additionally, various forms of traces and transpositions are useful.
The CartesianTensor constructor allows you to specify the minimum index for subscripting. In what
follows we discuss in detail how to manipulate tensors.
Here we construct the domain of Cartesian tensors of dimension 2 over the integers, with indices
starting at 1.
CT := CARTEN ( i0 := 1 , 2 , Integer )
Type
Forming tensors
8 (5)
rank t0
0 (6)
NonNegativeInteger
Vectors (mathematical direct products, rather than one dimensional array structures) can be converted
to tensors of rank one.
v : DirectProduct (2 , Integer ) := directProduct [3 ,4]
9.7. CARTESIANTENSOR 355
[3, 4] (7)
DirectProduct(2, Integer )
Tv : CT := v
[3, 4] (8)
1 2
(9)
4 5
SquareMatrix(2, Integer )
Tm : CT := m
1 2
(10)
4 5
2 3
(11)
0 1
SquareMatrix(2, Integer )
Tn : CT := n
2 3
(12)
0 1
In general, a tensor of rank k can be formed by making a list of rank k-1 tensors or, alternatively, a
k-deep nested list of lists.
t1 : CT := [2 , 3]
[2, 3] (13)
rank t1
1 (14)
356 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
PositiveInteger
t2 : CT := [ t1 , t1 ]
2 3
(15)
2 3
t3 : CT := [ t2 , t2 ]
2 3 2 3
, (16)
2 3 2 3
tt : CT := [ t3 , t3 ]; tt := [ tt , tt ]
2 3 2 3 2 3 2 3
2 3 2 3 2 3 2 3
, (17)
2 3 2 3 2 3 2 3
2 3 2 3 2 3 2 3
rank tt
5 (18)
PositiveInteger
Multiplication
Given two tensors of rank k1 and k2, the outer product forms a new tensor of rank k1+k2. Here
Tmn (i, j, k, l) = Tm (i, j) Tn (k, l).
Tmn := product ( Tm , Tn )
2 3 4 6
0 1
0 2 (19)
8 12 10 15
0 4 0 5
The inner product (contract) forms a tensor of rank k1+k2-2. This product generalizes the vector dot
product and matrix-vector product by summing component products along Pdimtwo indices. Here we
sum along the second index of Tm and the first index of Tv . Here Tmv = j=1 Tm (i, j) Tv (j)
Tmv := contract ( Tm ,2 , Tv ,1)
9.7. CARTESIANTENSOR 357
The multiplication operator * is scalar multiplication or an inner product depending on the ranks of
the arguments. If either argument is rank zero it is treated as scalar multiplication. Otherwise, a*b
is the inner product summing the last index of a with the first index of b.
Tm * Tv
This definition is consistent with the inner product on matrices and vectors.
Tmv = m * v
Selecting Components
For tensors of low rank (that is, four or less), components can be selected by applying the tensor to its
indices.
t0 ()
8 (23)
PositiveInteger
t1 (1+1)
3 (24)
PositiveInteger
t2 (2 ,1)
2 (25)
PositiveInteger
t3 (2 ,1 ,2)
3 (26)
PositiveInteger
Tmn (2 ,1 ,2 ,1)
358 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
0 (27)
NonNegativeInteger
8 (28)
PositiveInteger
t1 [2]
3 (29)
PositiveInteger
t2 [2 ,1]
2 (30)
PositiveInteger
The general mechanism works for tensors of arbitrary rank, but is somewhat less efficient since the
intermediate index list must be created.
t3 [2 ,1 ,2]
3 (31)
PositiveInteger
Tmn [2 ,1 ,2 ,1]
0 (32)
NonNegativeInteger
Contraction
A “contraction” between two tensors is an inner product, as we have seen above. You can also contract
a pair of indices of a single tensor. This corresponds to a “trace” in linear algebra. The expression
contract(t,k1,k2) forms a new tensor by Psumming the diagonal given by indices in position k1 and
dim
k2. This is the tensor given by xTmn = k=1 Tmn (k, k, i, j).
cTmn := contract ( Tmn ,1 ,2)
12 18
(33)
0 6
9.7. CARTESIANTENSOR 359
Since Tmn is the outer product of matrix m and matrix n, the above is equivalent to this.
trace ( m ) * n
12 18
(34)
0 6
SquareMatrix(2, Integer )
In this and the next few examples, we show all possible contractions of Tmn and their matrix algebra
equivalents.
contract ( Tmn ,1 ,2) = trace ( m ) * n
12 18 12 18
= (35)
0 6 0 6
2 7 2 7
= (36)
4 11 4 11
14 4 14 4
= (37)
19 5 19 5
2 5 2 5
= (38)
8 17 8 17
8 2 8 2
= (39)
23 5 23 5
3 6 3 6
= (40)
12 15 12 15
360 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Transpositions
You can exchange any desired pair of indices using the transpose operation.
Here the indices in positions one and three are exchanged, that is, tTmn (i, j, k, l) = Tmn (k, j, i, l).
tTmn := transpose ( Tmn ,1 ,3)
2 3 4 6
8 12 10 15
0 1
(41)
0 2
0 4 0 5
If no indices are specified, the first and last index are exchanged.
transpose Tmn
2 8 4 10
0 0
0 0
(42)
3 12 6 15
1 4 2 5
1 4 1 4
= (43)
2 5 2 5
If a more complicated reordering of the indices is required, then the reindex operation can be used. This
operation allows the indices to be arbitrarily permuted. This defines rTmn (i, j, k, l) = Tmn (i, l, j, k).
rTmn := reindex ( Tmn , [1 ,4 ,2 ,3])
2 0 3 1
4 0
6 2
8 0
(44)
12 4
10 0 15 5
Arithmetic
Tensors of equal rank can be added or subtracted so arithmetic expressions can be used to produce
new tensors.
9.7. CARTESIANTENSOR 361
tt := transpose ( Tm ) * Tn - Tn * transpose ( Tm )
−6 −16
(45)
2 6
Tv *( tt + Tn )
46 84 57 114
174 212 228 285
18
(47)
24 17 30
57 63 63 76
Specific Tensors
Two specific tensors have properties which depend only on the dimension.
The Kronecker delta satisfies
1 if i = j
delta(i, j) =
0 ̸ j
if i =
1 0
(48)
0 1
2 4 0 0 2 4 0 0
3 6 1 2 3 6
= 1 2 (49)
8 10 0 0 8 10 0 0
12 15 4 5 12 15 4 5
0 1
(50)
−1 0
Here we have:
+1 if i1 , . . . , idim is an even permutation of
i0 , . . . , i0 + dim − 1
−1 if i1 , . . . , idim is an odd permutation of
epsilon(i1 , . . . , idim ) =
i0 , . . . , i0 + dim − 1
0 if i1 , . . . , idim is not a permutation of
i0 , . . . , i0 + dim − 1
− 6 = −6 (51)
T[0](V) = R
T[k](V) = T[k-1](V) * V
where * denotes the R-module tensor product. CartesianTensor(i0,dim,R) is the graded algebra in
which the degree k module is T[k](V).
9.8. CHARACTER 363
Tensor Calculus
It should be noted here that often tensors are used in the context of tensor-valued manifold maps. This
leads to the notion of covariant and contravariant bases with tensor component functions transforming
in specific ways under a change of coordinates on the manifold. This is no more directly supported by
the CartesianTensor domain than it is by the Vector domain. However, it is possible to have the
components implicitly represent component maps by choosing a polynomial or expression type for the
components. In this case, it is up to the user to satisfy any constraints which arise on the basis of this
interpretation.
9.8 Character
The members of the domain Character are values representing letters, numerals and other text
elements. For more information on related topics, see ‘CharacterClass’ on page 365 and ‘String’ on
page 580.
Characters can be obtained using String notation.
chars := [ char " a " , char " A " , char " X " , char "8" , char "+"]
[a, A, X, 8, +] (4)
List (Character)
(5)
Character
" (6)
Character
This is the underscore character which is used to allow quotes and other special characters within
strings.
underscore ()
(7)
Character
Characters are represented as integers in a machine-dependent way. The integer value can be obtained
using the ord operation. It is always true that char(ord c)= c and ord(char i)= i, provided that
i is in the range 0..size()$Character-1.
[ ord c for c in chars ]
364 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
List ( Integer )
The lowerCase operation converts an upper case letter to the corresponding lower case letter. If the
argument is not an upper case letter, then it is returned unchanged.
[ upperCase c for c in chars ]
[A, A, X, 8, +] (9)
List (Character)
Likewise, the upperCase operation converts lower case letters to upper case.
[ lowerCase c for c in chars ]
[a, a, x, 8, +] (10)
List (Character)
A number of tests are available to determine whether characters belong to certain families.
[ alphabetic ? c for c in chars ]
List (Boolean)
List (Boolean)
List (Boolean)
List (Boolean)
List (Boolean)
List (Boolean)
9.9 CharacterClass
The CharacterClass domain allows classes of characters to be defined and manipulated efficiently.
Character classes can be created by giving either a string or a list of characters.
cl1 := charClass [ char " a " , char " e " , char " i " , char " o " , char " u " , char " y "]
"aeiouy" (4)
CharacterClass
cl2 := charClass " b c d f g h j k l m n p q r s t v w x y z "
"bcdfghjklmnpqrstvwxyz" (5)
CharacterClass
"0123456789" (6)
CharacterClass
hexDigit ()
"0123456789ABCDEFabcdef" (7)
CharacterClass
upperCase ()
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" (8)
CharacterClass
lowerCase ()
"abcdefghijklmnopqrstuvwxyz" (9)
CharacterClass
alphabetic ()
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" (10)
366 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
CharacterClass
alphanumeric ()
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" (11)
CharacterClass
true (12)
Boolean
member ?( char " a " , cl2 )
false (13)
Boolean
Classes have the usual set operations because the CharacterClass domain belongs to the category
FiniteSetAggregate(Character).
intersect ( cl1 , cl2 )
"y" (14)
CharacterClass
union ( cl1 , cl2 )
"abcdefghijklmnopqrstuvwxyz" (15)
CharacterClass
difference ( cl1 , cl2 )
"aeiou" (16)
CharacterClass
intersect ( complement ( cl1 ) , cl2 )
"bcdfghjklmnpqrstvwxz" (17)
CharacterClass
"abcdfghjklmnpqrstvwxyz" (18)
9.10. CLIFFORDALGEBRA 367
CharacterClass
remove !( char " b " , cl2 )
"acdfghjklmnpqrstvwxyz" (19)
CharacterClass
For more information on related topics, see ‘Character’ on page 363 and ‘String’ on page 580. Issue
the system command )show CharacterClass to display the full list of operations defined by Char-
acterClass.
9.10 CliffordAlgebra
CliffordAlgebra(n,K,Q) defines a vector space of dimension 2n over the field K with a given bilinar
form represented by square matrix Q. If e1 , . . . , en is a basis for K n then
{ 1
ei for 1 ≤ i ≤ n
ei1 ei2 for 1 ≤ i1 < i2 ≤ n
...
e1 e2 · · · en }
is a basis for the Clifford algebra. The algebra is defined by the relation
ei ei = Q(ei )
ei ej = −ej ei for i ̸= j
for all v being linear combinations of e(i). Examples of Clifford Algebras are gaussians (complex
numbers), quaternions, exterior algebras and spin algebras.
This is the field over which we will work, rational functions with integer coefficients.
K := Fraction Polynomial Integer
Fraction(Polynomial(Integer)) (1)
Type
−1 (2)
Matrix( Integer )
CliffordAlgebra 1, Fraction(Polynomial(Integer)), −1 (3)
Type
e1 (4)
a + b e1 (5)
y := c + d * i
c + d e1 (6)
See ‘Complex’ on page 372 for examples of FriCAS’s constructor implementing complex numbers.
x * y
− b d + a c + (a d + b c) e1 (7)
This is the field over which we will work, rational functions with integer coefficients.
K := Fraction Polynomial Integer
Fraction(Polynomial(Integer)) (1)
Type
−1 0
(2)
0 −1
9.10. CLIFFORDALGEBRA 369
Matrix( Integer )
−1 0
CliffordAlgebra 2, Fraction(Polynomial(Integer)), (3)
0 −1
Type
e1 (4)
j: H := e (2)
e2 (5)
k: H := i * j
e1 e2 (6)
x := a + b * i + c * j + d * k
a + b e1 + c e2 + d e1 e2 (7)
y := e + f * i + g * j + h * k
e + f e1 + g e2 + h e1 e2 (8)
x + y
e + a + (f + b) e1 + (g + c) e2 + (h + d) e1 e2 (9)
x * y
− d h − c g − b f + a e + (c h − d g + a f + b e) e1 + (−b h + a g + d f + c e) e2 + (a h + b g − c f + d e) e1 e2 (10)
370 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
See ‘Quaternion’ on page 540 for examples of FriCAS’s constructor implementing quaternions.
y * x
− d h − c g − b f + a e + (−c h + d g + a f + b e) e1 + (b h + a g − d f + c e) e2 + (a h − b g + c f + d e) e1 e2 (11)
This is the field over which we will work, rational functions with integer coefficients.
K := Fraction Polynomial Integer
Fraction(Polynomial(Integer)) (1)
Type
If we chose the three by three zero quadratic form, we obtain the exterior algebra on e(1),e(2),e(3).
Ext := C li ff or d Al ge br a (3 , K , 0)
0 0 0
CliffordAlgebra3, Fraction(Polynomial(Integer)), 0 0 0 (2)
0 0 0
Type
e1 (3)
CliffordAlgebra (3, Fraction (Polynomial( Integer )) , [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
j : Ext := e (2)
e2 (4)
CliffordAlgebra (3, Fraction (Polynomial( Integer )) , [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
k : Ext := e (3)
e3 (5)
CliffordAlgebra (3, Fraction (Polynomial( Integer )) , [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
x1 e1 + x2 e2 + x3 e3 (6)
CliffordAlgebra (3, Fraction (Polynomial( Integer )) , [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
y := y1 * i + y2 * j + y3 * k
y1 e1 + y2 e2 + y3 e3 (7)
CliffordAlgebra (3, Fraction (Polynomial( Integer )) , [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
x + y
CliffordAlgebra (3, Fraction (Polynomial( Integer )) , [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
x * y + y * x
0 (9)
CliffordAlgebra (3, Fraction (Polynomial( Integer )) , [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
On an n space, a grade p form has a dual n-p form. In particular, in three space the dual of a grade
two element identifies e1*e2→e3, e2*e3→e1, e3*e1→e2.
dual2 a == coefficient (a ,[2 ,3]) * i + coefficient (a ,[3 ,1]) * j + coefficient (a ,[1 ,2])
* k
CliffordAlgebra (3, Fraction (Polynomial( Integer )) , [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
Fraction(Integer) (1)
Type
1 0 0 0
0 −1 0 0
(2)
0 0 −1 0
0 0 0 −1
Matrix( Integer )
We obtain the Dirac spin algebra used in Relativistic Quantum Field Theory.
D := C li f fo rd Al g eb ra (4 , K , g )
1 0 0 0
0 −1 0 0
CliffordAlgebra4, Fraction(Integer),
(3)
0 0 −1 0
0 0 0 −1
Type
The usual notation for the basis is γ with a superscript. For FriCAS input we will use gam(i):
gam := [ e ( i ) $ D for i in 1..4]
[e1 , e2 , e3 , e4 ] (4)
List ( CliffordAlgebra (4, Fraction ( Integer ) , [[1, 0, 0, 0], [0, =1, 0, 0], [0, 0, =1, 0], [0, 0, 0, =1]]))
g(l,t)*gam(l)*gam(m)*gam(n)*gam(r)*gam(s)*gam(t) =
2*(gam(s)gam(m)gam(n)gam(r) + gam(r)*gam(n)*gam(m)*gam(s))
where a sum over l and t is implied. Verify this identity for particular values of m,n,r,s.
m := 1; n := 2; r := 3; s := 4;
PositiveInteger
lhs := reduce (+ , [ reduce (+ , [ g (l , t ) * gam ( l ) * gam ( m ) * gam ( n ) * gam ( r ) * gam ( s ) * gam ( t ) for l
in 1..4]) for t in 1..4])
− 4 e1 e2 e3 e4 (6)
CliffordAlgebra (4, Fraction ( Integer ) , [[1, 0, 0, 0], [0, =1, 0, 0], [0, 0, =1, 0], [0, 0, 0, =1]])
rhs := 2*( gam s * gam m * gam n * gam r + gam r * gam n * gam m * gam s )
− 4 e1 e2 e3 e4 (7)
CliffordAlgebra (4, Fraction ( Integer ) , [[1, 0, 0, 0], [0, =1, 0, 0], [0, 0, =1, 0], [0, 0, 0, =1]])
9.11 Complex
The Complex constructor implements complex objects over a commutative ring R. Typically, the
ring R is Integer, Fraction Integer, Float or DoubleFloat. R can also be a symbolic type, like
9.11. COMPLEX 373
Polynomial Integer. For more information about the numerical and graphical aspects of complex
numbers, see Section 8.1 on page 251.
Complex objects are created by the complex operation.
a := complex (4/3 ,5/2)
4 5
+ i (4)
3 2
Complex(Fraction(Integer))
4 5
− i (5)
3 2
Complex(Fraction(Integer))
8
(6)
3
Complex(Fraction(Integer))
a - b
5i (7)
Complex(Fraction(Integer))
a * b
289
(8)
36
Complex(Fraction(Integer))
161 240
− + i (9)
289 289
Complex(Fraction(Integer))
Use a conversion (Section 2.7 on page 84) to view the last object as a fraction of complex integers.
% :: Fraction Complex Integer
−15 + 8 i
(10)
15 + 8 i
374 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Fraction (Complex(Integer))
Complex(Float)
You can also compute the conjugate and norm of a complex number.
conjugate a
4 5
− i (12)
3 2
Complex(Fraction(Integer))
norm a
289
(13)
36
Fraction ( Integer )
The real and imag operations are provided to extract the real and imaginary parts, respectively.
real a
4
(14)
3
Fraction ( Integer )
imag a
5
(15)
2
Fraction ( Integer )
The domain Complex Integer is also called the Gaussian integers. If R is the integers (or, more
generally, a EuclideanDomain), you can compute greatest common divisors.
gcd (13 - 13*% i ,31 + 27*% i )
5+i (16)
Complex(Integer)
143 − 39 i (17)
Complex(Integer)
− (1 + i) (2 + 3 i) (3 + 2 i) (18)
Factored(Complex(Integer))
− i (1 + i)2 (19)
Factored(Complex(Integer))
9.12 ContinuedFraction
Continued fractions have been a fascinating and useful tool in mathematics for well over three hundred
years. FriCAS implements continued fractions for fractions of any Euclidean domain. In practice, this
usually means rational numbers. In this section we demonstrate some of the operations available for
manipulating both finite and infinite continued fractions. It may be helpful if you review ‘Stream’ on
page 578 to remind yourself of some of the operations with streams.
The ContinuedFraction domain is a field and therefore you can add, subtract, multiply and divide
the fractions. The continuedFraction operation converts its fractional argument to a continued
fraction.
c := c o n t i n u e d F r a c t i o n (3 1 41 59 /1 0 00 00 )
1| 1| 1| 1| 1| 1| 1|
3+ + + + + + + (4)
|7 |15 |1 |25 |1 |7 |4
ContinuedFraction( Integer )
Stream(Integer)
By considering more and more of the fraction, you get the convergents. For example, the first convergent
is a1 , the second is a1 + 1/a2 and so on.
convergents c
22 333 355 9208 9563 76149
3, , , , , , , ... (6)
7 106 113 2931 3044 24239
Stream(Fraction( Integer ))
Since this is a finite continued fraction, the last convergent is the original rational number, in reduced
form. The result of approximants is always an infinite stream, though it may just repeat the “last”
value.
approximants c
22 333 355 9208 9563 76149
3, , , , , , , ... (7)
7 106 113 2931 3044 24239
Stream(Fraction( Integer ))
Inverting c only changes the partial quotients of its fraction by inserting a 0 at the beginning of the
list.
pq := p a r t i a l Q u o t i e n ts (1/ c )
Stream(Integer)
Do this to recover the original continued fraction from this list of partial quotients. The three-argument
form of the continuedFraction operation takes an element which is the whole part of the fraction, a
stream of elements which are the numerators of the fraction, and a stream of elements which are the
denominators of the fraction.
c o n t i n u e d F r a c t i o n ( first pq , repeating [1] , rest pq )
1| 1| 1| 1| 1| 1| 1|
+ + + + + + + ... (9)
|3 |7 |15 |1 |25 |1 |7
9.12. CONTINUEDFRACTION 377
ContinuedFraction( Integer )
The streams need not be finite for continuedFraction. Can you guess which irrational number has the
following continued fraction? See the end of this section for the answer.
z := c o n t i n u ed F r a c t i o n (3 , repeating [1] , repeating [3 ,6])
1| 1| 1| 1| 1| 1| 1|
3+ + + + + + + + ... (10)
|3 |6 |3 |6 |3 |6 |3
ContinuedFraction( Integer )
e−1 1
=
2 1
1+
1
6+
1
10 +
14 + · · ·
We use this expansion to compute rational and floating point approximations of e.2
By looking at the above expansion, we see that the whole part is 0 and the numerators are all equal
to 1. This constructs the stream of denominators.
dens : Stream Integer := cons (1 , stream (( x + - > x + 4) , 6) )
Stream(Integer)
1| 1| 1| 1| 1| 1| 1|
+ + + + + + + ... (12)
|1 |6 |10 |14 |18 |22 |26
ContinuedFraction( Integer )
6 61 860 15541 342762
0, 1, , , , , , ... (13)
7 71 1001 18089 398959
Stream(Fraction( Integer ))
2 For this and other interesting expansions, see C. D. Olds, Continued Fractions, New Mathematical Library, (New
19 193 2721 49171 1084483
1, 3, , , , , , ... (14)
7 71 1001 18089 398959
Stream(Fraction( Integer ))
You can also compute the floating point approximations to these convergents.
eConvergents :: Stream Float
Stream(Float)
2.7182818284590452354 (16)
Float
In about 1658, Lord Brouncker established the following expansion for 4/π.
1
1+
9
2+
25
2+
49
2+
81
2+
2 + ···
Let’s use this expansion to compute rational and floating point approximations for π.
cf := c o n t i n u e d F r a c t i o n (1 ,[(2* i +1) ^2 for i in 0..] , repeating [2])
ContinuedFraction( Integer )
ccf := convergents cf
3 15 105 315 3465 45045
1, , , , , , , ... (18)
2 13 76 263 2578 36979
Stream(Fraction( Integer ))
8 52 304 1052 10312 147916
4, , , , , , , ... (19)
3 15 105 315 3465 45045
9.12. CONTINUEDFRACTION 379
Stream(Fraction( Integer ))
As you can see, the values are converging to π = 3.14159265358979323846..., but not very quickly.
piConvergents :: Stream Float
Stream(Float)
You need not restrict yourself to continued fractions of integers. Here is an expansion for a quotient
of Gaussian integers.
c o n t i n u e d F r a c t i o n (( - 122 + 597*% i ) /(4 - 4*% i ) )
1| 1|
− 90 + 59 i + + (21)
|1 − 2 i |−1 + 2 i
ContinuedFraction(Complex(Integer))
This is an expansion for a quotient of polynomials in one variable with rational number coefficients.
r : Fraction U n i v a r i a t e P o l y n o m i a l (x , Fraction Integer )
r := (( x - 1) * ( x - 2) ) / (( x -3) * (x -4) )
x2 − 3 x + 2
(23)
x2 − 7 x + 12
Fraction ( UnivariatePolynomial (x, Fraction ( Integer )))
continuedFraction r
1| 1|
1+ 1 9
+ 16 40
(24)
4
x− 8 3
x− 3
1| 1| 1| 1| 1| 1| 1|
3+ + + + + + + + ... (25)
|3 |6 |3 |6 |3 |6 |3
ContinuedFraction( Integer )
√
is the expansion of 11.
[ i * i for i in convergents ( z ) :: Stream Float ]
Stream(Float)
c o n t i n u e d F r a c t i o n sqrt 11.0
1| 1| 1| 1| 1| 1| 1|
3+ + + + + + + + ... (27)
|3 |6 |3 |6 |3 |6 |3
ContinuedFraction( Integer )
9.13 CycleIndicators
This section is based upon the paper J. H. Redfield, “The Theory of Group-Reduced Distributions”,
American J. Math.,49 (1927) 433-455, and is an application of group theory to enumeration problems.
It is a development of the work by P. A. MacMahon on the application of symmetric functions and
Hammond operators to combinatorial theory.
The theory is based upon the power sum symmetric functions si which are the sum of the i th powers
of the variables. The cycle index of a permutation is an expression that specifies the sizes of the cycles
of a permutation, and may be represented as a partition. A partition of a non-negative integer n is a
collection of positive integers called its parts whose sum is n. For example, the partition (32 2 12 ) will
be used to represent s23 s2 s21 and will indicate that the permutation has two cycles of length 3, one of
length 2 and two of length 1. The cycle index of a permutation group is the sum of the cycle indices
of its permutations divided by the number of permutations. The cycle indices of certain groups are
provided. We first expose something from the library.
) expose EVALCYC
E v a l u a t e C y c l e I n d i c a t o r s is now explicitly exposed in frame initial
The operation complete returns the cycle index of the symmetric group of order n for argument n.
Alternatively, it is the nth complete homogeneous symmetric function expressed in terms of power
sum symmetric functions.
complete 1
(1) (4)
SymmetricPolynomial(Fraction(Integer))
complete 2
1 1 2
(2) + 1 (5)
2 2
SymmetricPolynomial(Fraction(Integer))
complete 3
1 1 1 3
(3) + (2 1) + 1 (6)
3 2 6
9.13. CYCLEINDICATORS 381
SymmetricPolynomial(Fraction(Integer))
complete 7
1 1 1 1 1 1 1 1
5 12 + 4 13 + 32 1
(7) + (6 1) + (5 2) + (4 3) + (4 2 1) + (7)
7 6 10 10 12 8 24 18
1 1 1 1 1 1 1
3 22 + 3 2 12 + 3 14 + 23 1 + 22 13 + 2 15 + 17
+
24 12 72 48 48 240 5040
SymmetricPolynomial(Fraction(Integer))
The operation elementary computes the nth elementary symmetric function for argument n.
elementary 7
1 1 1 1 1 1 1 1
5 12 − 4 13 + 32 1
(7) − (6 1) − (5 2) + (4 3) + (4 2 1) − (8)
7 6 10 10 12 8 24 18
1 1 1 1 1 1 1
3 22 − 3 2 12 + 3 14 − 23 1 + 22 13 − 2 15 + 17
+
24 12 72 48 48 240 5040
SymmetricPolynomial(Fraction(Integer))
The operation alternating returns the cycle index of the alternating group having an even number of
even parts in each cycle partition.
alternating 7
2 1 1 1 2 1 1 1 1
5 12 + (4 2 1) + 3 22 + 3 14 + 22 13 + 17
(7) + 3 1 + (9)
7 5 4 9 12 36 24 2520
SymmetricPolynomial(Fraction(Integer))
The operation cyclic returns the cycle index of the cyclic group.
cyclic 7
6 1 7
(7) + 1 (10)
7 7
SymmetricPolynomial(Fraction(Integer))
3 1 3 1
17
(7) + 2 1 + (11)
7 2 14
SymmetricPolynomial(Fraction(Integer))
The operation graphs for argument n returns the cycle index of the group of permutations on the edges
of the complete graph with n nodes induced by applying the symmetric group to the nodes.
graphs 5
382 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
1 1 2 1 2 1 3 1 4 2 1 1
23 14 + 110
(6 3 1) + 5 + 4 2 + 3 1 + 2 1 + (12)
6 5 4 6 8 12 120
SymmetricPolynomial(Fraction(Integer))
The cycle index of a direct product of two groups is the product of the cycle indices of the groups.
Redfield provided two operations on two cycle indices which will be called “cup” and “cap” here. The
cup of two cycle indices is a kind of scalar product that combines monomials for permutations with the
same cycles. The cap operation provides the sum of the coefficients of the result of the cup operation
which will be an integer that enumerates what Redfield called group-reduced distributions.
We can, for example, represent complete 2 * complete 2 as the set of objects a a b b and complete
2 * complete 1 * complete 1 as c c d e.
This integer is the number of different sets of four pairs.
cap ( complete 2^2 , complete 2* complete 1^2)
4 (13)
Fraction ( Integer )
For example,
a a b b a a b b a a b b a a b b
c c d e c d c e c e c d d e c c
This integer is the number of different sets of four pairs no two pairs being equal.
cap ( elementary 2^2 , complete 2* complete 1^2)
2 (14)
Fraction ( Integer )
For example,
a a b b a a b b
c d c e c e c d
In this case the configurations enumerated are easily constructed, however the theory merely enumer-
ates them providing little help in actually constructing them. Here are the number of 6-pairs, first
from a a a b b c, second from d d e e f g.
cap ( complete 3* complete 2* complete 1 , complete 2^2* complete 1^2)
24 (15)
Fraction ( Integer )
8 (16)
Fraction ( Integer )
8 (17)
Fraction ( Integer )
1500 (18)
Fraction ( Integer )
1 3 2 1 1 4
(4) + 2 + 2 12 + 1 (19)
4 8 4 8
SymmetricPolynomial(Fraction(Integer))
The number of different squares with 2 red vertices and 2 blue vertices.
cap ( complete 2^2 , square )
2 (20)
Fraction ( Integer )
The number of necklaces with 3 red beads, 2 blue beads and 2 green beads.
cap ( complete 3* complete 2^2 , dihedral 7)
18 (21)
Fraction ( Integer )
4 (22)
Fraction ( Integer )
1 2 1 2 2 3 4 1
18
4 + 3 1 + 2 + (24)
4 3 8 24
SymmetricPolynomial(Fraction(Integer))
7 (25)
Fraction ( Integer )
The number of labeled graphs with degree sequence 2 2 2 1 1 with no loops or multiple edges.
cap ( complete 2^3* complete 1^2 , wreath ( elementary 4 , elementary 2) )
7 (26)
Fraction ( Integer )
17 (27)
Fraction ( Integer )
10 (28)
Fraction ( Integer )
23 (29)
Fraction ( Integer )
Having constructed a cycle index for a configuration we are at liberty to evaluate the si components
any way we please. For example we can produce enumerating generating functions. This is done
by providing a function f on an integer i to the value required of si , and then evaluating eval(f,
cycleindex).
x : ULS ( FRAC INT , ’x ,0) := ’x
9.13. CYCLEINDICATORS 385
x (30)
ZeroOrOne 5
Compiling function ZeroOrOne with type Integer -> U n i v a r i a t e L a u r e n t S e r i e s (
Fraction ( Integer ) ,x ,0)
1 + x5 (34)
Integers 5
Compiling function Integers with type Integer -> U n i v a r i a t e L a u r e n t S e r i e s (
Fraction ( Integer ) ,x ,0)
1 + x5 + O x8
(36)
1 + x + 2 x2 + 4 x3 + 6 x4 + 6 x5 + 6 x6 + 4 x7 + O x8
(37)
The coefficient of xn is the number of necklaces with n red beads and n-8 green beads.
eval ( ZeroOrOne , dihedral 8)
1 + x + 4 x2 + 5 x3 + 8 x4 + 5 x5 + 4 x6 + x7 + O x8
(38)
1 + x + 2 x2 + 3 x3 + 5 x4 + 6 x5 + 9 x6 + 11 x7 + O x8
(39)
386 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
The coefficient of xn is the number of partitions of n into 4 boxes containing ordered distinct parts.
eval ( Integers , elementary 4)
The coefficient of xn is the number of different cubes with n red vertices and 8-n green ones.
eval ( ZeroOrOne , cube )
1 + x + 3 x2 + 3 x3 + 7 x4 + 3 x5 + 3 x6 + x7 + O x8
(41)
The coefficient of xn is the number of different cubes with integers on the vertices whose sum is n.
eval ( Integers , cube )
1 + x + 4 x2 + 7 x3 + 21 x4 + 37 x5 + 85 x6 + 151 x7 + O x8
(42)
The coefficient of xn is the number of graphs with 5 nodes and with integers on the edges whose sum
is n. In other words, the enumeration is of multigraphs with 5 nodes and n edges.
eval ( Integers , graphs 5)
1 + x + 3 x2 + 7 x3 + 17 x4 + 35 x5 + 76 x6 + 149 x7 + O x8
(43)
1 + x + 2 x2 + 5 x3 + 11 x4 + 26 x5 + 68 x6 + 177 x7 + O x8
(44)
Necklaces with 7 green beads, 8 white beads, 5 yellow beads and 10 red beads.
cap ( dihedral 30 , complete 7* complete 8* complete 5* complete 10)
49958972383320 (45)
Fraction ( Integer )
The operation SFunction is the S-function or Schur function of a partition written as a descending list
of integers expressed in terms of power sum symmetric functions. In this case the argument partition
represents a tableau shape. For example 3,2,2,1 represents a tableau with three boxes in the first
row, two boxes in the second and third rows, and one box in the fourth row. SFunction [3,2,2,1]
9.13. CYCLEINDICATORS 387
counts the number of different tableaux of shape 3, 2, 2, 1 filled with objects with an ascending
order in the columns and a non-descending order in the rows.
sf3221 := SFunction [3 ,2 ,2 ,1]
1 1 1 1 1 1 1 1
6 12 − 42 + 4 14 − 32 2 + 32 12 − 3 22 1
(6 2)− (4 3 1)+ (46)
12 12 16 12 24 36 36 24
1 1 1 1 1 1 1
3 2 13 − 3 15 − 24 + 23 12 + 22 14 − 2 16 + 18
−
36 72 192 48 96 144 576
SymmetricPolynomial(Fraction(Integer))
3 (47)
Fraction ( Integer )
a a b a a c a a d
b c b b b b
c d c d c c
d d d
70 (48)
Fraction ( Integer )
The coefficient of xn is the number of column strict reverse plane partitions of n of shape 3 2 2 1.
eval ( Integers , sf3221 )
The smallest is
0 0 0
1 1
2 2
3
388 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
9.14 DecimalExpansion
All rationals have repeating decimal expansions. Operations to access the individual digits of a decimal
expansion can be obtained by converting the value to RadixExpansion(10). More examples of
expansions are available in ‘BinaryExpansion’ on page 348, ‘HexadecimalExpansion’ on page 440,
and ‘RadixExpansion’ on page 542. Issue the system command )show DecimalExpansion to display
the full list of operations defined by DecimalExpansion.
The operation decimal is used to create this expansion of type DecimalExpansion.
r := decimal (22/7)
3.142857 (4)
DecimalExpansion
Arithmetic is exact.
r + decimal (6/7)
4 (5)
DecimalExpansion
0.00285714, 0.002849, 0.0028409, 0.00283286118980169971671388101983, (6)
0.00282485875706214689265536723163841807909604519774011299435
List (DecimalExpansion)
or very long.
decimal (1/2049)
0.00048804294777940458760370912640312347486578818936066373840897999023914104441190824792581747193753050268423621278
(7)
DecimalExpansion
Polynomial(DecimalExpansion)
q := differentiate (p , x )
Polynomial(DecimalExpansion)
g := gcd (p , q )
x + 1.3 (10)
Polynomial(DecimalExpansion)
9.15 DeRhamComplex
The domain constructor DeRhamComplex creates the class of differential forms of arbitrary degree
over a coefficient ring. The De Rham complex constructor takes two arguments: a ring, coefRing,
and a list of coordinate variables.
This is the ring of coefficients.
coefRing := Integer
Integer (4)
Type
[x, y, z] (5)
List (Symbol)
Type
This complex allows us to describe differential forms having expressions of integers as coefficients. These
coefficients can involve any number of variables, for example, f(x,t,r,y,u,z). As we’ve chosen to
work with ordinary Euclidean three-space, expressions involving these forms are treated as functions
of x, y and z with the additional arguments t, r and u regarded as symbolic constants. Here are
some examples of coefficients.
R := Expression coefRing
Expression(Integer) (7)
Type
− 5 x3 y 2 z 5 + x2 y z (8)
Expression ( Integer )
− 7 z 2 sin x3 y 2 + y z 2 cos(z)
(9)
Expression ( Integer )
h : R := x * y *z -2* x ^3* y * z ^2
− 2 x3 y z 2 + x y z (10)
Expression ( Integer )
We now define the multiplicative basis elements for the exterior algebra over R.
dx : der := generator (1)
dx (11)
DeRhamComplex(Integer, [x, y, z ])
dy (12)
DeRhamComplex(Integer, [x, y, z ])
dz (13)
DeRhamComplex(Integer, [x, y, z ])
−2 x3 y z 2 + x y z dz + −7 z 2 sin x3 y 2 + y z 2 cos(z) dy + −5 x3 y 2 z 5 + x2 y z dx
(15)
DeRhamComplex(Integer, [x, y, z ])
x dy + cos(tan(x y z) + x y z) dx (16)
DeRhamComplex(Integer, [x, y, z ])
A well-known theorem states that the composition of exteriorDifferential with itself is the zero map for
continuous forms. Let’s verify this theorem for alpha.
e x t e r i o r D i f f e r e n t i a l alpha ;
DeRhamComplex(Integer, [x, y, z ])
We suppressed the lengthy output of the last expression, but nevertheless, the composition is zero.
exteriorDifferential %
0 (18)
DeRhamComplex(Integer, [x, y, z ])
2 x4 y z 2 − x2 y z dy dz + 2 x3 y z 2 − x y z cos(tan(x y z) + x y z) dx dz (19)
DeRhamComplex(Integer, [x, y, z ])
0 (20)
DeRhamComplex(Integer, [x, y, z ])
a (21)
BasicOperator
b : BOP := operator ( ’ b )
b (22)
BasicOperator
c : BOP := operator ( ’ c )
392 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
c (23)
BasicOperator
We also define some indeterminate one- and two-forms using these operators.
sigma := a (x ,y , z ) * dx + b (x ,y , z ) * dy + c (x ,y , z ) * dz
DeRhamComplex(Integer, [x, y, z ])
theta := a (x ,y , z ) * dx * dy + b (x ,y , z ) * dx * dz + c (x ,y , z ) * dy * dz
DeRhamComplex(Integer, [x, y, z ])
DeRhamComplex(Integer, [x, y, z ])
the “curl” . . .
e x t e r i o r D i f f e r e n t i a l sigma
(c,2 (x, y, z) − b,3 (x, y, z)) dy dz + (c,1 (x, y, z) − a,3 (x, y, z)) dx dz + (b,1 (x, y, z) − a,2 (x, y, z)) dx dy (27)
DeRhamComplex(Integer, [x, y, z ])
DeRhamComplex(Integer, [x, y, z ])
Note that the De Rham complex is an algebra with unity. This element 1 is the basis for elements for
zero-forms, that is, functions in our space.
one : der := 1
1 (29)
DeRhamComplex(Integer, [x, y, z ])
To convert a function to a function lying in the De Rham complex, multiply the function by “one.”
g1 : der := a ([ x ,t ,y ,u ,v ,z , e ]) * one
9.15. DERHAMCOMPLEX 393
a(x, t, y, u, v, z, e) (30)
DeRhamComplex(Integer, [x, y, z ])
A current limitation of FriCAS forces you to write functions with more than four arguments using
square brackets in this way.
h1 : der := a ([ x ,y ,x ,t ,x ,z ,y ,r ,u , x ]) * one
a(x, y, x, t, x, z, y, r, u, x) (31)
DeRhamComplex(Integer, [x, y, z ])
Now note how the system keeps track of where your coordinate functions are located in expressions.
e x t e r i o r D i f f e r e n t i a l g1
DeRhamComplex(Integer, [x, y, z ])
e x t e r i o r D i f f e r e n t i a l h1
DeRhamComplex(Integer, [x, y, z ])
In this example of Euclidean three-space, the basis for the De Rham complex consists of the eight
forms: 1, dx, dy, dz, dx*dy, dx*dz, dy*dz, and dx*dy*dz.
coefficient ( gamma , dx * dy )
Expression ( Integer )
0 (35)
Expression ( Integer )
coefficient ( g1 , one )
a(x, t, y, u, v, z, e) (36)
Expression ( Integer )
394 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
9.16 DistributedMultivariatePolynomial
DistributedMultivariatePolynomial and HomogeneousDistributedMultivariatePolynomial,
abbreviated DMP and HDMP, respectively, are very similar to MultivariatePolynomial except
that they are represented and displayed in a non-recursive manner.
( d1 , d2 , d3 ) : DMP ([ z ,y , x ] , FRAC INT )
The constructor DMP orders its monomials lexicographically while HDMP orders them by total
order refined by reverse lexicographic order.
d1 := -4* z + 4* y ^2* x + 16* x ^2 + 1
− 4 z + 4 y 2 x + 16 x2 + 1 (5)
d2 := 2* z * y ^2 + 4* x + 1
2 z y2 + 4 x + 1 (6)
d3 := 2* z * x ^2 - 2* y ^2 - x
2 z x2 − 2 y 2 − x (7)
1568 6 1264 5 6 4 182 3 2047 2 103 2857
z− x − x + x + x − x − x− ,
2745 305 305 549 610 2745 10980
112 6 84 5 1264 4 13 3 84 2 1772 2 (8)
y2 + x − x − x − x + x + x+ ,
2745 305 305 549 305 2745 2745
29 6 17 4 11 3 1 2 15 1
x7 + x − x − x + x + x+
4 16 8 32 16 4
( n1 , n2 , n3 ) := ( d1 , d2 , d3 )
2 z x2 − 2 y 2 − x (10)
Note that we get a different Gröbner basis when we use the HDMP polynomials, as expected.
groebner [ n1 , n2 , n3 ]
9.17. DOUBLEFLOAT 395
3 2 1 1 29 3 1 2 7 9 1 1
y 4 + 2 x3 − x + z − , x4 + x − y − zx− x − , z y2 + 2 x + , (11)
2 2 8 4 8 4 16 4 2
2 2 1 2 2 1 2 2 2 1 3
y x + 4 x − z + , z x − y − x, z − 4 y + 2 x − z − x
4 2 4 2
9.17 DoubleFloat
FriCAS provides two kinds of floating point numbers. The domain Float (abbreviation FLOAT)
implements a model of arbitrary precision floating point numbers. The domain DoubleFloat (abbre-
viation DFLOAT) is intended to make available hardware floating point arithmetic in FriCAS. The
actual model of floating point DoubleFloat that provides is system-dependent. In the past there were
wide variety of floating point formats. For example, the IBM system 370 used hexadecimal format such
that double precision number had fourteen hexadecimal digits of precision or roughly sixteen decimal
digits. All system currently supported by FriCAS use IEEE binary format with 64-bit double having
sign bit, 11 exponents bits and 53 significant bits (that adds to 65, but most significant bit is 1 and
there is no need to store it).
Arbitrary precision floats allow the user to specify the precision at which arithmetic operations are
computed. Although this is an attractive facility, it comes at a cost. Arbitrary-precision floating-point
arithmetic typically takes twenty to two hundred times more time than hardware floating point.
The usual arithmetic and elementary functions are available for DoubleFloat. Use )show DoubleFloat
to get a list of operations or the HyperDoc Browse facility to get more extensive documentation about
DoubleFloat.
By default, floating point numbers that you enter into FriCAS are of type Float.
2.71828
2.71828 (4)
Float
You must therefore tell FriCAS that you want to use DoubleFloat values and operations. The
following are some conservative guidelines for getting FriCAS to use DoubleFloat.
To get a value of type DoubleFloat, use a target with “@”, . . .
2.71828 @DoubleFloat
396 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
2.71828 (5)
DoubleFloat
a conversion, . . .
2.71828 :: DoubleFloat
2.71828 (6)
DoubleFloat
or an assignment to a declared variable. It is more efficient if you use a target rather than an explicit
or implicit conversion.
eApprox : DoubleFloat := 2.71828
2.71828 (7)
DoubleFloat
avg l ==
empty ? l = > 0 :: DoubleFloat
reduce ( _ + , l ) / # l
avg []
Compiling function avg with type List ( DoubleFloat ) -> DoubleFloat
0.0 (10)
DoubleFloat
avg [3.4 ,9.7 , -6.8]
2.1 (11)
DoubleFloat
Use package-calling for operations from DoubleFloat unless the arguments themselves are already of
type DoubleFloat.
cos (3.1415926) $ DoubleFloat
− 0.9999999999999986 (12)
DoubleFloat
cos (3.1415926 :: DoubleFloat )
− 0.9999999999999986 (13)
9.18. EQTABLE 397
DoubleFloat
By far, the most common usage of DoubleFloat is for functions to be graphed. For more information
about FriCAS’s numerical and graphical facilities, see Section 7 on page 195, Section 8.1 on page 251,
and ‘Float’ on page 419.
9.18 EqTable
The EqTable domain provides tables where the keys are compared using eq?. Keys are considered
equal only if they are the same instance of a structure. This is useful if the keys are themselves
updatable structures. Otherwise, all operations are the same as for type Table. See ‘Table’ on page
589 for general information about tables. Issue the system command )show EqTable to display the
full list of operations defined by EqTable.
The operation table is here used to create a table where the keys are lists of integers.
e : EqTable ( List Integer , Integer ) := table ()
table () (4)
These two lists are equal according to =, but not according to eq?.
l1 := [1 ,2 ,3]
[1, 2, 3] (5)
List ( PositiveInteger )
l2 := [1 ,2 ,3]
[1, 2, 3] (6)
List ( PositiveInteger )
Because the two lists are not eq?, separate values can be stored under each.
e . l1 := 111
111 (7)
PositiveInteger
e . l2 := 222
222 (8)
PositiveInteger
e . l1
398 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
111 (9)
PositiveInteger
9.19 Equation
The Equation domain provides equations as mathematical objects. These are used, for example, as
the input to various solve operations.
Equations are created using the equals symbol, =.
eq1 := 3* x + 4* y = 5
4y + 3x = 5 (4)
Equation(Polynomial(Integer ))
eq2 := 2* x + 2* y = 3
2y + 2x = 3 (5)
Equation(Polynomial(Integer ))
The left- and right-hand sides of an equation are accessible using the operations lhs and rhs.
lhs eq1
4y + 3x (6)
Polynomial( Integer )
rhs eq1
5 (7)
Polynomial( Integer )
Arithmetic operations are supported and operate on both sides of the equation.
eq1 + eq2
6y + 5x = 8 (8)
Equation(Polynomial(Integer ))
eq1 * eq2
8 y 2 + 14 x y + 6 x2 = 15 (9)
Equation(Polynomial(Integer ))
2* eq2 - eq1
9.20. EXIT 399
x=1 (10)
Equation(Polynomial(Integer ))
Equations may be created for any type so the arithmetic operations will be defined only when they
make sense. For example, exponentiation is not defined for equations involving non-square matrices.
eq1 ^2
16 y 2 + 24 x y + 9 x2 = 25 (11)
Equation(Polynomial(Integer ))
Note that an equals symbol is also used to test for equality of values in certain contexts. For example,
x+1 and y are unequal as polynomials.
if x +1 = y then " equal " else " unequal "
"unequal" (12)
String
eqpol := x +1 = y
x+1=y (13)
Equation(Polynomial(Integer ))
If an equation is used where a Boolean value is required, then it is evaluated using the equality test
from the operand type.
if eqpol then " equal " else " unequal "
"unequal" (14)
String
If one wants a Boolean value rather than an equation, all one has to do is ask!
eqpol :: Boolean
false (15)
Boolean
9.20 Exit
A function that does not return directly to its caller has Exit as its return type. The operation error
is an example of one which does not return to its caller. Instead, it causes a return to top-level.
n := 0
400 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
0 (4)
NonNegativeInteger
The function gasp is given return type Exit since it is guaranteed never to return a value to its caller.
gasp () : Exit ==
free n
n := n + 1
error " Oh no !"
Function declaration gasp : () -> Exit has been added to workspace .
The return type of half is determined by resolving the types of the two branches of the if.
half ( k ) ==
if odd ? k then gasp ()
else k quo 2
Because gasp has the return type Exit, the type of if in half is resolved to be Integer.
half 4
Compiling function gasp with type () -> Exit
Compiling function half with type Po s it iv eI n te ge r -> Integer
2 (7)
PositiveInteger
half 3
Error signalled from user code in function gasp :
Oh no !
n
1 (8)
NonNegativeInteger
For functions which return no value at all, use Void. See Section 6 on page 149 and ‘Void’ on page
606 for more information. Issue the system command )show Exit to display the full list of operations
defined by Exit.
9.21 Expression
Expression is a constructor that creates domains whose objects can have very general symbolic forms.
Here are some examples: This is an object of type Expression Integer.
sin ( x ) + 3* cos ( x ) ^2
Expression ( Integer )
tan ( x ) - 3.45* x
Expression (Float)
This object contains symbolic function applications, sums, products, square roots, and a quotient.
( tan sqrt 7 - sin sqrt 11) ^2 / (4 - cos ( x - y ) )
√ 2 √ √ √ 2
−tan 7 + 2 sin 11 tan 7 − sin 11
(6)
cos(y − x) − 4
Expression ( Integer )
As you can see, Expression actually takes an argument domain. The coefficients of the terms within
the expression belong to the argument domain. Integer and Float, along with Complex Integer
and Complex Float are the most common coefficient domains. The choice of whether to use a
Complex coefficient domain or not is important since FriCAS can perform some simplifications on
real-valued objects
log ( exp x ) @Expression ( Integer )
x (7)
Expression ( Integer )
log(ex ) (8)
Expression (Complex(Integer))
Many potential coefficient domains, such as AlgebraicNumber, are not usually used because Expression
can subsume them.
sqrt 3 + sqrt (2 + sqrt ( -5) )
q
√ √
−5 + 2 + 3 (9)
AlgebraicNumber
% :: Expression Integer
q
√ √
−5 + 2 + 3 (10)
Expression ( Integer )
Note that we sometimes talk about “an object of type Expression.” This is not really correct because
we should say, for example, “an object of type Expression Integer” or “an object of type Expression
402 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Float.” By a similar abuse of language, when we refer to an “expression” in this section we will mean
an object of type Expression R for some domain R.
The FriCAS documentation contains many examples of the use of Expression. For the rest of this
section, we’ll give you some pointers to those examples plus give you some idea of how to manipulate
expressions.
It is important for you to know that Expression creates domains that have category Field. Thus
you can invert any non-zero expression and you shouldn’t expect an operation like factor to give you
much information. You can imagine expressions as being represented as quotients of “multivariate”
polynomials where the “variables” are kernels (see ‘Kernel’ on page 454). A kernel can either be a
symbol such as x or a symbolic function application like sin(x + 4). The second example is actually
a nested kernel since the argument to sin contains the kernel x.
height mainKernel sin ( x + 4)
2 (11)
PositiveInteger
Actually, the argument to sin is an expression, and so the structure of Expression is recursive. ‘Kernel’
on page 454 demonstrates how to extract the kernels in an expression.
Use the HyperDoc Browse facility to see what operations are applicable to expression. At the time of
this writing, there were 262 operations with 147 distinct name in Expression Integer. For example,
numer and denom extract the numerator and denominator of an expression.
e := ( sin ( x ) - 4) ^2 / ( 1 - 2* y * sqrt ( - y ) )
−sin(x)2 + 8 sin(x) − 16
√ (12)
2 y −y − 1
Expression ( Integer )
numer e
denom e
√
2y −y − 1 (14)
√
(4 y cos(x) sin(x) − 16 y cos(x)) −y − 2 cos(x) sin(x) + 8 cos(x)
√ (15)
4 y −y + 4 y 3 − 1
9.21. EXPRESSION 403
Expression ( Integer )
See Section 1.12 on page 53 for more examples of expressions and derivatives.
D (e , [x , y ] , [1 , 2])
√
−2304 y 7 + 960 y 4 cos(x) sin(x) + 9216 y 7 − 3840 y 4 cos(x) −y + −960 y 9 + 2160 y 6 − 180 y 3 − 3 cos(x) sin(x) + 3840 y 9
√ (16)
(256 y 12 − 1792 y 9 + 1120 y 6 − 112 y 3 + 1) −y − 1024 y 11 + 1792 y 8 − 448 y 5 + 16 y 2
Expression ( Integer )
See Section 1.10 on page 49 and Section 1.11 on page 51 for more examples of expressions and calculus.
Differential equations involving expressions are discussed in Section 8.10 on page 296. Chapter 8 has
many advanced examples: see Section 8.8 on page 279 for a discussion of FriCAS’s integration facilities.
When an expression involves no “symbol kernels” (for example, x), it may be possible to numeri-
cally evaluate the expression. If you suspect the evaluation will create a complex number, use
complexNumeric.
comp lexNumer ic ( cos (2 - 3*% i ) )
Complex(Float)
0.77355609050312607286 (18)
Float
The numeric operation will display an error message if the evaluation yields a value with an non-zero
imaginary part. Both of these operations have an optional second argument n which specifies that the
accuracy of the approximation be up to n decimal places.
When an expression involves no “symbolic application” kernels, it may be possible to convert it a
polynomial or rational function in the variables that are present.
e2 := cos ( x ^2 - y + 3)
cos y − x2 − 3
(19)
Expression ( Integer )
e3 := asin ( e2 ) - % pi /2
2 arcsin cos y − x2 − 3
−π
(20)
2
Expression ( Integer )
e4 := normalize ( e3 )
404 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
− y + x2 + 3 (21)
Expression ( Integer )
e4 :: Polynomial Integer
− y + x2 + 3 (22)
Polynomial( Integer )
This also works for the polynomial types where specific variables and their ordering are given.
e4 :: DMP ([ x , y ] , Integer )
x2 − y + 3 (23)
DistributedMultivariatePolynomial ([ x, y ], Integer )
0 (24)
Expression ( Integer )
cos (% pi / 4)
√
2
(25)
2
Expression ( Integer )
For simplications that involve multiple terms of the expression, use simplify.
tan ( x ) ^6 + 3* tan ( x ) ^4 + 3* tan ( x ) ^2 + 1
Expression ( Integer )
simplify %
1
(27)
cos(x)6
Expression ( Integer )
See Section 6.21 on page 187 for examples of how to write your own rewrite rules for expressions.
9.22. FACTORED 405
9.22 Factored
Factored creates a domain whose objects are kept in factored form as long as possible. Thus certain
operations like * (multiplication) and gcd are relatively easy to do. Others, such as addition, require
somewhat more work, and the result may not be completely factored unless the argument domain R
provides a factor operation. Each object consists of a unit and a list of factors, where each factor
consists of a member of R (the base), an exponent, and a flag indicating what is known about the
base. A flag may be one of "nil", "sqfr", "irred" or "prime", which mean that nothing is known
about the base, it is square-free, it is irreducible, or it is prime, respectively. The current restriction
to factored objects of integral domains allows simplification to be performed without worrying about
multiplication order.
23 72 11 (1)
Factored( Integer )
Let’s begin by decomposing g into pieces. The only possible units for integers are 1 and -1.
unit ( g )
1 (2)
PositiveInteger
3 (3)
PositiveInteger
List ( Integer )
[3, 2, 1] (5)
406 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
List (NonNegativeInteger)
and the flags. You can see that all the bases (factors) are prime.
[ i . flag for i in factorList ( g ) ]
A useful operation for pulling apart a factored object into a list of records of the components is
factorList.
factorList ( g )
List (Record(flag : Union(”nil ”, ” sqfr ”, ” irred ”, ”prime”), factor : Integer , exponent: NonNegativeInteger))
[[f actor = 2, exponent = 3] , [f actor = 7, exponent = 2] , [f actor = 11, exponent = 1]] (8)
2 (9)
PositiveInteger
23 72 11 (1)
Factored( Integer )
4312 (2)
9.22. FACTORED 407
PositiveInteger
If you would like, say, the distinct factors multiplied together but with multiplicity one, you could do
it this way.
reduce (* ,[ t . factor for t in factors ( g ) ])
154 (3)
PositiveInteger
23 72 11 (1)
Factored( Integer )
24 32 5 73 (2)
Factored( Integer )
Operations involving multiplication and division are particularly easy with factored objects.
f * g
27 32 5 75 11 (3)
Factored( Integer )
f ^500
Factored( Integer )
gcd (f , g )
23 72 (5)
Factored( Integer )
lcm (f , g )
24 32 5 73 11 (6)
408 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Factored( Integer )
If we use addition and subtraction things can slow down because we may need to compute greatest
common divisors.
f + g
23 72 641 (7)
Factored( Integer )
f - g
23 72 619 (8)
Factored( Integer )
Test for equality with 0 and 1 by using zero? and one?, respectively.
zero ?( factor (0) )
true (9)
Boolean
zero ?( g )
false (10)
Boolean
one ?( factor (1) )
true (11)
Boolean
one ?( f )
false (12)
Boolean
Another way to get the zero and one factored objects is to use package calling (see Section 2.9 on page
89).
0 $ Factored ( Integer )
0 (13)
Factored( Integer )
1 $ Factored ( Integer )
9.22. FACTORED 409
1 (14)
Factored( Integer )
The map operation is used to iterate across the unit and bases of a factored object. See ‘FactoredFunctions2’
on page 411 for a discussion of map.
The following four operations take a base and an exponent and create a factored object. They differ
in handling the flag component.
nilFactor (24 ,2)
242 (1)
Factored( Integer )
"nil" (2)
Union(”nil ”, ...)
302 (3)
Factored( Integer )
1310 (4)
Factored( Integer )
115 (5)
Factored( Integer )
− 24 32 5 (6)
Factored( Integer )
The first argument is the unit and the second is a list of records as returned by factorList.
h - makeFR ( unit ( h ) , factorList ( h ) )
0 (7)
Factored( Integer )
Some of the operations available for polynomials are also available for factored polynomials.
p := (4* x *x -12* x +9) * y * y + (4* x *x -12* x +9) * y + 28* x * x - 84* x + 63
4 x2 − 12 x + 9 y 2 + 4 x2 − 12 x + 9 y + 28 x2 − 84 x + 63
(1)
Polynomial( Integer )
fp := factor ( p )
(2 x − 3)2 y 2 + y + 7
(2)
Factored(Polynomial( Integer ))
Polynomial( Integer )
D ( fp , x )
4 (2 x − 3) y 2 + y + 7
(4)
Factored(Polynomial( Integer ))
n um be rO f Fa ct or s (%)
2 (5)
PositiveInteger
9.23. FACTOREDFUNCTIONS2 411
9.23 FactoredFunctions2
The FactoredFunctions2 package implements one operation, map, for applying an operation to every
base in a factored object and to the unit.
double ( x ) == x + x
f := factor (720)
24 32 5 (5)
Factored( Integer )
Actually, the map operation used in this example comes from Factored itself, since double takes an
integer argument and returns an integer result.
map ( double , f )
Compiling function double with type Integer -> Integer
2 44 62 10 (6)
Factored( Integer )
If we want to use an operation that returns an object that has a type different from the operation’s
argument, the map in Factored cannot be used and we use the one in FactoredFunctions2.
makePoly ( b ) == x + b
In fact, the “2” in the name of the package means that we might be using factored objects of two
different types.
g := map ( makePoly , f )
Compiling function makePoly with type Integer -> Polynomial ( Integer )
Factored(Polynomial( Integer ))
It is important to note that both versions of map destroy any information known about the bases (the
fact that they are prime, for instance). The flags for each base are set to “nil” in the object returned
by map.
factorList ( g ) .1. flag
"nil" (9)
Union(”nil ”, ...)
For more information about factored objects and their use, see ‘Factored’ on page 405 and Section
8.13 on page 325.
412 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
9.24 File
The File(S) domain provides a basic interface to read and write values of type S in files. Before
working with a file, it must be made accessible to FriCAS with the open operation.
ifile : File List Integer := open ("/ tmp / jazz1 " ," output ")
"/tmp/jazz1" (4)
The open function arguments are a FileName and a String specifying the mode. If a full pathname is
not specified, the current default directory is assumed. The mode must be one of "input" or "output".
If it is not specified, "input" is assumed. Once the file has been opened, you can read or write data.
The operations read! and write! are provided.
write !( ifile , [ -1 ,2 ,3])
[−1, 2, 3] (5)
List ( Integer )
List ( Integer )
[7] (7)
List ( Integer )
You can change from writing to reading (or vice versa) by reopening a file.
reopen !( ifile , " input ")
"/tmp/jazz1" (8)
read ! ifile
[−1, 2, 3] (9)
List ( Integer )
read ! ifile
List ( Integer )
The read! operation can cause an error if one tries to read more data than is in the file. To guard
against this possibility the readIfCan! operation should be used.
readIfCan ! ifile
[7] (11)
readIfCan ! ifile
"failed" (12)
You can find the current mode of the file, and the file’s name.
iomode ifile
"input" (13)
String
name ifile
"/tmp/jazz1" (14)
FileName
When you are finished with a file, you should close it.
close ! ifile
"/tmp/jazz1" (15)
A limitation of the underlying LISP system is that not all values can be represented in a file. In
particular, delayed values containing compiled functions cannot be saved.
For more information on related topics, see ‘TextFile’ on page 592, ‘KeyedAccessFile’ on page 457,
‘Library’ on page 474, and ‘FileName’ on page 413. Issue the system command )show File to display
the full list of operations defined by File.
9.25 FileName
The FileName domain provides an interface to the computer’s file system. Functions are provided to
manipulate file names and to test properties of files.
The simplest way to use file names in the FriCAS interpreter is to rely on conversion to and from
strings. The syntax of these strings depends on the operating system.
414 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
fn : FileName
"/spad/src/input/fname.input" (5)
FileName
Although it is very convenient to be able to use string notation for file names in the interpreter, it is
desirable to have a portable way of creating and manipulating file names from within programs. A
measure of portability is obtained by considering a file name to consist of three parts: the directory,
the name, and the extension.
directory fn
"/spad/src/input" (6)
String
name fn
"fname" (7)
String
extension fn
"input" (8)
String
The meaning of these three parts depends on the operating system. For example, on CMS the file
"SPADPROF INPUT M" would have directory "M", name "SPADPROF" and extension "INPUT".
It is possible to create a filename from its parts.
fn := filename ("/ u / smwatt / work " , " fname " , " input ")
"/u/smwatt/work/fname.input" (9)
FileName
"/tmp" (10)
String
"/tmp/table.spad" (11)
9.25. FILENAME 415
FileName
If the directory or the extension is given as an empty string, then a default is used. On AIX, the
defaults are the current directory and no extension.
fn := filename ("" , " letter " , "")
"letter" (12)
FileName
Three tests provide information about names in the file system. The exists? operation tests whether
the named file exists.
exists ? "/ etc / passwd "
true (13)
Boolean
The operation readable? tells whether the named file can be read. If the file does not exist, then it
cannot be read.
readable ? "/ etc / passwd "
true (14)
Boolean
readable ? "/ etc / security / passwd "
false (15)
Boolean
readable ? "/ etc / passwd "
true (16)
Boolean
Likewise, the operation writable? tells whether the named file can be written. If the file does not exist,
the test is determined by the properties of the directory.
writable ? "/ etc / passwd "
false (17)
Boolean
writable ? "/ dev / null "
true (18)
416 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Boolean
writable ? "/ etc / DoesNotExist "
false (19)
Boolean
writable ? "/ tmp / DoesNotExist "
true (20)
Boolean
The new operation constructs the name of a new writable file. The argument sequence is the same
as for filename, except that the name part is actually a prefix for a constructed unique name. The
resulting file is in the specified directory with the given extension, and the same defaults are used.
fn := new ( objdir , " xxx " , " yy ")
"/tmp/xxx20.yy" (21)
FileName
9.26 FlexibleArray
The FlexibleArray domain constructor creates one-dimensional arrays of elements of the same type.
Flexible arrays are an attempt to provide a data type that has the best features of both one-dimensional
arrays (fast, random access to elements) and lists (flexibility). They are implemented by a fixed block
of storage. When necessary for expansion, a new, larger block of storage is allocated and the elements
from the old storage area are copied into the new block.
Flexible arrays have available most of the operations provided by OneDimensionalArray (see ‘OneDimensionalArray’
on page 518 and ‘Vector’ on page 604). Since flexible arrays are also of category ExtensibleLinearAg-
gregate, they have operations concat!, delete!, insert!, merge!, remove!, removeDuplicates!, and select!.
In addition, the operations physicalLength and physicalLength! provide user-control over expansion and
contraction.
A convenient way to create a flexible array is to apply the operation flexibleArray to a list of values.
flexibleArray [ i for i in 1..6]
[1, 2, 3, 4, 5, 6] (4)
FlexibleArray ( PositiveInteger )
[0, 0, 0, 0, 0, 0] (5)
9.26. FLEXIBLEARRAY 417
FlexibleArray ( Integer )
[1, 2, 3, 4, 5, 6] (6)
FlexibleArray ( Integer )
6 (7)
PositiveInteger
FlexibleArray ( Integer )
10 (9)
PositiveInteger
FlexibleArray ( Integer )
Concatenate the elements of f to itself. The physical length allows room for three more values at the
end.
concat !( f , f )
FlexibleArray ( Integer )
FlexibleArray ( Integer )
Create a second flexible array from f consisting of the elements from index 10 forward.
g := f (10..)
FlexibleArray ( Integer )
FlexibleArray ( Integer )
FlexibleArray ( Integer )
FlexibleArray ( Integer )
FlexibleArray ( Integer )
8 (18)
PositiveInteger
To force FriCAS not to shrink flexible arrays call the shrinkable operation with the argument false.
You must package call this operation. The previous value is returned.
shrinkable ( false ) $ Flex ibleArr ay ( Integer )
9.27. FLOAT 419
true (19)
Boolean
9.27 Float
FriCAS provides two kinds of floating point numbers. The domain Float (abbreviation FLOAT)
implements a model of arbitrary precision floating point numbers. The domain DoubleFloat (abbre-
viation DFLOAT) is intended to make available hardware floating point arithmetic in FriCAS. The
actual model of floating point that DoubleFloat provides is system-dependent. For example, on the
IBM system 370 FriCAS uses IBM double precision which has fourteen hexadecimal digits of precision
or roughly sixteen decimal digits. Arbitrary precision floats allow the user to specify the precision at
which arithmetic operations are computed. Although this is an attractive facility, it comes at a cost.
Arbitrary-precision floating-point arithmetic typically takes twenty to two hundred times more time
than hardware floating point.
For more information about FriCAS’s numeric and graphic facilities, see Section 7 on page 195, Section
8.1 on page 251, and ‘DoubleFloat’ on page 395.
Scientific notation is supported for input and output of floating point numbers. A floating point number
is written as a string of digits containing a decimal point optionally followed by the letter “E”, and
then the exponent. We begin by doing some calculations using arbitrary precision floats. The default
precision is twenty decimal digits.
1.234
1.234 (1)
Float
A decimal base for the exponent is assumed, so the number 1.234E2 denotes 1.234 · 102 .
1.234 E2
123.4 (2)
Float
The normal arithmetic operations are available for floating point numbers.
sqrt (1.2 + 2.3 / 3.4 ^ 4.5)
1.0996972790671286226 (3)
Float
420 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
You can use conversion (Section 2.7 on page 84) to go back and forth between Integer, Fraction
Integer and Float, as appropriate.
i := 3 :: Float
3.0 (1)
Float
i :: Integer
3 (2)
Integer
i :: Fraction Integer
3 (3)
Fraction ( Integer )
Since you are explicitly asking for a conversion, you must take responsibility for any loss of exactness.
r := 3/7 :: Float
0.42857142857142857143 (4)
Float
r :: Fraction Integer
3
(5)
7
Fraction ( Integer )
This conversion cannot be performed: use truncate or round if that is what you intend.
r :: Integer
Cannot convert the value from type Float to Integer .
3.0 (6)
Float
4.0 (7)
Float
truncate ( -3.6)
− 3.0 (8)
Float
round ( -3.6)
− 4.0 (9)
Float
The operation fractionPart computes the fractional part of x, that is, x - truncate x.
fractionPart 3.6
0.6 (10)
Float
The operation digits allows the user to set the precision. It returns the previous value it was using.
digits 40
20 (11)
PositiveInteger
sqrt 0.2
0.4472135954999579392818347337462552470881 (12)
Float
pi () $ Float
3.141592653589793238462643383279502884197 (13)
Float
The precision is only limited by the computer memory available. Calculations at 500 or more digits of
precision are not difficult.
digits 500
40 (14)
PositiveInteger
pi () $ Float
422 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328
(15)
Float
500 (16)
PositiveInteger
Numbers of type Float are represented as a record of two integers, namely, the mantissa and the
exponent where the base of the exponent is binary. That is, the floating point number (m,e) represents
the number m · 2e . A consequence of using a binary base is that decimal numbers can not, in general,
be represented exactly.
A number of operations exist for specifying how numbers of type Float are to be displayed. By default,
spaces are inserted every ten digits in the output for readability.3
Output spacing can be modified with the outputSpacing operation. This inserts no spaces and then
displays the value of x.
outputSpacing 0; x := sqrt 0.2
0.44721359549995793928 (1)
Float
0.44721359549995793928 (2)
Float
By default, the system displays floats in either fixed format or scientific format, depending on the
magnitude of the number.
y := x /10^10
0.44721359549995793928E − 10 (3)
Float
A particular format may be requested with the operations outputFloating and outputFixed.
outp utFloati ng () ; x
3 Note that you cannot include spaces in the input form of a floating point number, though you can use underscores.
9.27. FLOAT 423
0.44721359549995793928E0 (4)
Float
outputFixed () ; y
0.000000000044721359549995793928 (5)
Float
Additionally, you can ask for n digits to be displayed after the decimal point.
outp utFloati ng 2; y
0.45E − 10 (6)
Float
outputFixed 2; x
0.45 (7)
Float
1 1 1 1 1 1 1 1 1
1 2 3 4 5 6 7 8 9 10
1 1 1 1 1 1 1 1 1 1
21 3
1
4
1
5
1
6
1
7
1
8
1
9
1
10
1
11
1
31 4
1
5
1
6
1
7
1
8
1
9
1
10
1
11
1
12
1
41 5
1
6
1
7
1
8
1
9
1
10
1
11
1
12
1
13
1
51 6
1
7
1
8
1
9
1
10
1
11
1
12
1
13
1
14
1 (1)
61 7
1
8
1
9
1
10
1
11
1
12
1
13
1
14
1
15
1
71 8
1
9
1
10
1
11
1
12
1
13
1
14
1
15
1
16
1
8 9 10 11 12 13 14 15 16 17
1 1 1 1 1 1 1 1 1 1
9 10 11 12 13 14 15 16 17 18
1 1 1 1 1 1 1 1 1 1
10 11 12 13 14 15 16 17 18 19
Matrix(Fraction ( Integer ))
1
(2)
46206893947914691316295628839036278726983680000000000
Fraction ( Integer )
d :: Float
0.21641792264314918691E − 52 (3)
Float
Now use hardware floats. Note that a semicolon (;) is used to prevent the display of the matrix.
b : Matrix DoubleFloat := matrix [[1/( i + j +1 $ DoubleFloat ) for j in 0..9] for i in 0..9];
Matrix(DoubleFloat)
The result given by hardware floats is correct only to four significant digits of precision. In the jargon
of numerical analysis, the Hilbert matrix is said to be “ill-conditioned.”
determinant b
2.164367794572141e-53 (5)
DoubleFloat
20 (6)
PositiveInteger
determinant c
0.2164179226431491869060594983622617436159E − 52 (8)
Float
40 (9)
PositiveInteger
9.28 Fraction
The Fraction domain implements quotients. The elements must belong to a domain of category
IntegralDomain: multiplication must be commutative and the product of two non-zero elements
9.28. FRACTION 425
must not be zero. This allows you to make fractions of most things you would think of, but don’t
expect to create a fraction of two matrices! The abbreviation for Fraction is FRAC.
Use / to create a fraction.
a := 11/12
11
(4)
12
Fraction ( Integer )
b := 23/24
23
(5)
24
Fraction ( Integer )
313271
(6)
76032
Fraction ( Integer )
Extract the numerator and denominator by using numer and denom, respectively.
numer ( a )
11 (7)
PositiveInteger
denom ( b )
24 (8)
PositiveInteger
Operations like max, min, negative?, positive? and zero? are all available if they are provided for the
numerators and denominators. See ‘Integer’ on page 441 for examples.
Don’t expect a useful answer from factor, gcd or lcm if you apply them to fractions.
r := ( x ^2 + 2* x + 1) /( x ^2 - 2* x + 1)
x2 + 2 x + 1
(9)
x2 − 2 x + 1
Fraction (Polynomial( Integer ))
Since all non-zero fractions are invertible, these operations have trivial definitions.
factor ( r )
426 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
x2 + 2 x + 1
(10)
x2 − 2 x + 1
Factored( Fraction (Polynomial( Integer )))
Use map to apply factor to the numerator and denominator, which is probably what you mean.
map ( factor , r )
(x + 1)2
(11)
(x − 1)2
Other forms of fractions are available. Use continuedFraction to create a continued fraction.
c o n t i n u e d F r a c t i o n (7/12)
1| 1| 1| 1|
+ + + (12)
|1 |1 |2 |2
ContinuedFraction( Integer )
Use partialFraction to create a partial fraction. See ‘ContinuedFraction’ on page 375 and ‘PartialFraction’
on page 530 for additional information and examples.
p ar ti al F ra ct io n (7 ,12)
1 1
+ (13)
22 3
PartialFraction ( Integer )
Use conversion to create alternative views of fractions with objects moved in and out of the numerator
and denominator.
g := 2/3 + 4/5*% i
2 4
+ i (14)
3 5
Complex(Fraction(Integer))
10 + 12 i
(15)
15
Fraction (Complex(Integer))
9.29. FREEMAGMA 427
9.29 FreeMagma
Initialisations
x : Symbol := ’ x
x (4)
Symbol
y : Symbol := ’ y
y (5)
Symbol
z : Symbol := ’ z
z (6)
Symbol
FreeMonoid(Symbol) (7)
Type
FreeMagma(Symbol) (8)
Type
[x, x] (9)
FreeMagma(Symbol)
b : tree := y * y
[y, y] (10)
FreeMagma(Symbol)
c : tree := a * b
FreeMagma(Symbol)
[x, x] (12)
FreeMagma(Symbol)
right c
[y, y] (13)
FreeMagma(Symbol)
length c
4 (14)
PositiveInteger
x2 y 2 (15)
FreeMonoid(Symbol)
Check ordering
a < b
true (16)
Boolean
a < c
true (17)
Boolean
b < c
true (18)
Boolean
x (19)
9.30. FULLPARTIALFRACTIONEXPANSION 429
Symbol
rest c
FreeMagma(Symbol)
rest rest c
[y, y] (21)
FreeMagma(Symbol)
Check ordering
ax : tree := a * x
[[x, x] , x] (22)
FreeMagma(Symbol)
xa : tree := x * a
FreeMagma(Symbol)
xa < ax
true (24)
Boolean
lexico ( xa , ax )
false (25)
Boolean
9.30 FullPartialFractionExpansion
The domain FullPartialFractionExpansion implements factor-free conversion of quotients to full
partial fractions.
Our examples will all involve quotients of univariate polynomials with rational number coefficients.
Fx := FRAC UP (x , FRAC INT )
Type
36
(5)
x5 − 2 x4 − 2 x3 + 4 x2 + x − 2
Fraction ( UnivariatePolynomial (x, Fraction ( Integer )))
4 4 X −3 %A − 6
− + (6)
x−2 x+1
%A2 −1 =0
(x − %A)2
36
(7)
x5 − 2 x4 − 2 x3 + 4 x2 + x − 2
Fraction ( UnivariatePolynomial (x, Fraction ( Integer )))
f5 := D (f , 5)
We can check that the two forms represent the same function.
g5 :: Fx - f5
0 (10)
x6 − x5
(11)
x7 − 4 x6 + 3 x5 + 9 x3 − 6 x2 − 4 x − 8
Fraction ( UnivariatePolynomial (x, Fraction ( Integer )))
g := f u l l P a r t i a l F r a c t i o n f
g :: Fx - f
0 (13)
2 x7 − 7 x5 + 26 x3 + 8 x
(14)
x8 − 5 x6 + 6 x4 + 4 x2 − 8
Fraction ( UnivariatePolynomial (x, Fraction ( Integer )))
g := f u l l P a r t i a l F r a c t i o n f
1 1
X
2
X 1 X
2
+ 3 + (15)
x − %A (x − %A) x − %A
%A2 −2 =0 %A2 −2 =0 2
%A +1 =0
g :: Fx - f
0 (16)
f : Fx := x ^3 / ( x ^21 + 2* x ^20 + 4* x ^19 + 7* x ^18 + 10* x ^17 + 17* x ^16 + 22* x ^15 +
30* x ^14 + 36* x ^13 + 40* x ^12 + 47* x ^11 + 46* x ^10 + 49* x ^9 + 43* x ^8 + 38* x ^7 +
32* x ^6 + 23* x ^5 + 19* x ^4 + 10* x ^3 + 7* x ^2 + 2* x + 1)
x3
(17)
x21 + 2 x20 + 4 x19 + 7 x18 + 10 x17 + 17 x16 + 22 x15 + 30 x14 + 36 x13 + 40 x12 + 47 x11 + 46 x10 + 49 x9 + 43 x8 + 38 x7 + 32 x6 + 2
Fraction ( UnivariatePolynomial (x, Fraction ( Integer )))
g := f u l l P a r t i a l F r a c t i o n f
432 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
1 1
X
2
%A X
9
%A − 19
27
X 1
27
%A − 1
27
+ + 2
x − %A x − %A (x − %A)
%A2 +1 =0 %A2 +%A+1 =0 %A2 +%A+1 =0
X 96556567040
− 912390759099 %A4 + 420961732891
912390759099
%A3 − 912390759099
59101056149
%A2 − 373545875923
912390759099
%A + 529673492498
912390759099
+
x − %A
%A5 +%A2 +1 =0
4 3
X 5580868
− 94070601 %A − 2024443
94070601
%A + 4321919
94070601
%A2 − 84614
1542141
%A − 5070620
94070601
+ 2
%A5 +%A2 +1 =0
(x − %A)
4 3
X 1610957
94070601
%A + 2763014
94070601
%A − 2016775
94070601
%A2 + 266953
94070601
%A + 4529359
94070601
+
%A5 +%A2 +1 =0
(x − %A)3
(18)
This verification takes much longer than the conversion to partial fractions.
g :: Fx - f
0 (19)
For more information, see the paper: Bronstein, M and Salvy, B. “Full Partial Fraction Decomposition
of Rational Functions,” Proceedings of ISSAC’93, Kiev, ACM Press. All see ‘PartialFraction’ on
page 530 for standard partial fraction decompositions.
9.31 GeneralQuaternion
The domain constructor GeneralQuaternion implements general quaternions over commutative
rings. For information on related topics, see ‘Quaternion’ on page 540, ‘Complex’ on page 372 and
‘Octonion’ on page 516. You can also issue the system command )show GeneralQuaternion to display
the full list of operations defined by GeneralQuaternion.
To use general quaternions we need to explicitly qualify calls. So first we assign initialize domain and
assign it to a variable.
Q2 := G e n e r a l Q u a t e r n i o n ( Fraction ( Integer ) , 2 , 3)
GeneralQuaternion(Fraction(Integer), 2, 3) (4)
Type
i (5)
GeneralQuaternion(Fraction( Integer ) , 2, 3)
2 (6)
GeneralQuaternion(Fraction( Integer ) , 2, 3)
Similarly for b.
( quatern (0 , 0 , 1 , 0) $ Q2 ) ^2
3 (7)
GeneralQuaternion(Fraction( Integer ) , 2, 3)
2 3
− 8i + j + k (8)
11 4
GeneralQuaternion(Fraction( Integer ) , 2, 3)
Because q is over the rationals (and nonzero), you can invert it.
iq := inv q
1 (10)
GeneralQuaternion(Fraction( Integer ) , 2, 3)
20 119
− − 5i + j − 88 k (12)
11 36
GeneralQuaternion(Fraction( Integer ) , 2, 3)
2495 817
i + 2836 j − k (13)
6 18
GeneralQuaternion(Fraction( Integer ) , 2, 3)
The norm is the quaternion times its conjugate. Norm is rational, but may be negative.
norm q
239395
− (14)
1936
Fraction ( Integer )
conjugate q
2 3
+ 8i − j − k (15)
11 4
GeneralQuaternion(Fraction( Integer ) , 2, 3)
q * %
239395
− (16)
1936
GeneralQuaternion(Fraction( Integer ) , 2, 3)
9.32 GeneralSparseTable
Sometimes when working with tables there is a natural value to use as the entry in all but a few cases.
The GeneralSparseTable constructor can be used to provide any table type with a default value
for entries. See ‘Table’ on page 589 for general information about tables. Issue the system command
)show GeneralSparseTable to display the full list of operations defined by GeneralSparseTable.
Suppose we launched a fund-raising campaign to raise fifty thousand dollars. To record the contribu-
tions, we want a table with strings as keys (for the names) and integer entries (for the amount). In a
data base of cash contributions, unless someone has been explicitly entered, it is reasonable to assume
they have made a zero dollar contribution. This creates a keyed access file with default entry 0.
patrons : G e n e r a l S p a r s e T a b l e ( String , Integer , K ey ed A cc es s Fi le ( Integer ) , 0) := table () ;
GeneralSparseTable( String , Integer , KeyedAccessFile( Integer ) , 0)
Now patrons can be used just as any other table. Here we record two gifts.
patrons ." Smith " := 10500
10500 (5)
PositiveInteger
22000 (6)
PositiveInteger
Now let us look up the size of the contributions from Jones and Stingy.
patrons ." Jones "
22000 (7)
PositiveInteger
0 (8)
NonNegativeInteger
32500 (9)
PositiveInteger
9.33 GroebnerFactorizationPackage
Solving systems of polynomial equations with the Gröbner basis algorithm can often be very time
consuming because, in general, the algorithm has exponential run-time. These systems, which often
come from concrete applications, frequently have symmetries which are not taken advantage of by the
algorithm. However, it often happens in this case that the polynomials which occur during the Gröbner
calculations are reducible. Since FriCAS has an excellent polynomial factorization algorithm, it is very
natural to combine the Gröbner and factorization algorithms.
GroebnerFactorizationPackage exports the groebnerFactorize operation which implements a mod-
ified Gröbner basis algorithm. In this algorithm, each polynomial that is to be put into the partial
list of the basis is first factored. The remaining calculation is split into as many parts as there are
irreducible factors. Call these factors p1 , . . . , pn . In the branches corresponding to p2 , . . . , pn , the factor
p1 can be divided out, and so on. This package also contains operations that allow you to specify the
polynomials that are not zero on the common roots of the final Gröbner basis.
Here is an example from chemistry. In a theoretical model of the cyclohexan C6 H12 , the six carbon
atoms each sit in the center of gravity of a tetrahedron that has two hydrogen atoms and two carbon
atoms at its corners. We first normalize and set the length of each edge to 1. Hence, the distances of
one fixed carbon atom to each of its immediate neighbours is 1. We will denote the distances to the
other three carbon atoms by x, y and z.
436 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
A. Dress developed a theory to decide whether a set of points and distances between them can be
realized in an n-dimensional space. Here, of course, we have n = 3.
mfzn : SQMATRIX (6 , DMP ([ x ,y , z ] , Fraction INT ) ) := [[0 ,1 ,1 ,1 ,1 ,1] , [1 ,0 ,1 ,8/3 , x ,8/3] ,
[1 ,1 ,0 ,1 ,8/3 , y ] , [1 ,8/3 ,1 ,0 ,1 ,8/3] , [1 ,x ,8/3 ,1 ,0 ,1] , [1 ,8/3 , y ,8/3 ,1 ,0]]
0 1 1 1 1 1
1 8 8
0 1 3
x 3
1 8
1 0 1 3
y
1 8 8
(4)
3
1 0 1 3
1 8
x 3
1 0 1
8 8
1 3
y 3
1 0
They also must satisfy the equations given by cyclic shifts of the indeterminates.
g r o e b n e r F a c t o r i z e [ eq , eval ( eq , [x ,y , z ] , [y ,z , x ]) , eval ( eq , [x ,y , z ] , [z ,x , y ]) ]
22 22 22 121
xy + xz − x+yz − y− z+ ,
3 3 3 3
22 25 22 25 22 2 388 250
x z2 − xz + x + y z2 − yz + y− z + z+ ,
3 9 3 9 3 9 27
22 2 25 2 22 388 250 25 2 250 14575 21994 (6)
y2 z2 − y z+ y − y z2 + yz+ y+ z + z− , x+y− ,
3 9 3 9 27 9 27 81 5625
21994 4427 463 1 11 5 265 38 265 25
y2 − y+ , z− , x2 − x z − x− z + , y − z, z 2 − z+ , x− ,
5625 675 87 2 2 6 18 3 9 9
11 11 11 11 11 5 5 5 19 5 5
y− , z− , x− , y− , z− , x+ , y+ , z+ , x− , y+ , z+
3 3 3 3 3 3 3 3 3 3 3
The union of the solutions of this list is the solution of our original problem. If we impose positivity
conditions, we get two relevant ideals. One ideal is zero-dimensional, namely x = y = z = 11/3, and
this determines the “boat” form of the cyclohexan. The other ideal is one-dimensional, which means
that we have a solution space given by one parameter. This gives the “chair” form of the cyclohexan.
The parameter describes the angle of the “back of the chair.”
groebnerFactorize has an optional Boolean-valued second argument. When it is true partial results
are displayed, since it may happen that the calculation does not terminate in a reasonable time. See
the source code for GroebnerFactorizationPackage in groebf.spad for more details about the
algorithms used.
9.34. GROUPPRESENTATION 437
9.34 GroupPresentation
The domain GroupPresentation implements group presentations.
We first expose it to simplify notation.
) expose G r o u p P r e s e n t a t i o n
G r o u p P r e s e n t a t i o n is now explicitly exposed in frame initial
GroupPresentation
Union(PermutationGroup(Integer), ...)
FreeGroup(Symbol) (6)
Type
a := (^ $ fG ) ( ’a , 1)
a (7)
FreeGroup(Symbol)
b := (^ $ fG ) ( ’b , 1)
b (8)
FreeGroup(Symbol)
c := (^ $ fG ) ( ’c , 1)
c (9)
FreeGroup(Symbol)
List (FreeGroup(Symbol))
cP := G r o u p P r e s e n t a t i o n F u n c t i o n s 1 ( Symbol )
GroupPresentationFunctions1(Symbol) (11)
Type
And convert it to permutation group. Since Mathieu group has many elements we compute represen-
tation on cosets of group generated by a and b.
m12per := t o P e r m u t a t i o n I f C a n ( m12pres , [[1] , [2]] , false )
Union(PermutationGroup(Integer), ...)
95040 (14)
PositiveInteger
9.35 GuessPolynomialInteger
The package GuessPolynomialInteger can guess formulas for sequences of polynomials or rational
functions over integers, given the first few terms. Related packages are GuessInteger for sequences
of rational numbers or rational functions, GuessAlgebraicNumber when sequences contain ale-
braic numbers, GuessPolynomial for polynomials and rational functions with general coefficients
and Guess (general version).
Below we show how to guess recurence relation for squares of Hermite polynomials.
We first need to prepare data.
hl := [ hermiteH (i , x ) ^2 for i in 0..15];
9.36. HEAP 439
9.36 Heap
The domain Heap(S) implements a priority queue of objects of type S such that the operation extract!
removes and returns the maximum element. The implementation represents heaps as flexible arrays
(see ‘FlexibleArray’ on page 416). The representation and algorithms give complexity of O(log(n))
for insertion and extractions, and O(n) for construction.
Create a heap of six elements.
h := heap [ -4 ,9 ,11 ,2 ,7 , -7]
Heap(Integer)
Heap(Integer)
11 (6)
PositiveInteger
Heap(Integer)
Now extract! elements repeatedly until none are left, collecting the elements in a list.
[ extract !( h ) while not empty ?( h ) ]
440 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
List ( Integer )
Heap(Integer)
List ( Integer )
9.37 HexadecimalExpansion
All rationals have repeating hexadecimal expansions. The operation hex returns these expansions
of type HexadecimalExpansion. Operations to access the individual numerals of a hexadecimal
expansion can be obtained by converting the value to RadixExpansion(16). More examples of
expansions are available in the ‘DecimalExpansion’ on page 388, ‘BinaryExpansion’ on page 348, and
‘RadixExpansion’ on page 542.
Issue the system command )show HexadecimalExpansion to display the full list of operations defined
by HexadecimalExpansion.
This is a hexadecimal expansion of a rational number.
r := hex (22/7)
3.249 (4)
HexadecimalExpansion
Arithmetic is exact.
r + hex (6/7)
4 (5)
HexadecimalExpansion
0.00BB3EE721A54D88, 0.00BAB6561, 0.00BA2E8, (6)
0.00B9A7862A0FF465879D5F, 0.00B92143FA36F5E02E4850FE8DBD78
List (HexadecimalExpansion)
or very long!
hex (1/1007)
0.0041149783F0BF2C7D13933192AF6980619EE345E91EC2BB9D5CCA5C071E40926E54E8DDAE24196C0B2F8A0AAD60DBA57F5D4C8536262210
(7)
HexadecimalExpansion
Polynomial(HexadecimalExpansion)
q := D (p , x )
Polynomial(HexadecimalExpansion)
g := gcd (p , q )
x + 1.5 (10)
Polynomial(HexadecimalExpansion)
9.38 Integer
FriCAS provides many operations for manipulating arbitrary precision integers. In this section we will
show some of those that come from Integer itself plus some that are implemented in other packages.
More examples of using integers are in the following sections: ‘Some Numbers’ in Section 1.5 on page 31,
‘IntegerNumberTheoryFunctions’ on page 450, ‘DecimalExpansion’ on page 388, ‘BinaryExpansion’
on page 348, ‘HexadecimalExpansion’ on page 440, and ‘RadixExpansion’ on page 542.
The size of an integer in FriCAS is only limited by the amount of computer storage you have available.
The usual arithmetic operations are available.
2^(5678 - 4856 + 2 * 17)
442 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
480481077043500814718154092512592439123952613987168226347385561008808420007630829308634252709141208374307457227821
(1)
PositiveInteger
There are a number of ways of working with the sign of an integer. Let’s use this x as an example.
x := -101
− 101 (2)
Integer
101 (3)
PositiveInteger
The sign operation returns -1 if its argument is negative, 0 if zero and 1 if positive.
sign ( x )
−1 (4)
Integer
true (5)
Boolean
x <= -1
true (6)
Boolean
negative ?( x )
true (7)
Boolean
false (8)
9.38. INTEGER 443
Boolean
x >= 1
false (9)
Boolean
positive ?( x )
false (10)
Boolean
false (11)
Boolean
Use the zero? operation whenever you are testing any mathematical object for equality with zero.
This is usually more efficient that using = (think of matrices: it is easier to tell if a matrix is zero
by just checking term by term than constructing another “zero” matrix and comparing the two
matrices term by term) and also avoids the problem that = is usually used for creating equations.
false (12)
Boolean
This syntax is used to test equality using =. It says that you want a Boolean (true or false) answer
rather than an equation.
( x = -101) @Boolean
true (13)
Boolean
The operations odd? and even? determine whether an integer is odd or even, respectively. They each
return a Boolean object.
odd ?( x )
true (14)
Boolean
even ?( x )
444 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
false (15)
Boolean
The operation gcd computes the greatest common divisor of two integers.
gcd (56788 ,43688)
4 (16)
PositiveInteger
620238536 (17)
PositiveInteger
678 (18)
PositiveInteger
567 (19)
PositiveInteger
The reduce operation is used to extend binary operations to more than two arguments. For example,
you can use reduce to find the maximum integer in a list or compute the least common multiple of all
integers in the list.
reduce ( max ,[2 ,45 , -89 ,78 ,100 , -45])
100 (20)
PositiveInteger
− 89 (21)
Integer
1 (22)
PositiveInteger
1041300 (23)
PositiveInteger
The infix operator “/” is not used to compute the quotient of integers. Rather, it is used to create
rational numbers as described in ‘Fraction’ on page 424.
13 / 4
13
(24)
4
Fraction ( Integer )
3 (25)
PositiveInteger
1 (26)
PositiveInteger
One integer is evenly divisible by another if the remainder is zero. The operation exquo can also be
used. See Section 2.5 on page 79 for an example.
zero ? ( 1 6 7 6 04 7 3 6 4 4 6 9 5 2 rem 2003644)
true (27)
Boolean
The operation divide returns a record of the quotient and remainder and thus is more efficient when
both are needed.
d := divide (13 ,4)
d . quotient
446 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
3 (29)
PositiveInteger
1 (30)
PositiveInteger
Use the operation factor to factor integers. It returns an object of type Factored Integer. See
‘Factored’ on page 405 for a discussion of the manipulation of factored objects.
factor 102400
212 52 (1)
Factored( Integer )
The operation prime? returns true or false depending on whether its argument is a prime.
prime ? 7
true (2)
Boolean
prime ? 8
false (3)
Boolean
The operation nextPrime returns the least prime number greater than its argument.
nextPrime 100
101 (4)
PositiveInteger
The operation prevPrime returns the greatest prime number less than its argument.
prevPrime 100
97 (5)
9.38. INTEGER 447
PositiveInteger
To compute all primes between two integers (inclusively), use the operation primes.
primes (100 ,175)
[101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173] (6)
List ( Integer )
You might sometimes want to see the factorization of an integer when it is considered a Gaussian
integer. See ‘Complex’ on page 372 for more details.
factor (2 :: Complex Integer )
− i (1 + i)2 (7)
Factored(Complex(Integer))
FriCAS provides several number theoretic operations for integers. More examples are in ‘IntegerNumberTheoryFunctions
on page 450.
The operation fibonacci computes the Fibonacci numbers. The algorithm has running time O (log3 (n))
for argument n.
[ fibonacci ( k ) for k in 0..]
[0, 1, 1, 2, 3, 5, 8, . . .] (1)
Stream(Integer)
The operation legendre computes the Legendre symbol for its two integer arguments where the second
one is prime. If you know the second argument to be prime, use jacobi instead where no check is made.
[ legendre (i ,11) for i in 0..10]
List ( Integer )
The operation jacobi computes the Jacobi symbol for its two integer arguments. By convention, 0 is
returned if the greatest common divisor of the numerator and denominator is not 1.
[ jacobi (i ,15) for i in 0..9]
List ( Integer )
The operation eulerPhi computes the values of Euler’s φ-function where φ(n) equals the number of
positive integers less than or equal to n that are relatively prime to the positive integer n.
[ eulerPhi i for i in 1..]
448 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
[1, 1, 2, 2, 4, 2, 6, . . .] (4)
Stream(Integer)
Stream(Integer)
Although they have somewhat limited utility, FriCAS provides Roman numerals.
a := roman (78)
RomanNumeral
b := roman (87)
LXXXV II (7)
RomanNumeral
a + b
CLXV (8)
RomanNumeral
a * b
M M M M M M DCCLXXXV I (9)
RomanNumeral
b rem a
IX (10)
RomanNumeral
9.39 IntegerLinearDependence
The elements v1 , . . . , vn of a module M over a ring R are said to be linearly dependent over R if there
exist c1 , . . . , cn in R, not all 0, such that c1 v1 + . . . cn vn = 0. If such ci ’s exist, they form what is called
a linear dependence relation over R for the vi ’s.
The package IntegerLinearDependence provides functions for testing whether some elements of a
module over the integers are linearly dependent over the integers, and to find the linear dependence
relations, if any. Consider the domain of two by two square matrices with integer entries.
9.39. INTEGERLINEARDEPENDENCE 449
M := SQMATRIX (2 , INT )
1 2
(5)
0 −1
SquareMatrix(2, Integer )
2 3
(6)
1 −2
SquareMatrix(2, Integer )
3 4
(7)
2 −3
SquareMatrix(2, Integer )
This tells you whether m1, m2 and m3 are linearly dependent over the integers.
l i n e a r l y D e p e n d e n t O v e r Z ? vector [ m1 , m2 , m3 ]
true (8)
Boolean
Since they are linearly dependent, you can ask for the dependence relation.
c := l i n e a r D e p e n d e n c e O v e r Z vector [ m1 , m2 , m3 ]
Union(Vector(Integer ) , ...)
0 0
(10)
0 0
450 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
SquareMatrix(2, Integer )
When a given set of elements are linearly dependent over R, this also means that at least one of them
can be rewritten as a linear combination of the others with coefficients in the quotient field of R. To
express a given element in terms of other elements, use the operation solveLinearlyOverQ.
s o l v e L i n e a r l y O v e r Q ( vector [ m1 , m3 ] , m2 )
1 1
particular = , , basis = [] (11)
2 2
Record( particular : Union(Vector(Fraction( Integer )) , ” failed ”), basis : List (Vector( Fraction ( Integer ))))
9.40 IntegerNumberTheoryFunctions
The IntegerNumberTheoryFunctions package contains a variety of operations of interest to number
theorists. Many of these operations deal with divisibility properties of integers. (Recall that an integer
a divides an integer b if there is an integer c such that b = a * c.)
The operation divisors returns a list of the divisors of an integer.
div144 := divisors (144)
[1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 36, 48, 72, 144] (4)
List ( Integer )
You can now compute the number of divisors of 144 and the sum of the divisors of 144 by counting
and summing the elements of the list we just created.
#( div144 )
15 (5)
PositiveInteger
reduce (+ , div144 )
403 (6)
PositiveInteger
Of course, you can compute the number of divisors of an integer n, usually denoted d(n), and the sum
of the divisors of an integer n, usually denoted σ(n), without ever listing the divisors of n.
In FriCAS, you can simply call the operations numberOfDivisors and sumOfDivisors.
n u m b e r O f D i v i s o rs (144)
15 (7)
9.40. INTEGERNUMBERTHEORYFUNCTIONS 451
PositiveInteger
sumOfDivisors (144)
403 (8)
PositiveInteger
The key is that d(n) and σ(n) are “multiplicative functions.” This means that when n and m are
relatively prime, that is, when n and m have no prime factor in common, then d(nm) = d(n) d(m) and
σ(nm) = σ(n) σ(m). Note that these functions are trivial to compute when n is a prime power and are
computed for general n from the prime factorization of n. Other examples of multiplicative functions
are σk (n), the sum of the k th powers of the divisors of n and φ(n), the number of integers between 1
and n which are prime to n. The corresponding FriCAS operations are called sumOfKthPowerDivisors
and eulerPhi.
An interesting function is µ(n), the Möbius µ function, defined as follows: µ(1) = 1, µ(n) = 0, when n
k
is divisible by a square, and µ = (−1) , when n is the product of k distinct primes. The corresponding
FriCAS operation is moebiusMu. This function occurs in the following theorem:
Theorem (Möbius Inversion Formula):
Let f(n) be a function on the positive integers and let F(n) be defined by
X
F (n) = f (d)
d|n
where the sum is taken over the positive divisors of n. Then the values of f(n) can be recovered from
the values of F(n): X n
f (n) = µ(n)F ( )
d
d|n
f1 (200)
Compiling function f1 with type P o si ti ve I nt eg er -> Integer
1 (10)
PositiveInteger
f1 (846)
1 (11)
PositiveInteger
Similarly, when f(n) = n, then F(n) = σ(n). Thus, if you sum µ(d) σ (n/d) over the positive divisors
d of n, you should always get n.
f2 ( n ) == reduce (+ ,[ moebiusMu ( d ) * sumOfDivisors ( quo (n , d ) ) for d in divisors ( n ) ])
452 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
f2 (200)
Compiling function f2 with type P o si ti ve I nt eg er -> Integer
200 (13)
PositiveInteger
f2 (846)
846 (14)
PositiveInteger
The Möbius inversion formula is derived from the multiplication of formal Dirichlet series. A Dirichlet
series is an infinite series of the form
∞
X
a(n)n−s
n=1
When
∞
X ∞
X ∞
X
a(n)n−s · b(n)n−s = c(n)n−s
n=1 n=1 n=1
P
then c(n) = d|n a(d)b(n/d). Recall that the Riemann ζ function is defined by
Y
ζ(s) = (1 − p−s )−1 = σn=1
∞
n−s
p
where the product is taken over the set of (positive) primes. Thus,
Y
ζ(s)−1 = (1 − p−s ) = σn=1
∞
µ(n)n−s
p
P
Now if F (n) = d|n)f (d) , then
X X
f (n)n−s · ζ(s) = F (n)n−s
Thus, X X
ζ(s)−1 · F (n)n−s = f (n)n−s
P
and f (n) = d|n µ(d)F (n/d).
The Fibonacci numbers are defined by F(1) = F(2) = 1 and F(n) = F(n-1)+ F(n-2) for n = 3,4,
.... The operation fibonacci computes the nth Fibonacci number.
fibonacci (25)
75025 (15)
PositiveInteger
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] (16)
List ( Integer )
fib (25)
Compiling function fib with type Po si ti v eI nt eg e r -> Integer
75025 (18)
PositiveInteger
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] (19)
List ( Integer )
Quadratic
symbols can be computed with the operations legendre and jacobi. The Legendre
symbol
a a
p is defined for integers a and p with p an odd prime number. By definition, p , when a is a
square (mod p), ap , when a is not a square (mod p), and ap , when a is divisible by p. You
compute ap via the command legendre(a,p).
legendre (3 ,5)
−1 (20)
Integer
−1 (21)
Integer
The Jacobi symbol ap is the usual extension of the Legendre symbol, where n is an arbitrary integer.
The most important property of the Jacobi symbol is the following: if K is a quadratic field with
discriminant d and quadratic character χ, then χ(n) = (d/n). Thus, you can use the Jacobi symbol
to compute, say, the class numbers of imaginary quadratic fields from a standard class number formula.
This function computes the class number of the imaginary quadratic field with discriminant d.
h ( d ) == quo ( reduce (+ , [ jacobi (d , k ) for k in 1.. quo ( -d , 2) ]) , 2 - jacobi (d ,2) )
h ( -163)
Compiling function h with type Integer -> Integer
1 (23)
454 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
PositiveInteger
h ( -499)
3 (24)
PositiveInteger
h ( -1832)
26 (25)
PositiveInteger
9.41 Kernel
A kernel is a symbolic function application (such as sin(x + y)) or a symbol (such as x). More
precisely, a non-symbol kernel over a set S is an operator applied to a given list of arguments from S.
The operator has type BasicOperator (see ‘BasicOperator’ on page 345) and the kernel object is
usually part of an expression object (see ‘Expression’ on page 400).
Kernels are created implicitly for you when you create expressions.
x :: Expression Integer
x (4)
Expression ( Integer )
You can directly create a “symbol” kernel by using the kernel operation.
kernel x
x (5)
Expression ( Integer )
The operator kernels returns a list of the kernels in an object of type Expression.
kernels %
Expression ( Integer )
[] (10)
If one or more kernels are present, one of them is designated the main kernel.
mainKernel ( cos ( x ) + tan ( x ) )
tan(x) (11)
1 (12)
PositiveInteger
This has height 2 because the x has height 1 and then we apply an operator to that.
height mainKernel ( sin x )
2 (13)
PositiveInteger
3 (14)
456 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
PositiveInteger
4 (15)
PositiveInteger
Use the operator operation to extract the operator component of the kernel. The operator has type
BasicOperator.
operator mainKernel ( sin cos ( tan x + sin x ) )
sin (16)
BasicOperator
Use the name operation to extract the name of the operator component of the kernel. The name has
type Symbol. This is really just a shortcut for a two-step process of extracting the operator and then
calling name on the operator.
name mainKernel ( sin cos ( tan x + sin x ) )
sin (17)
Symbol
FriCAS knows about functions such as sin, cos and so on and can make kernels and then expressions
using them. To create a kernel and expression using an arbitrary operator, use operator. Now f can
be used to create symbolic function applications.
f := operator ’f
f (18)
BasicOperator
e := f (x , y , 10)
Expression ( Integer )
Use the is? operation to learn if the operator component of a kernel is equal to a given operator.
is ?( e , f )
true (20)
Boolean
You can also use a symbol or a string as the second argument to is?.
is ?( e , ’f )
9.42. KEYEDACCESSFILE 457
true (21)
Boolean
Use the argument operation to get a list containing the argument component of a kernel.
argument mainKernel e
9.42 KeyedAccessFile
The domain KeyedAccessFile(S) provides files which can be used as associative tables. Data values
are stored in these files and can be retrieved according to their keys. The keys must be strings so
this type behaves very much like the StringTable(S) domain. The difference is that keyed access
files reside in secondary storage while string tables are kept in memory. For more information on
table-oriented operations, see the description of Table.
Before a keyed access file can be used, it must first be opened. A new file can be created by opening
it for output.
ey : Ke y ed Ac ce s sF il e ( Integer ) := open ("/ tmp / editor . year " , " output ")
"/tmp/editor.year" (4)
KeyedAccessFile( Integer )
Just as for vectors, tables or lists, values are saved in a keyed access file by setting elements.
ey ." Char " := 1986
1986 (5)
PositiveInteger
1985 (6)
PositiveInteger
1984 (7)
458 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
PositiveInteger
1986 (8)
PositiveInteger
1986 (9)
PositiveInteger
1986 (10)
PositiveInteger
Attempting to retrieve a non-existent element in this way causes an error. If it is not known whether
a key exists, you should use the search operation.
search (" Char " , ey )
1986 (11)
Union(Integer , ...)
"failed" (12)
1986 (13)
Union(Integer , ...)
The keys operation returns a list of all the keys for a given file.
keys ey
List ( String )
2 (15)
PositiveInteger
The table view of keyed access files provides safe operations. That is, if the FriCAS program is
terminated between file operations, the file is left in a consistent, current state. This means, however,
that the operations are somewhat costly. For example, after each update the file is closed. Here we
add several more items to the file, then check its contents.
KE := Record ( key : String , entry : Integer )
Type
"/tmp/editor.year" (17)
KeyedAccessFile( Integer )
If many items are to be added to a file at the same time, then it is more efficient to use the write!
operation.
write !( ey , [" van Hulzen " , 1983] $ KE )
close ! ey
"/tmp/editor.year" (21)
KeyedAccessFile( Integer )
The read! operation is also available from the file view, but it returns elements in a random order. It
is generally clearer and more efficient to use the keys operation and to extract elements by key.
keys ey
460 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
List ( String )
members ey
List ( Integer )
For more information on related topics, see ‘File’ on page 412, ‘TextFile’ on page 592, and ‘Library’
on page 474. Issue the system command )show KeyedAccessFile to display the full list of operations
defined by KeyedAccessFile.
9.43 LazardSetSolvingPackage
The LazardSetSolvingPackage package constructor solves polynomial systems by means of Lazard
triangular sets. However one condition is relaxed: Regular triangular sets whose saturated ideals have
positive dimension are not necessarily normalized.
The decompositions are computed in two steps. First the algorithm of Moreno Maza (implemented
in the RegularTriangularSet domain constructor) is called. Then the resulting decompositions are
converted into lists of square-free regular triangular sets and the redundant components are removed.
Moreover, zero-dimensional regular triangular sets are normalized.
Note that the way of understanding triangular decompositions is detailed in the example of the Reg-
ularTriangularSet constructor.
The LazardSetSolvingPackage constructor takes six arguments. The first one, R, is the coefficient
ring of the polynomials; it must belong to the category GcdDomain. The second one, E, is the expo-
nent monoid of the polynomials; it must belong to the category OrderedAbelianMonoidSup. the
third one, V, is the ordered set of variables; it must belong to the category OrderedSet. The fourth
one is the polynomial ring; it must belong to the category RecursivePolynomialCategory(R,E,V).
The fifth one is a domain of the category RegularTriangularSetCategory(R,E,V,P) and the last
one is a domain of the category SquareFreeRegularTriangularSetCategory(R,E,V,P). The ab-
breviation for LazardSetSolvingPackage is LAZM3PK.
N.B. For the purpose of solving zero-dimensional algebraic systems, see also LexTriangularPackage
and ZeroDimensionalSolvePackage. These packages are easier to call than LAZM3PK. Moreover, the
ZeroDimensionalSolvePackage package provides operations to compute either the complex roots
or the real roots.
We illustrate now the use of the LazardSetSolvingPackage package constructor with two examples
(Butcher and Vermeer).
Define the coefficient ring.
R := Integer
9.43. LAZARDSETSOLVINGPACKAGE 461
Integer (4)
Type
[b1, x, y, z, t, v, u, w] (5)
List (Symbol)
Type
Type
Type
b1 (9)
x : P := ’x
x (10)
y : P := ’y
y (11)
462 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
z : P := ’z
z (12)
t : P := ’t
t (13)
u : P := ’u
u (14)
v : P := ’v
v (15)
w : P := ’w
w (16)
RegularTriangularSet(Integer, IndexedExponents(OrderedVariableList([b1,
(17)
x, y, z, t, v, u, w])), OrderedVariableList([b1, x, y, z, t, v, u,
w]), NewSparseMultivariatePolynomial(Integer, OrderedVariableList([b1, x, y, z, t, v, u, w])))
Type
b1 + y + z − t − w (18)
p1 := 2* z * u + 2* y * v + 2* t * w - 2* w ^2 - w - 1
2 v y + 2 u z + 2 w t − 2 w2 − w − 1 (19)
9.43. LAZARDSETSOLVINGPACKAGE 463
p2 := 3* z * u ^2 + 3* y * v ^2 - 3* t * w ^2 + 3* w ^3 + 3* w ^2 - t + 4* w
3 v 2 y + 3 u2 z + −3 w2 − 1 t + 3 w3 + 3 w2 + 4 w
(20)
p3 := 6* x * z * v - 6* t * w ^2 + 6* w ^3 - 3* t * w + 6* w ^2 - t + 4* w
6 v z x + −6 w2 − 3 w − 1 t + 6 w3 + 6 w2 + 4 w
(21)
4 v 3 y + 4 u3 z + 4 w3 + 4 w t − 4 w4 − 6 w3 − 10 w2 − w − 1
(22)
8 u v z x + 8 w3 + 4 w2 + 4 w t − 8 w4 − 12 w3 − 14 w2 − 3 w − 1
(23)
12 v 2 z x + 12 w3 + 12 w2 + 8 w t − 12 w4 − 18 w3 − 14 w2 − w − 1
(24)
−24 w3 − 24 w2 − 8 w t + 24 w4 + 36 w3 + 26 w2 + 7 w + 1
(25)
lp := [ p0 , p1 , p2 , p3 , p4 , p5 , p6 , p7 ]
b1 + y + z − t − w, 2 v y + 2 u z + 2 w t − 2 w2 − w − 1,
3 v 2 y +3 u2 z + −3 w2 −1 t+3 w3 +3 w2 +4 w, 6 v z x+ −6 w2 −3 w −1 t+6 w3 +6 w2 +4 w,
4 v 3 y + 4 u3 z + 4 w3 + 4 w t − 4 w4 − 6 w3 − 10 w2 − w − 1, (26)
8 u v z x + 8 w3 + 4 w2 + 4 w t − 8 w4 − 12 w3 − 14 w2 − 3 w − 1,
12 v 2 z x + 12 w3 + 12 w2 + 8 w t − 12 w4 − 18 w3 − 14 w2 − w − 1,
−24 w3 − 24 w2 − 8 w t + 24 w4 + 36 w3 + 26 w2 + 7 w + 1
First of all, let us solve this system in the sense of Lazard by means of the REGSET constructor:
lts := zeroSetSplit ( lp , false ) $ T
464 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
{w + 1, u, v, t + 1, b1 + y + z + 2} , {w + 1, v, t + 1, z, b1 + y + 2} ,
{w + 1, t + 1, z, y, b1 + 2} , {w + 1, v − u, t + 1, y + z, x, b1 + 2} , {w + 1,
u, t + 1, y, x, b1 + z + 2} , 144 w5 + 216 w4 + 96 w3 + 6 w2 − 11 w − 1,
12 w2 + 9 w + 1 u − 72 w5 − 108 w4 − 42 w3 − 9 w2 − 3 w,
(27)
12 w2 + 9 w + 1 v + 36 w4 + 54 w3 + 18 w2 ,
24 w3 + 24 w2 + 8 w t − 24 w4 − 36 w3 − 26 w2 − 7 w − 1,
12 u v − 12 u2 z + 12 w v + 12 w2 + 4 t + (3 w − 5) v + 36 w4 + 42 w3 + 6 w2 − 16 w,
2 v y + 2 u z + 2 w t − 2 w2 − w − 1,
6 v z x + −6 w2 − 3 w − 1 t + 6 w3 + 6 w2 + 4 w, b1 + y + z − t − w
[3, 3, 3, 2, 2, 0] (28)
List (NonNegativeInteger)
The first five sets have a simple shape. However, the last one, which has dimension zero, can be
simplified by using Lazard triangular sets.
Thus we call the SquareFreeRegularTriangularSet domain constructor,
ST := SREGSET (R ,E ,V , P )
SquareFreeRegularTriangularSet(Integer, IndexedExponents(OrderedVariableList([b1,
(29)
x, y, z, t, v, u, w])), OrderedVariableList([b1, x, y, z, t, v, u,
w]), NewSparseMultivariatePolynomial(Integer, OrderedVariableList([b1, x, y, z, t, v, u, w])))
Type
Type
{w + 1, t + 1, z, y, b1 + 2} , {w + 1, v, t + 1, z, b1 + y + 2} , {w + 1, u,
v, t + 1, b1 + y + z + 2} , {w + 1, v − u, t + 1, y + z, x, b1 + 2} , {w + 1,
u, t + 1, y, x, b1 + z + 2} , 144 w5 + 216 w4 + 96 w3 + 6 w2 − 11 w − 1,
u − 24 w4 − 36 w3 − 14 w2 + w + 1, 3 v − 48 w4 − 60 w3 − 10 w2 + 8 w + 2, (31)
4 3 2 4 3 2
t − 24 w − 36 w − 14 w − w + 1, 486 z − 2772 w − 4662 w − 2055 w + 30 w + 127,
2916 y − 22752 w4 − 30312 w3 − 8220 w2 + 2064 w + 1561,
356 x − 3696 w4 − 4536 w3 − 968 w2 + 822 w + 371,
2916 b1 − 30600 w4 − 46692 w3 − 20274 w2 − 8076 w + 593
We see the sixth triangular set is nicer now: each one of its polynomials has a constant initial.
We follow with the Vermeer example. The ordering is the usual one for this system.
Define the polynomial system.
f0 := ( w - v ) ^ 2 + ( u - t ) ^ 2 - 1
t 2 − 2 u t + v 2 − 2 w v + u2 + w 2 − 1 (32)
f1 := t ^ 2 - v ^ 3
t2 − v 3 (33)
f2 := 2 * t * ( w - v ) + 3 * v ^ 2 * ( u - t )
−3 v 2 − 2 v + 2 w t + 3 u v 2
(34)
f3 := (3 * z * v ^ 2 - 1) * (2 * z * t - 1)
6 v 2 t z 2 + −2 t − 3 v 2 z + 1
(35)
lf := [ f0 , f1 , f2 , f3 ]
466 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
t2 − 2 u t + v 2 − 2 w v + u2 + w2 − 1, t2 − v 3 , −3 v 2 − 2 v + 2 w t + 3 u v 2 , 6 v 2 t z 2 + −2 t − 3 v 2 z + 1
(36)
First of all, let us solve this system in the sense of Kalkbrener by means of the REGSET constructor:
zeroSetSplit ( lf , true ) $ T
3 v 2 + 2 v − 2 w t − 3 u v 2 , (4 v − 4 w) t − 6 u v 2 z 2 + 2 t + 3 v 2 z − 1
We have obtained one regular chain (i.e. regular triangular set) with dimension 1. This set is in fact
a characterist set of the (radical of) of the ideal generated by the input system lf. Thus we have only
the generic points of the variety associated with lf (for the elimination ordering given by ls).
So let us get now a full description of this variety. Hence, we solve this system in the sense of Lazard
by means of the REGSET constructor:
zeroSetSplit ( lf , false ) $ T
3 v 2 + 2 v − 2 w t − 3 u v 2 , (4 v − 4 w) t − 6 u v 2 z 2 + 2 t + 3 v 2 z − 1 ,
27 w4 + 4 w3 − 54 w2 − 36 w + 23, u, (12 w + 2) v − 9 w2 − 2 w + 9, 6 t2 − 2 v − 3 w2 + 2 w + 3,
3 v 2 + 2 v − 2 w t − 3 u v 2 , (4 v − 4 w) t − 6 u v 2 z 2 + 2 t + 3 v 2 z − 1 ,
27 w4 + 4 w3 − 54 w2 − 36 w + 23, u, (12 w + 2) v − 9 w2 − 2 w + 9, 6 t2 − 2 v − 3 w2 + 2 w + 3, 3 v 2 z − 1
We retrieve our regular chain of dimension 1 and we get three regular chains of dimension 0 corre-
9.44. LEXTRIANGULARPACKAGE 467
sponding to the degenerated cases. We want now to simplify these zero-dimensional regular chains by
using Lazard triangular sets. Moreover, this will allow us to prove that the above decomposition has
no redundant component. N.B. Generally, decompositions computed by the REGSET constructor
do not have redundant components. However, to be sure that no redundant component occurs one
needs to use the SREGSET or LAZM3PK constructors.
So let us solve the input system in the sense of Lazard by means of the LAZM3PK constructor:
zeroSetSplit ( lf , false ) $ pack
3 v 2 + 2 v − 2 w t − 3 u v 2 , (4 v − 4 w) t − 6 u v 2 z 2 + 2 t + 3 v 2 z − 1 ,
702 v − 162 w3 − 225 w2 + 40 w − 99, 11336 t + 324 w3 − 603 w2 − 1718 w − 1557 u, 595003968 z 2
Due to square-free factorization, we obtained now four zero-dimensional regular chains. Moreover, each
of them is normalized (the initials are constant). Note that these zero-dimensional components may
be investigated further with the ZeroDimensionalSolvePackage package constructor.
9.44 LexTriangularPackage
The LexTriangularPackage package constructor provides an implementation of the lexTriangular
algorithm (D. Lazard ”Solving Zero-dimensional Algebraic Systems”, J. of Symbol. Comput., 1992).
This algorithm decomposes a zero-dimensional variety into zero-sets of regular triangular sets. Thus
the input system must have a finite number of complex solutions. Moreover, this system needs to be
a lexicographical Groebner basis.
This package takes two arguments: the coefficient-ring R of the polynomials, which must be a Gcd-
Domain and their set of variables given by ls a List Symbol. The type of the input polynomials
468 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Integer (4)
9.44. LEXTRIANGULARPACKAGE 469
Type
[a, b, c, d, e, f ] (5)
List (Symbol)
OrderedVariableList([a, b, c, d, e, f ]) (6)
Type
Type
f edcba − 1 (8)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ a, b, c, d, e, f ]) )
p2 : P := a * b * c * d * e + a * b * c * d * f + a * b * c * e * f + a * b * d * e * f + a * c * d * e * f + b * c * d * e * f
((((e + f ) d + f e) c + f e d) b + f e d c) a + f e d c b (9)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ a, b, c, d, e, f ]) )
(((d + f ) c + f e) b + f e d) a + e d c b + f e d c (10)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ a, b, c, d, e, f ]) )
p4 : P := a * b * c + a * b * f + a * e * f + b * c * d + c * d * e + d * e * f
((c + f ) b + f e) a + d c b + e d c + f e d (11)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ a, b, c, d, e, f ]) )
p5 : P := a * b + a * f + b * c + c * d + d * e + e * f
470 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
(b + f ) a + c b + d c + e d + f e (12)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ a, b, c, d, e, f ]) )
p6 : P := a + b + c + d + e + f
a+b+c+d+e+f (13)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ a, b, c, d, e, f ]) )
lp := [ p1 , p2 , p3 , p4 , p5 , p6 ]
[f e d c b a − 1, ((((e + f ) d + f e) c + f e d) b + f e d c) a + f e d c b,
(14)
(((d + f ) c + f e) b + f e d) a + e d c b + f e d c, ((c + f ) b + f e) a + d c b + e d c + f e d,
(b + f ) a + c b + d c + e d + f e, a + b + c + d + e + f ]
Type
Compute the lexicographical Groebner basis of the system. This may take between 5 minutes and one
hour, depending on your machine.
lg := groebner ( lp ) $ lextripack ;
List (NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ a, b, c, d, e, f ]) ))
Apply lexTriangular to compute a decomposition into regular triangular sets. This should not take
more than 5 seconds.
lexTriangular ( lg , false ) $ lextripack
9.44. LEXTRIANGULARPACKAGE 471
f 6 + 1, e6 − 3 f e5 + 3 f 2 e4 − 4 f 3 e3 + 3 f 4 e2 − 3 f 5 e − 1, 3 d + f 2 e5 − 4 f 3 e4 + 4 f 4 e3 − 2 f 5 e2 − 2 e + 2 f,
(17)
2 5 3 4 4 3 5 2 2 5 3 4 4 3 5 2
c + f, 3 b + 2 f e − 5 f e + 5 f e − 10 f e − 4 e + 7 f, a − f e + 3 f e − 3 f e + 4 f e + 3 e − 3 f ,
6
f − 1, e − f, d − f, c2 + 4 f c + f 2 , (c − f ) b − f c − 5 f 2 , a + b + c + 3 f , f 6 − 1, e − f, d − f, c − f,
b2 + 4 f b + f 2 , a + b + 4 f , f 6 − 1, e − f, d2 + 4 f d + f 2 , (d − f ) c − f d − 5 f 2 , b − f, a + c + d + 3 f ,
36
f − 2554 f 30 − 399709 f 24 − 502276 f 18 − 399709 f 12 − 2554 f 6 + 1, 161718564 f 12 − 161718564 e2
e2 + 4 f e + f 2 , (e − f ) d − f e − 5 f 2 , c − f, b − f, a + d + e + 3 f
Note that the first set of the decomposition is normalized (all initials are integer numbers) but not
the second one (normalized triangular sets are defined in the description of the NormalizedTrian-
gularSetCategory constructor). So apply now lexTriangular to produce normalized triangular
sets.
lts := lexTriangular ( lg , true ) $ lextripack
472 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
f 6 + 1, e6 − 3 f e5 + 3 f 2 e4 − 4 f 3 e3 + 3 f 4 e2 − 3 f 5 e − 1, 3 d + f 2 e5 − 4 f 3 e4 + 4 f 4 e3 − 2 f 5 e2 − 2 e + 2 f,
(18)
2 5 3 4 4 3 5 2 2 5 3 4 4 3 5 2
c + f, 3 b + 2 f e − 5 f e + 5 f e − 10 f e − 4 e + 7 f, a − f e + 3 f e − 3 f e + 4 f e + 3 e − 3 f ,
6
f − 1, e − f, d − f, c2 + 4 f c + f 2 , b + c + 4 f, a − f , f 6 − 1, e − f, d − f, c − f,
b2 + 4 f b + f 2 , a + b + 4 f , f 6 − 1, e − f, d2 + 4 f d + f 2 , c + d + 4 f, b − f, a − f ,
36
f − 2554 f 30 − 399709 f 24 − 502276 f 18 − 399709 f 12 − 2554 f 6 + 1, 1387545279120 e2
+ 4321823003 f 31 −11037922310209 f 25 −1727506390124986 f 19 −2176188913464634 f 13 −1732620732685741 f 7 −13506088516033 f
+ 24177661775 f 32 − 61749727185325 f 26 − 9664082618092450 f 20
− 12152237485813570 f 14 − 9672870290826025 f 8 − 68544102808525 f 2 , 1387545279120 d
+ −1128983050 f 30 +2883434331830 f 24 +451234998755840 f 18 +562426491685760 f 12 +447129055314890 f 6 −165557857270 e
Note that each triangular set in lts is a lexicographical Groebner basis. Recall that a point belongs to
the variety associated with lp if and only if it belongs to that associated with one triangular set ts in
lts.
By running the squareFreeLexTriangular operation, we retrieve the above decomposition.
s q u a r e F r e e L e x T r i a n g u l a r ( lg , true ) $ lextripack
9.44. LEXTRIANGULARPACKAGE 473
f 6 + 1, e6 − 3 f e5 + 3 f 2 e4 − 4 f 3 e3 + 3 f 4 e2 − 3 f 5 e − 1, 3 d + f 2 e5 − 4 f 3 e4 + 4 f 4 e3 − 2 f 5 e2 − 2 e + 2 f,
(20)
2 5 3 4 4 3 5 2 2 5 3 4 4 3 5 2
c + f, 3 b + 2 f e − 5 f e + 5 f e − 10 f e − 4 e + 7 f, a − f e + 3 f e − 3 f e + 4 f e + 3 e − 3 f ,
6
f − 1, e − f, d − f, c2 + 4 f c + f 2 , b + c + 4 f, a − f , f 6 − 1, e − f, d − f, c − f,
b2 + 4 f b + f 2 , a + b + 4 f , f 6 − 1, e − f, d2 + 4 f d + f 2 , c + d + 4 f, b − f, a − f ,
36
f − 2554 f 30 − 399709 f 24 − 502276 f 18 − 399709 f 12 − 2554 f 6 + 1, 1387545279120 e2
+ 4321823003 f 31 −11037922310209 f 25 −1727506390124986 f 19 −2176188913464634 f 13 −1732620732685741 f 7 −13506088516033 f
+ 24177661775 f 32 − 61749727185325 f 26 − 9664082618092450 f 20
− 12152237485813570 f 14 − 9672870290826025 f 8 − 68544102808525 f 2 , 1387545279120 d
+ −1128983050 f 30 +2883434331830 f 24 +451234998755840 f 18 +562426491685760 f 12 +447129055314890 f 6 −165557857270 e
Thus the solutions given by lts are pairwise different. We count them as follows.
reduce (+ ,[ degree ( ts ) for ts in lts ])
156 (21)
PositiveInteger
List (Symbol)
Type
We compute a univariate representation of the variety associated with the input system as follows.
474 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Since the univariateSolve operation may split a regular set, it returns a list. This explains the use
of concat.
Look at the last item of the result. It consists of two parts. For any complex root ? of the univariate
polynomial in the first part, we get a tuple of univariate polynomials (in a, ..., f respectively) by
replacing %A by ? in the second part. Each of these tuples t describes a point of the variety
associated with lp by equaling to zero the polynomials in t.
Note that the way of reading these univariate representations is explained also in the example illus-
trating the ZeroDimensionalSolvePackage constructor.
Now, we compute the points of the variety with real coordinates.
concat [ realSolve ( ts ) $ zdpack for ts in lts ];
List ( List (RealClosure( Fraction ( Integer ))))
We obtain 24 points given by lists of elements in the RealClosure of Fraction of R. In each list,
the first value corresponds to the indeterminate f, the second to e and so on. See ZeroDimensional-
SolvePackage to learn more about the realSolve operation.
9.45 Library
The Library domain provides a simple way to store FriCAS values in a file. This domain is similar
to KeyedAccessFile but fewer declarations are needed and items of different types can be saved
together in the same file.
To create a library, you supply a file name.
stuff := library "/ tmp / Neat . stuff "
"/tmp/Neat.stuff" (4)
Library
Now values can be saved by key in the file. The keys should be mnemonic, just as the field names are
for records. They can be given either as strings or symbols.
stuff . int := 32^2
1024 (5)
PositiveInteger
x2 + 1 (6)
Polynomial( Integer )
"Hello" (7)
String
You obtain the set of available keys using the keys operation.
keys stuff
List ( String )
x2 + 1 (9)
Polynomial( Integer )
x2 + 1 (10)
Polynomial( Integer )
When the file is no longer needed, you should remove it from the file system.
) system rm - rf / tmp / Neat . stuff
For more information on related topics, see ‘File’ on page 412, ‘TextFile’ on page 592, and ‘KeyedAccessFile’
on page 457. Issue the system command )show Library to display the full list of operations defined
by Library.
9.46 LieExponentials
This example is in just two variables
a : Symbol := ’a
a (4)
Symbol
b : Symbol := ’b
b (5)
Symbol
Declarations of domains
coef := Fraction ( Integer )
476 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Fraction(Integer) (6)
Type
Type
Type
Calculations
ea := exp ( a :: lpoly ) $ group
e[a] (10)
e[b] (11)
g : group := ea * eb
1 2 1 2
e[b] e 2 [a b ] e[a b] e 2 [a b] e[a] (12)
g :: poly
1 1 1 1 2
1 + [a] + [b] + [a] [a] + [a b] + [b] [a] + [b] [b] + [a] [a] [a] + a b (13)
2 2 6 2
1 1 1 1
a b2 + [b] [a] [a] + [b] [a b] + [b] [b] [a] + [b] [b] [b]
+ [a b] [a] +
2 2 2 6
XPBWPolynomial(Symbol, Fraction(Integer))
log ( g ) $ group
9.47. LIEPOLYNOMIAL 477
1 1 2 1 2
[a] + [b] + [a b] + a b + ab (14)
2 12 12
LiePolynomial(Symbol, Fraction( Integer ))
g1 : group := inv ( g )
g * g1
1 (16)
9.47 LiePolynomial
Declaration of domains
RN := Fraction Integer
Fraction(Integer) (4)
Type
Type
Type
LyndonWord(Symbol) (7)
Type
Initialisation
a : Symbol := ’a
a (8)
478 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Symbol
b : Symbol := ’b
b (9)
Symbol
c : Symbol := ’c
c (10)
Symbol
aa : Lpoly := a
[a] (11)
bb : Lpoly := b
[b] (12)
cc : Lpoly := c
[c] (13)
p : Lpoly := [ aa , bb ]
[a b] (14)
q : Lpoly := [p , bb ]
a b2
(15)
[a] , [b] , [a b] , a2 b , a b2 , a3 b , a2 b2 , a b3
(16)
List (LyndonWord(Symbol))
[a b] + 3 a2 b + a b2
(17)
s : Lpoly := [p , r ]
− 3 a2 b a b + a b a b2
(18)
2 [a b] − 5 a b2 − 3 a2 b a b + a b a b2
(19)
degree t
5 (20)
PositiveInteger
mirror t
− 2 [a b] − 5 a b2 − 3 a2 b a b + a b a b2
(21)
Jacobi Relation
Jacobi ( p : Lpoly , q : Lpoly , r : Lpoly ) : Lpoly == [[ p , q ] $ Lpoly , r ] + [[ q , r ] $ Lpoly , p ] +
[[ r , p ] $ Lpoly , q ]
Function declaration Jacobi : ( LiePolynomial ( Symbol , Fraction ( Integer )) ,
LiePolynomial ( Symbol , Fraction ( Integer )) , LiePolynomial ( Symbol , Fraction (
Integer ))) -> LiePolynomial ( Symbol , Fraction ( Integer )) has been added to
workspace .
Tests
test : Lpoly := Jacobi (a ,b , b )
Compiling function Jacobi with type ( LiePolynomial ( Symbol , Fraction ( Integer )) ,
LiePolynomial ( Symbol , Fraction ( Integer )) , LiePolynomial ( Symbol , Fraction (
Integer ))) -> LiePolynomial ( Symbol , Fraction ( Integer ))
0 (23)
0 (24)
480 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
0 (25)
Evaluation
eval (p , a , p ) $ Lpoly
a b2
(26)
− 6 [a b] (27)
r : Lpoly := [p , c ]
[a b c] + [a c b] (28)
− [a b c] (29)
− [a c b] (30)
r + r1 + r2
0 (31)
9.48 LinearOrdinaryDifferentialOperator
LinearOrdinaryDifferentialOperator(A, diff ) is the domain of linear ordinary differential op-
erators with coefficients in a ring A with a given derivation. Issue the system command )show
LinearOrdinaryDifferentialOperator to display the full list of operations defined by Linear-
OrdinaryDifferentialOperator.
9.48. LINEARORDINARYDIFFERENTIALOPERATOR 481
Dx := D ()
D (2)
G −x3 + H
D3 + 2
D+ (3)
x x3
LinearOrdinaryDifferentialOperator ( Expression ( Integer ) , theMap(*1;anonymousFunction;2;initial ; internal ))
3 s0 H + s0 G2 + 6 s0 G (9 s0 G + 54 s0 ) H + s0 G3 + 18 s0 G2 + 72 s0 G
s0 G
s1 = , s2 = , s3 = (5)
3 18 162
f i r s t C o e f f i c i e n t s (4)
""
s0 G 3 s0 H + s0 G2 + 6 s0 G (9 s0 G + 54 s0 ) H + s0 G3 + 18 s0 G2 + 72 s0 G
s1 = , s2 = , s3 = ,
3 18 162 (6)
##
27 s0 H 2 + 18 s0 G2 + 378 s0 G + 1296 s0 H + s0 G4 + 36 s0 G3 + 396 s0 G2 + 1296 s0 G
s4 =
1944
482 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
f i r s t C o e f f i c i e n t s (7)
""
s0 G 3 s0 H + s0 G2 + 6 s0 G (9 s0 G + 54 s0 ) H + s0 G3 + 18 s0 G2 + 72 s0 G
s1 = , s2 = , s3 = , (7)
3 18 162
27 s0 H 2 + 18 s0 G2 + 378 s0 G + 1296 s0 H + s0 G4 + 36 s0 G3 + 396 s0 G2 + 1296 s0 G
s4 = ,
1944
(135 s0 G + 2268 s0 ) H + 30 s0 G + 1350 s0 G + 16416 s0 G + 38880 s0 H + s0 G + 60 s0 G4 + 1188 s0 G3 + 9504 s0 G2 + 2
2 3 2 5
s5 =
29160
405 s0 H 3 + 405 s0 G2 + 18468 s0 G + 174960 s0 H 2 + 45 s0 G4 + 3510 s0 G3 + 88776 s0 G2 + 777600 s0 G + 1166400 s0 H +
s6 =
524880
(2835 s0 G + 91854 s0 ) H 3 + 945 s0 G3 + 81648 s0 G2 + 2082996 s0 G + 14171760 s0 H 2 + 63 s0 G5 + 7560 s0 G4 + 317520 s0
s7 =
9.49 LinearOrdinaryDifferentialOperator1
LinearOrdinaryDifferentialOperator1(A) is the domain of linear ordinary differential operators
with coefficients in the differential ring A. Issue the system command )show LinearOrdinaryDifferentialOperator1
to display the full list of operations defined by LinearOrdinaryDifferentialOperator1.
This example shows differential operators with rational function coefficients. In this case operator
multiplication is non-commutative and, since the coefficients form a field, an operator division algorithm
exists.
We begin by defining RFZ to be the rational functions in x with integer coefficients and Dx to be the
differential operator for d/dx.
RFZ := Fraction U n i v a r i a t e P o l y n o m i a l ( ’x , Integer )
Type
x : RFZ := ’x
x (2)
Dx : LODO1 RFZ := D ()
D (3)
9.49. LINEARORDINARYDIFFERENTIALOPERATOR1 483
1
3 x2 D2 + 2 D + (4)
x
LinearOrdinaryDifferentialOperator1 ( Fraction ( UnivariatePolynomial (x, Integer )))
7
15 x3 D3 + 51 x2 + 10 x D2 + 29 D +
(5)
x
LinearOrdinaryDifferentialOperator1 ( Fraction ( UnivariatePolynomial (x, Integer )))
x4 + 1
(6)
x2
Fraction ( UnivariatePolynomial (x, Integer ))
−75 x4 + 540 x − 75
(7)
x4
Fraction ( UnivariatePolynomial (x, Integer ))
When the coefficients of operator polynomials come from a field, as in this case, it is possible to
define operator division. Division on the left and division on the right yield different results when the
multiplication is non-commutative.
The results of leftDivide and rightDivide are quotient-remainder pairs satisfying:
leftDivide(a,b)= [q, r] such that a = b*q + r
rightDivide(a,b)= [q, r] such that a = q*b + r
In both cases, the degree of the remainder, r, is less than the degree of b.
ld := leftDivide (a , b )
a = b * ld . quotient + ld . remainder
7 7
15 x3 D3 + 51 x2 + 10 x D2 + 29 D + = 15 x3 D3 + 51 x2 + 10 x D2 + 29 D +
(9)
x x
484 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
The operations of left and right division are so-called because the quotient is obtained by dividing a
on that side by b.
rd := rightDivide (a , b )
5
quotient = 5 x D + 7, remainder = 10 D + (10)
x
a = rd . quotient * b + rd . remainder
7 7
15 x3 D3 + 51 x2 + 10 x D2 + 29 D + = 15 x3 D3 + 51 x2 + 10 x D2 + 29 D +
(11)
x x
Equation( LinearOrdinaryDifferentialOperator1 ( Fraction ( UnivariatePolynomial (x, Integer ))))
Operations rightQuotient and rightRemainder are available if only one of the quotient or remainder are
of interest to you. This is the quotient from right division.
rightQuotient (a , b )
5xD + 7 (12)
This is the remainder from right division. The corresponding “left” functions leftQuotient and left-
Remainder are also available.
righ tRemaind er (a , b )
5
10 D + (13)
x
LinearOrdinaryDifferentialOperator1 ( Fraction ( UnivariatePolynomial (x, Integer )))
For exact division, the operations leftExactQuotient and rightExactQuotient are supplied. These return
the quotient but only if the remainder is zero. The call rightExactQuotient(a,b) would yield an
error.
l e f t E x a c t Q u o t i e n t (a , b )
5xD + 7 (14)
The division operations allow the computation of left and right greatest common divisors (leftGcd and
rightGcd) via remainder sequences, and consequently the computation of left and right least common
multiples (rightLcm and leftLcm).
e := leftGcd (a , b )
9.50. LINEARORDINARYDIFFERENTIALOPERATOR2 485
1
3 x2 D2 + 2 D + (15)
x
LinearOrdinaryDifferentialOperator1 ( Fraction ( UnivariatePolynomial (x, Integer )))
Note that a greatest common divisor doesn’t necessarily divide a and b on both sides. Here the left
greatest common divisor does not divide a on the right.
leftRemainder (a , e )
0 (16)
righ tRemaind er (a , e )
5
10 D + (17)
x
LinearOrdinaryDifferentialOperator1 ( Fraction ( UnivariatePolynomial (x, Integer )))
Similarly, a least common multiple is not necessarily divisible from both sides.
f := rightLcm (a , b )
7
15 x3 D3 + 51 x2 + 10 x D2 + 29 D +
(18)
x
LinearOrdinaryDifferentialOperator1 ( Fraction ( UnivariatePolynomial (x, Integer )))
righ tRemaind er (f , b )
5
10 D + (19)
x
LinearOrdinaryDifferentialOperator1 ( Fraction ( UnivariatePolynomial (x, Integer )))
leftRemainder (f , b )
0 (20)
9.50 LinearOrdinaryDifferentialOperator2
LinearOrdinaryDifferentialOperator2(A, M) is the domain of linear ordinary differential opera-
tors with coefficients in the differential ring A and operating on M, an A-module. This includes the cases
of operators which are polynomials in D acting upon scalar or vector expressions of a single variable.
The coefficients of the operator polynomials can be integers, rational functions, matrices or elements of
other domains. Issue the system command )show LinearOrdinaryDifferentialOperator2 to display
the full list of operations defined by LinearOrdinaryDifferentialOperator2.
486 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
This example shows differential operators with rational number coefficients operating on univariate
polynomials.
We begin by making type assignments so we can conveniently refer to univariate polynomials in x over
the rationals.
Q := Fraction Integer
Fraction(Integer) (1)
Type
PQ := U n i v a r i a t e P o l y n o m i a l ( ’x , Q )
Type
x : PQ := ’x
x (3)
D (4)
D+1 (5)
b := a + 1/2* Dx ^2 - 1/2
1 2 1
D +D+ (6)
2 2
LinearOrdinaryDifferentialOperator2 ( Fraction ( Integer ) , UnivariatePolynomial (x, Fraction ( Integer )))
To apply the operator a to the value p the usual function call syntax is used.
p := 4* x ^2 + 2/3
2
4 x2 + (7)
3
9.50. LINEARORDINARYDIFFERENTIALOPERATOR2 487
a p
2
4 x2 + 8 x + (8)
3
UnivariatePolynomial (x, Fraction ( Integer ))
37 37
2 x2 + 12 x + = 2 x2 + 12 x + (9)
3 3
Equation(UnivariatePolynomial (x, Fraction ( Integer )))
1 6 5 5 13 4 19 3 79 2 7 1
D + D + D + D + D + D+ (10)
72 36 24 18 72 12 8
LinearOrdinaryDifferentialOperator2 ( Fraction ( Integer ) , UnivariatePolynomial (x, Fraction ( Integer )))
44 541
3 x2 + x+ (11)
3 36
UnivariatePolynomial (x, Fraction ( Integer ))
This is another example of linear ordinary differential operators with non-commutative multiplication.
Unlike the rational function case, the differential ring of square matrices (of a given dimension) with
univariate polynomial entries does not form a field. Thus the number of operations available is more
limited.
In this section, the operators have three by three matrix coefficients with polynomial entries.
PZ := U n i v a r i a t e P o l y n o m i a l (x , Integer )
x : PZ := ’x
488 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
x (2)
Mat := SquareMatrix (3 , PZ )
Type
The matrix m is used as a coefficient and the vectors p and q are operated upon.
m : Mat := matrix [[ x ^2 ,1 ,0] ,[1 , x ^4 ,0] ,[0 ,0 ,4* x ^2]]
x2
1 0
1 x4 0 (6)
0 0 4 x2
3 x2 + 1, 2 x, 7 x3 + 2 x
(7)
q : Vect := m * p
4
3 x + x2 + 2 x, 2 x5 + 3 x2 + 1, 28 x5 + 8 x3
(8)
D (9)
a : Modo := Dx + m
9.50. LINEARORDINARYDIFFERENTIALOPERATOR2 489
x2
1 0
D+1 x4 0 (10)
0 0 4 x2
b : Modo := m * Dx + 1
x2
1 0 1 0 0
1 x4 0 D + 0 1 0 (11)
0 0 4 x2 0 0 1
c := a * b
2 4
x4 + x2
2
x 1 0 x + 2x + 2 0 x 1 0
1 x4 0 D2 + x4 + x2 x + 4 x3 + 2
8
0 D+1 x4 0 (12)
0 0 4 x2 0 0 16 x4 + 8 x + 1 0 0 4 x2
4
3 x + x2 + 8 x, 2 x5 + 3 x2 + 3, 28 x5 + 8 x3 + 21 x2 + 2
(13)
b p
3
6 x + 3 x2 + 3, 2 x4 + 8 x, 84 x4 + 7 x3 + 8 x2 + 2 x
(14)
(a + b + c) (p + q)
10 x8 + 12 x7 + 16 x6 + 30 x5 + 85 x4 + 94 x3 + 40 x2 + 40 x + 17,
(15)
10 x12 + 10 x9 + 12 x8 + 92 x7 + 6 x6 + 32 x5 + 72 x4 + 28 x3 + 49 x2 + 32 x + 19,
2240 x8 + 224 x7 + 1280 x6 + 3508 x5 + 492 x4 + 751 x3 + 98 x2 + 18 x + 4
490 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
9.51 List
A list is a finite collection of elements in a specified order that can contain duplicates. A list is a
convenient structure to work with because it is easy to add or remove elements and the length need
not be constant. There are many different kinds of lists in FriCAS, but the default types (and those
used most often) are created by the List constructor. For example, there are objects of type List
Integer, List Float and List Polynomial Fraction Integer. Indeed, you can even have List List
List Boolean (that is, lists of lists of lists of Boolean values). You can have lists of any type of FriCAS
object.
The easiest way to create a list with, for example, the elements 2, 4, 5, 6 is to enclose the elements
with square brackets and separate the elements with commas. The spaces after the commas are
optional, but they do improve the readability.
[2 , 4 , 5 , 6]
[2, 4, 5, 6] (1)
List ( PositiveInteger )
To create a list with the single element 1, you can use either [1] or the operation list.
[1]
[1] (2)
List ( PositiveInteger )
list (1)
[1] (3)
List ( PositiveInteger )
Once created, two lists k and m can be concatenated by issuing append(k,m). append does not physically
join the lists, but rather produces a new list with the elements coming from the two arguments.
append ([1 ,2 ,3] ,[5 ,6 ,7])
[1, 2, 3, 5, 6, 7] (4)
List ( PositiveInteger )
[10, 9, 8, 7] (5)
List ( PositiveInteger )
To determine whether a list has any elements, use the operation empty?.
empty ? [ x +1]
false (1)
Boolean
true (2)
Boolean
[4, 3, 7, 3, 8, 5, 9, 2] (3)
List ( PositiveInteger )
4 (4)
PositiveInteger
k . first
4 (5)
PositiveInteger
k .1
4 (6)
PositiveInteger
k (1)
492 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
4 (7)
PositiveInteger
The last two forms generalize to k.i and k(i), respectively, where 1 ≤ i ≤ n and n equals the length
of k. This length is calculated by #.
n := # k
8 (8)
PositiveInteger
Performing an operation such as k.i is sometimes referred to as indexing into k or elting into k. The
latter phrase comes about because the name of the operation that extracts elements is called elt. That
is, k.3 is just alternative syntax for elt(k,3). It is important to remember that list indices begin with
1. If we issue k := [1,3,2,9,5] then k.4 returns 9. It is an error to use an index that is not in the
range from 1 to the length of the list.
The last element of a list is extracted by any of the following three expressions.
last k
2 (9)
PositiveInteger
k . last
2 (10)
PositiveInteger
This form computes the index of the last element and then extracts the element from the list.
k .(# k )
2 (11)
PositiveInteger
[4, 3, 7, 3, 8, 5, 9, 2] (1)
List ( PositiveInteger )
List elements are reset by using the k.i form on the left-hand side of an assignment. This expression
resets the first element of k to 999.
9.51. LIST 493
k .1 := 999
999 (2)
PositiveInteger
As with indexing into a list, it is an error to use an index that is not within the proper bounds. Here
you see that k was modified.
k
[999, 3, 7, 3, 8, 5, 9, 2] (3)
List ( PositiveInteger )
The operation that performs the assignment of an element to a particular position in a list is called
setelt!. This operation is destructive in that it changes the list. In the above example, the assignment
returned the value 999 and k was modified. For this reason, lists are called mutable objects: it is
possible to change part of a list (mutate it) rather than always returning a new list reflecting the
intended modifications. Moreover, since lists can share structure, changes to one list can sometimes
affect others.
k := [1 ,2]
[1, 2] (4)
List ( PositiveInteger )
m := cons (0 , k )
[0, 1, 2] (5)
List ( Integer )
99 (6)
PositiveInteger
List ( Integer )
[99, 2] (8)
List ( PositiveInteger )
An operation that is used frequently in list processing is that which returns all elements in a list after
the first element.
k := [1 ,2 ,3]
[1, 2, 3] (1)
List ( PositiveInteger )
[2, 3] (2)
List ( PositiveInteger )
[4, 3, 5] (3)
List ( PositiveInteger )
To get a list with elements in the order opposite to those in a list k, use reverse.
reverse [1 ,2 ,3 ,4 ,5 ,6]
[6, 5, 4, 3, 2, 1] (4)
List ( PositiveInteger )
To test whether an element is in a list, use member?: member?(a,k) returns true or false depending
on whether a is in k or not.
member ?(1/2 ,[3/4 ,5/6 ,1/2])
true (5)
Boolean
member ?(1/12 ,[3/4 ,5/6 ,1/2])
false (6)
9.52. LLLREDUCTION 495
Boolean
As an exercise, the reader should determine how to get a list containing all but the last of the elements
in a given non-empty list k.4
Certain lists are used so often that FriCAS provides an easy way of constructing them. If n and m
are integers, then expand [n..m] creates a list containing n, n+1, ... m. If n > m then the list is
empty. It is actually permissible to leave off the m in the dot-dot construction (see below).
The dot-dot notation can be used more than once in a list construction and with specific elements
being given. Items separated by dots are called segments.
[1..3 ,10 ,20..23]
Segments can be expanded into the range of items between the endpoints by using expand.
expand [1..3 ,10 ,20..23]
List ( Integer )
[1, 2, 3, 4, 5, 6, 7, . . .] (3)
Stream(Integer)
What is created in this case is a Stream which is a generalization of a list. See ‘Stream’ on page 578
for more information.
9.52 LLLReduction
The package LLLReduction implements LLL reduction. We show how to use it to find equation
satisfied by imaginary part of fifth primitive root of 1.
digits (24)
20 (4)
4 reverse(rest(reverse(k))) works.
496 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
PositiveInteger
0.951056516295153572116439 (5)
Float
lf := [ ii ^ i for i in 0..4]
List (Float)
List ( Integer )
− 16 x4 + 20 x2 − 5 (8)
Polynomial( Integer )
eval ( pol , x = ii )
0.0 (9)
Polynomial(Float)
9.53 LyndonWord
Initialisations
a : Symbol := ’ a
a (4)
Symbol
b : Symbol := ’ b
b (5)
Symbol
c : Symbol := ’ c
9.53. LYNDONWORD 497
c (6)
Symbol
LyndonWord(Symbol) (7)
Type
FreeMagma(Symbol) (8)
Type
FreeMonoid(Symbol) (9)
Type
a2 b , a2 c , a b2 , [a b c] , [a c b] , a c2 , b2 c , b c2
[[a] , [b] , [c]] , [[a b] , [a c] , [b c]] , (10)
OneDimensionalArray(List(LyndonWord(Symbol)))
List (LyndonWord(Symbol))
[a] , [b] , [a b] , a2 b , a b2 , a3 b , a2 b2 , a b3 , a4 b , a3 b2 , a2 b a b , a2 b3 , a b a b2 , a b4
(12)
List (LyndonWord(Symbol))
w1 : word := lw .4 :: word
a2 b (13)
FreeMonoid(Symbol)
w2 : word := lw .5 :: word
498 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
a b2 (14)
FreeMonoid(Symbol)
[[a]] (15)
List (LyndonWord(Symbol))
factor ( w1 * w2 ) $ lword
a2 b a b2
(16)
List (LyndonWord(Symbol))
factor ( w2 * w2 ) $ lword
a b2 , a b2
(17)
List (LyndonWord(Symbol))
factor ( w2 * w1 ) $ lword
a b2 , a2 b
(18)
List (LyndonWord(Symbol))
true (19)
Boolean
lyndon ?( w1 * w2 ) $ lword
true (20)
Boolean
lyndon ?( w2 * w1 ) $ lword
false (21)
Boolean
lyndonIfCan ( w1 ) $ lword
9.54. MAKEFUNCTION 499
a2 b
(22)
Union(LyndonWord(Symbol), ...)
lyndonIfCan ( w2 * w1 ) $ lword
"failed" (23)
lyndon ( w1 ) $ lword
a2 b
(24)
LyndonWord(Symbol)
lyndon ( w1 * w2 ) $ lword
a2 b a b2
(25)
LyndonWord(Symbol)
9.54 MakeFunction
It is sometimes useful to be able to define a function given by the result of a calculation. Suppose
that you have obtained the following expression after several computations and that you now want to
tabulate the numerical values of f for x between -1 and +1 with increment 0.1.
expr := ( x - exp x + 1) ^2 * ( sin ( x ^2) * x + 1) ^3
3
x3 (ex )2 + −2 x4 − 2 x3 ex + x5 + 2 x4 + x3 sin x2
2 (4)
+ 3 x2 (ex )2 + −6 x3 − 6 x2 ex + 3 x4 + 6 x3 + 3 x2 sin x2
+ 3 x (ex )2 + −6 x2 − 6 x ex + 3 x3 + 6 x2 + 3 x sin x2 + (ex )2 + (−2 x − 2) ex + x2 + 2 x + 1
Expression ( Integer )
You could, of course, use the function eval within a loop and evaluate expr twenty-one times, but
this would be quite slow. A better way is to create a numerical function f such that f(x) is defined
by the expression expr above, but without retyping expr! The package MakeFunction provides the
operation function which does exactly this. Issue this to create the function f(x) given by expr.
function ( expr , f , x )
f (5)
Symbol
Use the list [x1,...,xn] as the third argument to function to create a multivariate function f(x1
,...,xn).
e := ( x - y + 1) ^2 * ( x ^2 * y + 1) ^2
x4 y 4 + −2 x5 − 2 x4 + 2 x2 y 3 + x6 + 2 x5 + x4 − 4 x3 − 4 x2 + 1 y 2 (7)
+ 2 x4 + 4 x3 + 2 x2 − 2 x − 2 y + x2 + 2 x + 1
Polynomial( Integer )
function (e , g , [x , y ])
g (8)
Symbol
In the case of just two variables, they can be given as arguments without making them into a list.
function (e , h , x , y )
h (9)
Symbol
Note that the functions created by function are not limited to floating point numbers, but can be
applied to any type for which they are defined.
m1 := squareMatrix [[1 , 2] , [3 , 4]]
1 2
(10)
3 4
SquareMatrix(2, Integer )
1 0
(11)
−1 1
SquareMatrix(2, Integer )
h ( m1 , m2 )
Compiling function h with type ( SquareMatrix (2 , Integer ) , SquareMatrix (2 , Integer
)) -> SquareMatrix (2 , Integer )
−7836 8960
(12)
−17132 19588
9.55. MAPPINGPACKAGE1 501
SquareMatrix(2, Integer )
For more information, see Section 6.14 on page 169. Issue the system command )show MakeFunction
to display the full list of operations defined by MakeFunction.
9.55 MappingPackage1
Function are objects of type Mapping. In this section we demonstrate some library operations from
the packages MappingPackage1, MappingPackage2, and MappingPackage3 that manipulate
and create functions. Some terminology: a nullary function takes no arguments, a unary function
takes one argument, and a binary function takes two arguments.
We begin by creating an example function that raises a rational number to an integer exponent.
power ( q : FRAC INT , n : INT ) : FRAC INT == q ^ n
Function declaration power : ( Fraction ( Integer ) , Integer ) -> Fraction ( Integer )
has been added to workspace .
power (2 ,3)
Compiling function power with type ( Fraction ( Integer ) , Integer ) -> Fraction (
Integer )
8 (5)
Fraction ( Integer )
The twist operation transposes the arguments of a binary function. Here rewop(a, b) is power(b, a).
rewop := twist power
theMap(twist) (6)
This is 23 .
rewop (3 , 2)
8 (7)
Fraction ( Integer )
The curryRight operation creates a unary function from a binary one by providing a constant argument
on the right.
square := curryRight ( power , 2)
theMap(curryRight) (9)
502 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
16 (10)
Fraction ( Integer )
The constantRight operation creates (in a trivial way) a binary function from a unary one: constantRight
(f) is the function g such that g(a,b)= f(a).
squirrel := constantRight ( square ) $ MAPPKG3 ( FRAC INT , FRAC INT , FRAC INT )
theMap(constantRight) (11)
1
(12)
4
Fraction ( Integer )
theMap(curry) (13)
sixteen ()
16 (14)
Fraction ( Integer )
theMap(∗) (15)
square2 3
81 (16)
9.55. MAPPINGPACKAGE1 503
Fraction ( Integer )
Use the ^ operation to create functions that are n-fold iterations of other functions.
sc ( x : FRAC INT ) : FRAC INT == x + 1
Function declaration sc : Fraction ( Integer ) -> Fraction ( Integer ) has been added
to workspace .
Use the recur operation for recursion: g := recur f means g(n,x) == f(n,f(n-1,...f(1,x))).
times ( n : NNI , i : INT ) : INT == n * i
Function declaration times : ( NonNegativeInteger , Integer ) -> Integer has been
added to workspace .
r := recur ( times )
Compiling function times with type ( NonNegativeInteger , Integer ) -> Integer
theMap(recur) (21)
theMap(curryRight) (22)
(NonNegativeInteger → Integer )
fact 4
24 (23)
PositiveInteger
3
This is 32 .
mto2ton (3 , 3)
Compiling function mto2ton with type ( PositiveInteger , Po si ti v eI nt e ge r ) ->
Fraction ( Integer )
6561 (25)
Fraction ( Integer )
[0, 1] (27)
List ( Integer )
fibs := curry ( shiftfib , fibinit )
Compiling function shiftfib with type List ( Integer ) -> Integer
theMap(curry) (28)
(() → Integer )
[ fibs () for i in 0..30]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, (29)
6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040]
List ( Integer )
9.56 Matrix
The Matrix domain provides arithmetic operations on matrices and standard functions from linear
algebra. This domain is similar to the TwoDimensionalArray domain, except that the entries for
Matrix must belong to a Ring.
There are many ways to create a matrix from a collection of values or from existing matrices.
If the matrix has almost all items equal to the same value, use new to create a matrix filled with that
value and then reset the entries that are different.
9.56. MATRIX 505
0 0 0
0 0 0 (1)
0 0 0
Matrix( Integer )
To change the entry in the second row, third column to 5, use setelt!.
setelt !( m , 2 , 3 , 5)
5 (2)
PositiveInteger
10 (3)
PositiveInteger
0 10 0
0 0 5 (4)
0 0 0
Matrix( Integer )
If you already have the matrix entries as a list of lists, use matrix.
matrix [[1 ,2 ,3 ,4] ,[0 ,9 ,8 ,7]]
1 2 3 4
(5)
0 9 8 7
Matrix(NonNegativeInteger)
1 0 0 0 0
0
x2 0 0 0
x3
0 0 0 0 (6)
0 0 0 x4 0
0 0 0 0 x5
506 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Matrix(Polynomial( Integer ))
1 0 0 0 0
0
x2 0 0 0
x3
0 0 0 0 (7)
0 0 0 x4 0
1 1 1 1 1
Matrix(Polynomial( Integer ))
setColumn !( dm ,2 , vector [y ,y ,y ,y , y ])
1 y 0 0 0
0 y 0 0 0
x3
0 y 0 0 (8)
0 y 0 x4 0
1 y 1 1 1
Matrix(Polynomial( Integer ))
1 y 0 0 0
0 y 0 0 0
x3
0 y 0 0 (9)
0 y 0 x4 0
1 y 1 1 1
Matrix(Polynomial( Integer ))
This is useful if you intend to modify a matrix destructively but want a copy of the original.
setelt !( dm , 4 , 1 , 1 - x ^7)
− x7 + 1 (10)
Polynomial( Integer )
[ dm , cdm ]
1 y 0 0 0 1 y 0 0 0
0 y 0 0 0 0 y 0 0 0
x3
x3
7 0 y 0 0
,
0
y 0 0
(11)
−x + 1 y 0 x4 0 0 y 0 x4 0
1 y 1 1 1 1 y 1 1 1
9.56. MATRIX 507
Use subMatrix to extract part of an existing matrix. The syntax is subMatrix(m, firstrow, lastrow,
firstcol, lastcol).
subMatrix ( dm ,2 ,3 ,2 ,4)
y 0 0
(12)
y x3 0
Matrix(Polynomial( Integer ))
1.2 0.0 0.0 0.0
0.0 −1.3 0.0 0.0
0.0
(13)
0.0 1.4 0.0
0.0 0.0 0.0 −1.5
Matrix(Float)
If e is too big to fit where you specify, an error message is displayed. Use subMatrix to extract part of
e, if necessary.
e := matrix [[6.7 ,9.11] ,[ -31.33 ,67.19]]
6.7 9.11
(14)
−31.33 67.19
Matrix(Float)
This changes the submatrix of d whose upper left corner is at the first row and second column and
whose size is that of e.
setsubMatrix !( d ,1 ,2 , e )
1.2 6.7 9.11 0.0
0.0 −31.33 67.19 0.0
0.0
(15)
0.0 1.4 0.0
0.0 0.0 0.0 −1.5
Matrix(Float)
1.2 6.7 9.11 0.0
0.0 −31.33 67.19 0.0
0.0
(16)
0.0 1.4 0.0
0.0 0.0 0.0 −1.5
508 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Matrix(Float)
1 1 1
2 3 4 (17)
1 1 1
5 6 7
Matrix(Fraction ( Integer ))
3 3 3
5 7 11 (18)
3 3 3
13 17 19
Matrix(Fraction ( Integer ))
Use horizConcat to append them side to side. The two matrices must have the same number of rows.
horizConcat (a , b )
1 1 1 3 3 3
2 3 4 5 7 11 (19)
1 1 1 3 3 3
5 6 7 13 17 19
Matrix(Fraction ( Integer ))
Use vertConcat to stack one upon the other. The two matrices must have the same number of columns.
vab := vertConcat (a , b )
1 1 1
2 3 4
1 1 1
35 6
3
7
3 (20)
5 7 11
3 3 3
13 17 19
Matrix(Fraction ( Integer ))
The operation transpose is used to create a new matrix by reflection across the main diagonal.
transpose vab
1 1 3 3
2 5 5 13
1 1 3 3
(21)
3 6 7 17
1 1 3 3
4 7 11 19
Matrix(Fraction ( Integer ))
1 2
(1)
3 4
Matrix( Integer )
4 * m * ( -5)
−20 −40
(2)
−60 −80
Matrix( Integer )
You can add, subtract, and multiply matrices provided, of course, that the matrices have compatible
dimensions. If not, an error message is displayed.
n := matrix ([[1 ,0 , -2] ,[ -3 ,5 ,1]])
1 0 −2
(3)
−3 5 1
Matrix( Integer )
−5 10 0
(4)
−9 20 −2
Matrix( Integer )
The operations nrows and ncols return the number of rows and columns of a matrix. You can extract
a row or a column of a matrix using the operations row and column. The object returned is a Vector.
Here is the third column of the matrix n.
vec := column (n ,3)
[−2, 1] (5)
Vector( Integer )
You can multiply a matrix on the left by a “row vector” and on the right by a “column vector.”
vec * m
[1, 0] (6)
Vector( Integer )
Of course, the dimensions of the vector and the matrix must be compatible or an error message is
returned.
m * vec
510 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Vector( Integer )
The operation inverse computes the inverse of a matrix if the matrix is invertible, and returns "failed"
if not. This Hilbert matrix is invertible.
hilb := matrix ([[1/( i + j ) for i in 1..3] for j in 1..3])
1 1 1
2 3 4
1 1 1
(8)
3 4 5
1 1 1
4 5 6
Matrix(Fraction ( Integer ))
inverse ( hilb )
72 −240 180
−240 900 −720 (9)
180 −720 600
1 2 3 4
5 6 7 8
9
(10)
10 11 12
13 14 15 16
Matrix( Integer )
inverse ( mm )
"failed" (11)
The operation determinant computes the determinant of a matrix provided that the entries of the
matrix belong to a CommutativeRing. The above matrix mm is not invertible and, hence, must
have determinant 0.
determinant ( mm )
0 (12)
NonNegativeInteger
34 (13)
PositiveInteger
The operation rank computes the rank of a matrix: the maximal number of linearly independent rows
or columns.
rank ( mm )
2 (14)
PositiveInteger
The operation nullity computes the nullity of a matrix: the dimension of its null space.
nullity ( mm )
2 (15)
PositiveInteger
The operation nullSpace returns a list containing a basis for the null space of a matrix. Note that the
nullity is the number of elements in a basis for the null space.
nullSpace ( mm )
The operation rowEchelon returns the row echelon form of a matrix. It is easy to see that the rank of
this matrix is two and that its nullity is also two.
rowEchelon ( mm )
1 2 3 4
0 4 8 12
0
(17)
0 0 0
0 0 0 0
Matrix( Integer )
For more information on related topics, see Section 1.7 on page 43, Section 8.4 on page 267, Section
9.27.4 on page 423, ‘Permanent’ on page 532, ‘Vector’ on page 604, ‘OneDimensionalArray’ on page
518, and ‘TwoDimensionalArray’ on page 593. Issue the system command )show Matrix to display
the full list of operations defined by Matrix.
9.57 Multiset
The domain Multiset(R) is similar to Set(R) except that multiplicities (counts of duplications) are
maintained and displayed. Use the operation multiset to create multisets from lists. All the standard
512 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
operations from sets are available for multisets. An element with multiplicity greater than one has the
multiplicity displayed first, then a colon, and then the element.
Create a multiset of integers.
s := multiset [1 ,2 ,3 ,4 ,5 ,4 ,3 ,2 ,3 ,4 ,5 ,6 ,7 ,4 ,10]
Multiset ( PositiveInteger )
Multiset ( PositiveInteger )
Use remove! to remove an element. If a third argument is present, it specifies how many instances to
remove. Otherwise all instances of the element are removed. Display the resulting multiset.
remove !(3 , s ,1) ; s
Multiset ( PositiveInteger )
remove !(5 , s ) ; s
Multiset ( PositiveInteger )
0 (8)
NonNegativeInteger
A second multiset.
t := multiset [2 ,2 ,2 , -9]
{3 : 2, −9} (9)
Multiset ( Integer )
Multiset ( Integer )
The intersect operation gives the elements that are in common, with additive multiplicity.
I := intersect (s , t )
{5 : 2} (11)
Multiset ( Integer )
The difference of s and t consists of the elements that s has but t does not. Elements are regarded as
indistinguishable, so that if s and t have any element in common, the difference does not contain that
element.
difference (s , t )
{10, 7, 6, 4 : 4, 3 : 3, 1} (12)
Multiset ( Integer )
Multiset ( Integer )
Check that the union of the symmetricDifference and the intersect equals the union of the elements.
( U = union (S , I ) ) @Boolean
true (14)
Boolean
List (Boolean)
9.58 MultivariatePolynomial
The domain constructor MultivariatePolynomial is similar to Polynomial except that it specifies
the variables to be used. Most functions available for Polynomial are available for Multivariate-
Polynomial. The abbreviation for MultivariatePolynomial is MPOLY. The type expressions
refer to the domain of multivariate polynomials in the variables x and y where the coefficients are
restricted to be integers. The first variable specified is the main variable and the display of the
polynomial reflects this. This polynomial appears with terms in descending powers of the variable
x.
m : MPOLY ([ x , y ] , INT ) := ( x ^2 - x * y ^3 +3* y ) ^2
x4 − 2 y 3 x3 + y 6 + 6 y x2 − 6 y 4 x + 9 y 2
(4)
MultivariatePolynomial ([ x, y ], Integer )
x2 y 6 − 6 x y 4 − 2 x3 y 3 + 9 y 2 + 6 x2 y + x4 (5)
MultivariatePolynomial ([ y, x ], Integer )
You can use other, unspecified variables, by using Polynomial in the coefficient type of MPOLY.
p : MPOLY ([ x , y ] , POLY INT )
p := ( a ^2* x - b * y ^2 + 1) ^2
a4 x2 + −2 a2 b y 2 + 2 a2 x + b2 y 4 − 2 b y 2 + 1
(7)
Conversions can be used to re-express such polynomials in terms of the other variables. For example,
you can first push all the variables into a polynomial with integer coefficients.
p :: POLY INT
b2 y 4 + −2 a2 b x − 2 b y 2 + a4 x2 + 2 a2 x + 1
(8)
Polynomial( Integer )
x2 a4 + −2 x y 2 b + 2 x a2 + y 4 b2 − 2 y 2 b + 1
(9)
Restriction:
FriCAS does not allow you to create types where MultivariatePolynomial is con-
tained in the coefficient type of Polynomial. Therefore, MPOLY([x,y],POLY INT) is
legal but POLY MPOLY([x,y],INT) is not.
Multivariate polynomials may be combined with univariate polynomials to create types with special
structures.
9.59. NONE 515
−2 z − 2 3 4 y 2 + z 2 + 2 z + 1 2 −4 z − 4
x4 + x + x + x+4 (11)
y y2 y
UnivariatePolynomial (x, Fraction ( MultivariatePolynomial ([ y, z ], Integer )))
Use conversions for structural rearrangements. z does not appear in a denominator and so it can be
made the main variable.
q :: UP (z , FRAC MPOLY ([ x , y ] , INT ) )
y 2 x4 − 2 y x3 + 4 y 2 + 1 x2 − 4 y x + 4 y 2
x2 2 −2 y x3 + 2 x2 − 4 y x
z + z + (12)
y2 y2 y2
UnivariatePolynomial (z, Fraction ( MultivariatePolynomial ([ x, y ], Integer )))
Or you can make a multivariate polynomial in x and z whose coefficients are fractions in polynomials
in y.
q :: MPOLY ([ x , z ] , FRAC UP (y , INT ) )
4 y2 + 1
2 2 1 2 2 4 4
x4 + − z − x3 + z + z + x2
+ − z − x+4 (13)
y y y2 y2 y2 y y
A conversion like q :: MPOLY([x,y], FRAC UP(z,INT)) is not possible in this example because y
appears in the denominator of a fraction. As you can see, FriCAS provides extraordinary flexibility in
the manipulation and display of expressions via its conversion facility.
For more information on related topics, see ‘Polynomial’ on page 533, ‘UnivariatePolynomial’ on
page 597, and ‘DistributedMultivariatePolynomial’ on page 394. Issue the system command )show
MultivariatePolynomial to display the full list of operations defined by MultivariatePolynomial.
9.59 None
The None domain is not very useful for interactive work but it is provided nevertheless for completeness
of the FriCAS type system. Probably the only place you will ever see it is if you enter an empty list
with no type information.
[]
[] (4)
List (None)
Such an empty list can be converted into an empty list of any other type.
516 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
[] :: List Float
[] (5)
List (Float)
If you wish to produce an empty list of a particular type directly, such as List NonNegativeInteger,
do it this way.
[] $ List ( N o n N e g a t i v e I n t e g e r )
[] (6)
List (NonNegativeInteger)
9.60 Octonion
The Octonions, also called the Cayley-Dixon algebra, defined over a commutative ring are an eight-
dimensional non-associative algebra. Their construction from quaternions is similar to the construction
of quaternions from complex numbers (see ‘Quaternion’ on page 540). As Octonion creates an
eight-dimensional algebra, you have to give eight components to construct an octonion.
oci1 := octon (1 ,2 ,3 ,4 ,5 ,6 ,7 ,8)
1 + 2i + 3j + 4k + 5E + 6I + 7J + 8K (4)
Octonion(Integer)
7 + 2i + 3j − 4k + 5E + 6I − 7J (5)
Octonion(Integer)
− 7 − 12 i + 3 j − 10 k + 5 E + 6 I + 9 J (6)
Octonion(Integer)
Octonion(Integer)
As with the quaternions, we have a real part, the imaginary parts i, j, k, and four additional imaginary
parts E, I, J and K. These parts correspond to the canonical basis (1,i,j,k,E,I,J,K). For each
9.60. OCTONION 517
basis element there is a component operation to extract the coefficient of the basis element for a given
octonion.
[ real oci1 , imagi oci1 , imagj oci1 , imagk oci1 , imagE oci1 , imagI oci1 , imagJ oci1 ,
imagK oci1 ]
[1, 2, 3, 4, 5, 6, 7, 8] (8)
List ( PositiveInteger )
A basis with respect to the quaternions is given by (1,E). However, you might ask, what then are the
commuting rules? To answer this, we create some generic elements. We do this in FriCAS by simply
changing the ground ring from Integer to Polynomial Integer.
q : Quaternion Polynomial Integer := quatern ( q1 , qi , qj , qk )
q1 + qi i + qj j + qk k (9)
Quaternion(Polynomial(Integer ))
E (10)
Octonion(Polynomial(Integer))
Note that quaternions are automatically converted to octonions in the obvious way.
q * E
q1 E + qi I + qj J + qk K (11)
Octonion(Polynomial(Integer))
E * q
q1 E − qi I − qj J − qk K (12)
Octonion(Polynomial(Integer))
q1 + qi i + qj j + qk k (13)
Octonion(Polynomial(Integer))
q1 + qi i + qj j + qk k (14)
Octonion(Polynomial(Integer))
Finally, we check that the norm, defined as the sum of the squares of the coefficients, is a multiplicative
map.
o : Octonion Polynomial Integer := octon ( o1 , oi , oj , ok , oE , oI , oJ , oK )
518 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
o1 + oi i + oj j + ok k + oE E + oI I + oJ J + oK K (15)
Octonion(Polynomial(Integer))
norm o
Polynomial( Integer )
p1 + pi i + pj j + pk k + pE E + pI I + pJ J + pK K (17)
Octonion(Polynomial(Integer))
Polynomial( Integer )
Issue the system command )show Octonion to display the full list of operations defined by Octonion.
9.61 OneDimensionalArray
The OneDimensionalArray domain is used for storing data in a one-dimensional indexed data
structure. Such an array is a homogeneous data structure in that all the entries of the array must
belong to the same FriCAS domain. Each array has a fixed length specified by the user and arrays
are not extensible. The indexing of one-dimensional arrays is one-based. This means that the “first”
element of an array is given the index 1. See also ‘Vector’ on page 604 and ‘FlexibleArray’ on page
416. To create a one-dimensional array, apply the operation oneDimensionalArray to a list.
o n e D i m e n s i o n a l A r r a y [ i ^2 for i in 1..10]
OneDimensionalArray( PositiveInteger )
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (5)
OneDimensionalArray(Integer)
OneDimensionalArray(Integer)
OneDimensionalArray(Integer)
OneDimensionalArray(Integer)
OneDimensionalArray(Integer)
OneDimensionalArray(Integer)
OneDimensionalArray(Integer)
[36, 49, 64, 81, 100, 36, 49, 64, 81, 100] (12)
OneDimensionalArray(Integer)
9.62 Operator
Given any ring R, the ring of the Integer-linear operators over R is called Operator(R). To create
an operator over R, first create a basic operator using the operation operator, and then convert it to
Operator(R) for the R you want. We choose R to be the two by two matrices over the integers.
R := SQMATRIX (2 , INT )
Type
tilde (5)
Operator(SquareMatrix(2, Integer ))
Since Operator is unexposed we must either package-call operations from it, or expose it explicitly.
For convenience we will do the latter. Expose Operator.
) set expose add constructor Operator
tilde (6)
Operator(SquareMatrix(2, Integer ))
Operators can be manipulated formally as in any ring: + is the pointwise addition and * is composition.
Any element x of R can be converted to an operator opx over R, and the evaluation function of opx is
left-multiplication by x. Multiplying on the left by this matrix swaps the two rows.
s : R := matrix [[0 , 1] , [1 , 0]]
9.62. OPERATOR 521
0 1
(7)
1 0
SquareMatrix(2, Integer )
0 1
tilde (8)
1 0
Operator(SquareMatrix(2, Integer ))
Hint: applying rho four times gives the identity, so rho^4-1 should return 0 when applied to any two
by two matrix.
z := rho ^4 - 1
0 1 0 1 0 1 0 1
− 1 + tilde tilde tilde tilde (9)
1 0 1 0 1 0 1 0
Operator(SquareMatrix(2, Integer ))
1 2
(10)
3 4
SquareMatrix(2, Integer )
z m
0 0
(11)
0 0
SquareMatrix(2, Integer )
As you have probably guessed by now, rho acts on matrices by rotating the elements clockwise.
rho m
3 1
(12)
4 2
SquareMatrix(2, Integer )
rho rho m
4 3
(13)
2 1
522 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
SquareMatrix(2, Integer )
( rho ^3) m
2 4
(14)
1 3
SquareMatrix(2, Integer )
Do the swapping of rows and transposition commute? We can check by computing their bracket.
b := t * s - s * t
0 1 0 1
− tilde + tilde (15)
1 0 1 0
Operator(SquareMatrix(2, Integer ))
Now apply it to m.
b m
1 −3
(16)
3 −1
SquareMatrix(2, Integer )
Next we demonstrate how to define a differential operator on a polynomial ring. This is the recursive
definition of the n-th Legendre polynomial.
L n ==
n = 0 => 1
n = 1 => x
(2* n -1) / n * x * L (n -1) - (n -1) / n * L (n -2)
d
Create the differential operator dx on polynomials in x over the rational numbers.
dx := operator (" D ") :: OP ( POLY FRAC INT )
D (18)
D (19)
L 15
Compiling function L with type Integer -> Polynomial ( Fraction ( Integer ))
Compiling function L as a recurrence relation .
Polynomial(Fraction ( Integer ))
240 − 2 x D + −x2 + 1 D2
(22)
0 (23)
Polynomial(Fraction ( Integer ))
9.63 OrderedVariableList
The domain OrderedVariableList provides symbols which are restricted to a particular list and have
a definite ordering. Those two features are specified by a List Symbol object that is the argument to
the domain. This is a sample ordering of three symbols.
ls : List Symbol :=[ ’ x , ’a , ’ z ]
[x, a, z] (4)
List (Symbol)
3 (6)
NonNegativeInteger
[x, a, z] (7)
List ( OrderedVariableList ([ x, a, z ]) )
true (8)
Boolean
9.64 OrderlyDifferentialPolynomial
Many systems of differential equations may be transformed to equivalent systems of ordinary differ-
ential equations where the equations are expressed polynomially in terms of the unknown functions.
In FriCAS, the domain constructors OrderlyDifferentialPolynomial (abbreviated ODPOL) and
SequentialDifferentialPolynomial (abbreviation SDPOL) implement two domains of ordinary dif-
ferential polynomials over any differential ring. In the simplest case, this differential ring is usually
either the ring of integers, or the field of rational numbers. However, FriCAS can handle ordinary
differential polynomials over a field of rational functions in a single indeterminate.
The two domains ODPOL and SDPOL are almost identical, the only difference being the choice of a
different ranking, which is an ordering of the derivatives of the indeterminates. The first domain uses
an orderly ranking, that is, derivatives of higher order are ranked higher, and derivatives of the same
order are ranked alphabetically. The second domain uses a sequential ranking, where derivatives are
ordered first alphabetically by the differential indeterminates, and then by order. A more general do-
main constructor, DifferentialSparseMultivariatePolynomial (abbreviation DSMP) allows both
a user-provided list of differential indeterminates as well as a user-defined ranking. We shall illus-
trate ODPOL(FRAC INT), which constructs a domain of ordinary differential polynomials in an
arbitrary number of differential indeterminates with rational numbers as coefficients.
dpol := ODPOL ( FRAC INT )
OrderlyDifferentialPolynomial(Fraction(Integer)) (4)
Type
w := makeVariable ( ’ w ) $ dpol
theMap(makeVariable) (5)
z := makeVariable ( ’ z ) $ dpol
theMap(makeVariable) (6)
The fifth derivative of w can be obtained by applying the map w to the number 5. Note that the order
of differentiation is given as a subscript (except when the order is 0).
w .5
w5 (7)
w 0
w (8)
[z1 , z2 , z3 , z4 , z5 ] (9)
The usual arithmetic can be used to form a differential polynomial from the derivatives.
f := w .4 - w .1 * w .1 * z .3
w4 − (w1 )2 z3 (10)
w5 − (w1 )2 z4 − 2 w1 w2 z3 (12)
The same operation can compute higher derivatives, like the fourth derivative.
D (f ,4)
The operation makeVariable creates a map to facilitate referencing the derivatives of f, similar to the
map w.
df := makeVariable ( f ) $ dpol
theMap(makeVariable) (14)
The operation order returns the order of a differential polynomial, or the order in a specified differential
indeterminate.
order ( g )
2 (16)
PositiveInteger
order (g , ’w )
2 (17)
PositiveInteger
[z, w] (18)
9.64. ORDERLYDIFFERENTIALPOLYNOMIAL 527
List (Symbol)
The operation degree returns the degree, or the degree in the differential indeterminate specified.
degree ( g )
degree (g , ’w )
1 (20)
PositiveInteger
The operation weights returns a list of weights of differential monomials appearing in differential poly-
nomial, or a list of weights in a specified differential indeterminate.
weights ( g )
[7, 2] (21)
List (NonNegativeInteger)
weights (g , ’ w )
[2] (22)
List (NonNegativeInteger)
The operation weight returns the maximum weight of all differential monomials appearing in the
differential polynomial.
weight ( g )
7 (23)
PositiveInteger
A differential polynomial is isobaric if the weights of all differential monomials appearing in it are
equal.
isobaric ?( g )
false (24)
Boolean
To substitute differentially, use eval. Note that we must coerce ’w to Symbol, since in ODPOL,
differential indeterminates belong to the domain Symbol. Compare this result to the next, which
substitutes algebraically (no substitution is done since w.0 does not appear in g).
eval (g ,[ ’ w :: Symbol ] ,[ f ])
528 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
variables ( g )
[z2 , w2 , z1 ] (28)
gcd (f , g )
1 (29)
groebner ([ f , g ])
The next three operations are essential for elimination procedures in differential polynomial rings. The
operation leader returns the leader of a differential polynomial, which is the highest ranked derivative
of the differential indeterminates that occurs.
lg := leader ( g )
z2 (31)
OrderlyDifferentialVariable (Symbol)
The operation separant returns the separant of a differential polynomial, which is the partial derivative
with respect to the leader.
sg := separant ( g )
9.64. ORDERLYDIFFERENTIALPOLYNOMIAL 529
2 (z1 )3 z2 (32)
The operation initial returns the initial, which is the leading coefficient when the given differential
polynomial is expressed as a polynomial in the leader.
ig := initial ( g )
(z1 )3 (33)
Using these three operations, it is possible to reduce f modulo the differential ideal generated by g.
The general scheme is to first reduce the order, then reduce the degree in the leader. First, eliminate
z.3 using the derivative of g.
g1 := D g
z3 (35)
OrderlyDifferentialVariable (Symbol)
− (w1 )2 (36)
Note that high powers of lg still appear in prf. Compute the leading coefficient of prf as a polynomial
in the leader of g.
lcf := l e a d i n g C o e f f i c i e n t univariate ( prf , lg )
Finally, continue eliminating the high powers of lg appearing in prf to obtain the (pseudo) remainder
of f modulo g and its derivatives.
ig * prf - lcf * g * lg
Issue the system command )show OrderlyDifferentialPolyomial to display the full list of opera-
tions defined by OrderlyDifferentialPolyomial. Issue the system command )show SequentialDifferentialPolynomi
to display the full list of operations defined by SequentialDifferentialPolynomial.
9.65 PartialFraction
A partial fraction is a decomposition of a quotient into a sum of quotients where the denominators of the
summands are powers of primes.5 For example, the rational number 1/6 is decomposed into 1/2 -1/3
. You can compute partial fractions of quotients of objects from domains belonging to the category
EuclideanDomain. For example, Integer, Complex Integer, and UnivariatePolynomial(x,
Fraction Integer) all belong to EuclideanDomain. In the examples following, we demonstrate
how to decompose quotients of each of these kinds of object into partial fractions. Issue the system
command )show PartialFraction to display the full list of operations defined by PartialFraction.
It is necessary that we know how to factor the denominator when we want to compute a partial
fraction. Although the interpreter can often do this automatically, it may be necessary for you to
include a call to factor. In these examples, it is not necessary to factor the denominators explicitly.
The main operation for computing partial fractions is called partialFraction and we use this to compute
a decomposition of 1 / 10!. The first argument to partialFraction is the numerator of the quotient and
the second argument is the factored denominator.
p ar ti al F ra ct io n (1 , factorial 10)
97 58 13 6
− + 4 + 2 − (4)
28 3 5 7
PartialFraction ( Integer )
Since the denominators are powers of primes, it may be possible to expand the numerators further
with respect to those primes. Use the operation padicFraction to do this.
f := padicFraction (%)
1 1 1 2 1 1 2 3 6
− − 3 − 8 + + 3 + 4 + + 2 − (5)
22 2 2 3 3 3 5 5 7
PartialFraction ( Integer )
The operation compactFraction returns an expanded fraction into the usual form. The compacted
version is used internally for computational efficiency.
5 Most people first encounter partial fractions when they are learning integral calculus. For a technical discussion of
c om pa ct F ra ct io n ( f )
97 58 13 6
− + 4 + 2 − (6)
28 3 5 7
PartialFraction ( Integer )
You can add, subtract, multiply and divide partial fractions. In addition, you can extract the parts
of the decomposition. numberOfFractionalTerms computes the number of terms in the fractional part.
This does not include the whole part of the fraction, which you get by calling wholePart. In this
example, the whole part is just 0.
numberOfFractionalTerms (f)
9 (7)
PositiveInteger
The operation fractionalTerms returns the individual terms in the decomposition. Notice that the
object returned is a list of Record(num : R, den : Factored(R)), you can extract the numerator
and denominator from this object.
f ra ct io n al Te rm s ( f ) .3
Given two gaussian integers (see ‘Complex’ on page 372), you can decompose their quotient into a
partial fraction.
p ar ti al F ra ct io n (1 , - 13 + 14 * % i )
1 4
− + (9)
1 + 2i 3 + 8i
PartialFraction (Complex(Integer))
i
− (10)
14 + 13 i
Fraction (Complex(Integer))
The polynomials in this object have type UnivariatePolynomial(x, Fraction Integer). We use
the primeFactor operation (see ‘Factored’ on page 405) to create the denominator in factored form
directly.
532 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
These are the compact and expanded partial fractions for the quotient.
p ar ti al F ra ct io n (1 , u )
1
648
1
4
x+ 7
16
− 17
8
x2 − 12 x − 139
8
607
324
x3 + 10115
432
x2 + 391
4
x+ 44179
324
+ 2 + 3 + 4 (12)
x+1 (x + 2) (x + 3) (x + 4)
padicFraction %
607 403 13 1 17 3 1 1 1 1
324 432 36 12 8 4 2 4 16 648
+ + + − + − + − + (13)
x+4 (x + 4)2 (x + 4)3 (x + 4)4 x+3 (x + 3)2 (x + 3)3 x+2 (x + 2)2 x+1
All see ‘FullPartialFractionExpansion’ on page 429 for examples of factor-free conversion of quo-
tients to full partial fractions.
9.66 Permanent
The package Permanent provides the function permanent for square matrices. The permanent of a
square matrix can be computed in the same way as the determinant by expansion of minors except that
for the permanent the sign for each element is 1, rather than being 1 if the row plus column indices
is positive and -1 otherwise. This function is much more difficult to compute efficiently than the
determinant. An example of the use of permanent is the calculation of the nth derangement number,
defined to be the number of different possibilities for n couples to dance but never with their own
spouse. Consider an n by n matrix with entries 0 on the diagonal and 1 elsewhere. Think of the rows
as one-half of each couple (for example, the males) and the columns the other half. The permanent of
such a matrix gives the desired derangement number.
kn n ==
r : MATRIX INT := new (n ,n ,1)
for i in 1.. n repeat
r (i , i ) := 0
r
Here are some derangement numbers, which you see grow quite fast.
permanent ( kn (5) :: SQMATRIX (5 , INT ) )
Compiling function kn with type P o si ti ve I nt eg er -> Matrix ( Integer )
44 (5)
9.67. POLYNOMIAL 533
PositiveInteger
[ permanent ( kn ( n ) :: SQMATRIX (n , INT ) ) for n in 1..13]
Cannot compile conversion for types involving local variables . In particular ,
could not compile the expression involving :: SQMATRIX (n , INT )
FriCAS will attempt to step through and interpret the code .
[0, 1, 2, 9, 44, 265, 1854, 14833, 133496, 1334961, 14684570, 176214841, 2290792932] (6)
List (NonNegativeInteger)
9.67 Polynomial
The domain constructor Polynomial (abbreviation: POLY) provides polynomials with an arbitrary
number of unspecified variables.
It is used to create the default polynomial domains in FriCAS. Here the coefficients are integers.
x + 1
x+1 (4)
Polynomial( Integer )
z − 2.3 (5)
Polynomial(Float)
And here we have a polynomial in two variables with coefficients which have type Fraction Integer.
y ^2 - z + 3/4
3
− z + y2 + (6)
4
Polynomial(Fraction ( Integer ))
The representation of objects of domains created by Polynomial is that of recursive univariate poly-
nomials.6 This recursive structure is sometimes obvious from the display of a polynomial.
y ^2 + x * y + y
y 2 + (x + 1) y (7)
Polynomial( Integer )
In this example, you see that the polynomial is stored as a polynomial in y with coefficients that are
polynomials in x with integer coefficients. In fact, you really don’t need to worry about the representa-
tion unless you are working on an advanced application where it is critical. The polynomial types cre-
ated from DistributedMultivariatePolynomial and NewDistributedMultivariatePolynomial
6 The term univariate means “one variable.” multivariate means “possibly more than one variable.”
534 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
y2 + y x + y (8)
DistributedMultivariatePolynomial ([ y, x ], Integer )
We will demonstrate many of the polynomial facilities by using two polynomials with integer coeffi-
cients. By default, the interpreter expands polynomial expressions, even if they are written in a
factored format.
p := (y -1) ^2 * x * z
x y2 − 2 x y + x z
(9)
Polynomial( Integer )
See ‘Factored’ on page 405 to see how to create objects in factored form directly.
q := (y -1) * x * ( z +5)
(x y − x) z + 5 x y − 5 x (10)
Polynomial( Integer )
x (y − 1) (z + 5) (11)
Factored(Polynomial( Integer ))
This is the same name used for the operation to factor integers. Such reuse of names is called overloading
and makes it much easier to think of solving problems in general ways. FriCAS facilities for factoring
polynomials created with Polynomial are currently restricted to the integer and rational number
coefficient cases. There are more complete facilities for factoring univariate polynomials: see Section
8.2 on page 260.
The standard arithmetic operations are available for polynomials.
p - q ^2
−x2 y 2 + 2 x2 y − x2 z 2 + −10 x2 + x y 2 + 20 x2 − 2 x y − 10 x2 + x z − 25 x2 y 2 + 50 x2 y − 25 x2
(12)
Polynomial( Integer )
The operation gcd is used to compute the greatest common divisor of two polynomials.
gcd (p , q )
9.67. POLYNOMIAL 535
xy − x (13)
Polynomial( Integer )
In the case of p and q, the gcd is obvious from their definitions. We factor the gcd to show this
relationship better.
factor %
x (y − 1) (14)
Factored(Polynomial( Integer ))
x y 2 − 2 x y + x z 2 + 5 x y 2 − 10 x y + 5 x z
(15)
Polynomial( Integer )
Use content to compute the greatest common divisor of the coefficients of the polynomial.
content p
1 (16)
PositiveInteger
Many of the operations on polynomials require you to specify a variable. For example, resultant requires
you to give the variable in which the polynomials should be expressed. This computes the resultant
of the values of p and q, considering them as polynomials in the variable z. They do not share a root
when thought of as polynomials in z.
resultant (p ,q , z )
5 x2 y 3 − 15 x2 y 2 + 15 x2 y − 5 x2 (17)
Polynomial( Integer )
0 (18)
Polynomial( Integer )
The data type used for the variables created by Polynomial is Symbol. As mentioned above, the
representation used by Polynomial is recursive and so there is a main variable for nonconstant poly-
nomials. The operation mainVariable returns this variable. The return type is actually a union of
Symbol and "failed".
mainVariable p
536 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
z (19)
Union(Symbol, ...)
The latter branch of the union is be used if the polynomial has no variables, that is, is a constant.
mainVariable (1 :: POLY INT )
"failed" (20)
You can also use the predicate ground? to test whether a polynomial is in fact a member of its ground
ring.
ground ? p
false (21)
Boolean
ground ?(1 :: POLY INT )
true (22)
Boolean
The complete list of variables actually used in a particular polynomial is returned by variables. For
constant polynomials, this list is empty.
variables p
[z, y, x] (23)
List (Symbol)
1 (24)
PositiveInteger
degree (p , y )
2 (25)
PositiveInteger
degree (p , z )
1 (26)
9.67. POLYNOMIAL 537
PositiveInteger
If you give a list of variables for the second argument, a list of the degrees in those variables is returned.
degree (p ,[ x ,y , z ])
[1, 2, 1] (27)
List (NonNegativeInteger)
1 (28)
PositiveInteger
4 (29)
PositiveInteger
It is often convenient to think of a polynomial as a leading monomial plus the remaining terms.
l ea di ng M on om ia l p
x y2 z (30)
Polynomial( Integer )
The reductum operation returns a polynomial consisting of the sum of the monomials after the first.
reductum p
(−2 x y + x) z (31)
Polynomial( Integer )
These have the obvious relationship that the original polynomial is equal to the leading monomial plus
the reductum.
p - l ea di ng M on om ia l p - reductum p
0 (32)
Polynomial( Integer )
The value returned by leadingMonomial includes the coefficient of that term. This is extracted by using
leadingCoefficient on the original polynomial.
leadingCoefficient p
538 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
1 (33)
PositiveInteger
x y2 − 2 x y + x z
(34)
Polynomial( Integer )
w y2 − 2 w y + w z
(35)
Polynomial( Integer )
eval (p ,x ,1)
y2 − 2 y + 1 z
(36)
Polynomial( Integer )
Actually, all the things being substituted are just polynomials, some more trivial than others.
eval (p ,x , y ^2 - 1)
y4 − 2 y3 + 2 y − 1 z
(37)
Polynomial( Integer )
y2 − 2 y + 1 z
(38)
Polynomial( Integer )
The first argument is the polynomial and the second is the variable.
D (p , y )
(2 x y − 2 x) z (39)
Polynomial( Integer )
Even if the polynomial has only one variable, you must specify it.
D (p , z )
9.67. POLYNOMIAL 539
x y2 − 2 x y + x (40)
Polynomial( Integer )
1
x y3 − x y2 + x y z (41)
3
Polynomial(Fraction ( Integer ))
It is not possible, in general, to divide two polynomials. In our example using polynomials over the
integers, the operation monicDivide divides a polynomial by a monic polynomial (that is, a polynomial
with leading coefficient equal to 1). The result is a record of the quotient and remainder of the division.
You must specify the variable in which to express the polynomial.
qr := monicDivide (p , x +1 , x )
quotient = y 2 − 2 y + 1 z, remainder = −y 2 + 2 y − 1 z
(42)
The selectors of the components of the record are quotient and remainder. Issue this to extract the
remainder.
qr . remainder
−y 2 + 2 y − 1 z
(43)
Polynomial( Integer )
Now that we can extract the components, we can demonstrate the relationship among them and the
arguments to our original expression qr := monicDivide(p,x+1,x).
p - (( x +1) * qr . quotient + qr . remainder )
0 (44)
Polynomial( Integer )
If the / operator is used with polynomials, a fraction object is created. In this example, the result is
an object of type Fraction Polynomial Integer.
p/q
(y − 1) z
(45)
z+5
540 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
If you use rational numbers as polynomial coefficients, the resulting object is of type Polynomial
Fraction Integer.
(2/3) * x ^2 - y + 4/5
2 2 4
−y+ x + (46)
3 5
Polynomial(Fraction ( Integer ))
−15 y + 10 x2 + 12
(47)
15
Fraction (Polynomial( Integer ))
2 2 4
−y+ x + (48)
3 5
Polynomial(Fraction ( Integer ))
To convert the coefficients to floating point, map the numeric operation on the coefficients of the
polynomial.
map ( numeric ,%)
Polynomial(Float)
For more information on related topics, see ‘UnivariatePolynomial’ on page 597, ‘MultivariatePolynomial’
on page 513, and ‘DistributedMultivariatePolynomial’ on page 394. You can also issue the system
command )show Polynomial to display the full list of operations defined by Polynomial.
9.68 Quaternion
The domain constructor Quaternion implements Hamilton quaternions over commutative rings. For
information on related topics, see ‘GeneralQuaternion’ on page 432, ‘Complex’ on page 372 and
‘Octonion’ on page 516. You can also issue the system command )show Quaternion to display the
full list of operations defined by Quaternion.
The basic operation for creating quaternions is quatern. This is a quaternion over the rational numbers.
q := quatern (2/11 , -8 ,3/4 ,1)
9.68. QUATERNION 541
2 3
− 8i + j + k (4)
11 4
Quaternion(Fraction( Integer ))
The four arguments are the real part, the i imaginary part, the j imaginary part, and the k imaginary
part, respectively.
[ real q , imagI q , imagJ q , imagK q ]
2 3
, −8, , 1 (5)
11 4
Because q is over the rationals (and nonzero), you can invert it.
inv q
20 119
− − 5i + j − 88 k (8)
11 36
Quaternion(Fraction( Integer ))
2495 817
− i − 1418 j − k (9)
18 18
Quaternion(Fraction( Integer ))
There are no predefined constants for the imaginary i, j, and k parts, but you can easily define them.
i := quatern (0 ,1 ,0 ,0) ; j := quatern (0 ,0 ,1 ,0) ; k := quatern (0 ,0 ,0 ,1)
k (10)
542 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Quaternion(Integer )
2 3
−1, −1, −1, k, i, j, 8 + i+j− k (11)
11 4
126993
(12)
1936
Fraction ( Integer )
conjugate q
2 3
+ 8i − j − k (13)
11 4
Quaternion(Fraction( Integer ))
q * %
126993
(14)
1936
Quaternion(Fraction( Integer ))
9.69 RadixExpansion
It possible to expand numbers in general bases.
Here we expand 111 in base 5. This means 102 + 101 + 100 = 4 · 52 + 2 · 51 + 50 .
111:: RadixEx pansion (5)
421 (4)
RadixExpansion(5)
0.00110 (5)
9.69. RADIXEXPANSION 543
RadixExpansion(2)
0.012 (6)
RadixExpansion(3)
0.152 (7)
RadixExpansion(8)
0.2083 (8)
RadixExpansion(10)
0.26 (9)
RadixExpansion(12)
0.35 (10)
RadixExpansion(16)
0.7I (11)
RadixExpansion(36)
For bases greater than 36, the ragits are separated by blanks.
(5/24) :: RadixE xpansion (38)
0 . 7 34 31 25 12 (12)
RadixExpansion(38)
The RadixExpansion type provides operations to obtain the individual ragits. Here is a rational
number in base 8.
a := (76543/210) :: RadixExp ansion (8)
544 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
554.37307 (13)
RadixExpansion(8)
The operation wholeRagits returns a list of the ragits for the integral part of the number.
w := wholeRagits a
[5, 5, 4] (14)
List ( Integer )
The operations prefixRagits and cycleRagits return lists of the initial and repeating ragits in the fractional
part of the number.
f0 := prefixRagits a
[3] (15)
List ( Integer )
f1 := cycleRagits a
[7, 3, 0, 7] (16)
List ( Integer )
You can construct any radix expansion by giving the whole, prefix and cycle parts. The declaration is
necessary to let FriCAS know the base of the ragits.
u : RadixExp ansion (8) := wholeRadix ( w ) + fractRadix ( f0 , f1 )
554.37307 (17)
RadixExpansion(8)
0.123B0 (18)
RadixExpansion(12)
If you are not interested in the repeating nature of the expansion, an infinite stream of ragits can be
obtained using fractRagits.
fractRagits ( u )
3, 7, 3, 0, 7, 7 (19)
Stream(Integer)
a :: Fraction ( Integer )
76543
(20)
210
Fraction ( Integer )
Issue the system command )show RadixExpansion to display the full list of operations defined by
RadixExpansion. More examples of expansions are available in ‘DecimalExpansion’ on page 388,
‘BinaryExpansion’ on page 348, and ‘HexadecimalExpansion’ on page 440.
9.70 RealClosure
The Real Closure 1.0 package provided by Renaud Rioboo ([email protected]) consists of different
packages, categories and domains :
CAVEATS
Since real algebraic expressions are stored as depending on ”real roots” which are managed like vari-
ables, there is an ordering on these. This ordering is dynamical in the sense that any new algebraic
takes precedence over older ones. In particular every creation function raises a new ”real root”. This
has the effect that when you type something like sqrt(2) + sqrt(2) you have two new variables which
happen to be equal. To avoid this name the expression such as in s2 := sqrt(2); s2 + s2
Also note that computing times depend strongly on the ordering you implicitly provide. Please provide
algebraics in the order which seems most natural to you.
LIMITATIONS
This packages uses algorithms which are published in [1] and [2] which are based on field arithmetics,
in particular for polynomial gcd related algorithms. This can be quite slow for high degree polynomials
546 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
and subresultants methods usually work best. Beta versions of the package try to use these techniques
in a better way and work significantly faster. These are mostly based on unpublished algorithms and
cannot be distributed. Please contact the author if you have a particular problem to solve or want to
use these versions.
Be aware that approximations behave as post-processing and that all computations are done exactly.
They can thus be quite time consuming when depending on several ”real roots”.
REFERENCES
[1] R. Rioboo : Real Algebraic Closure of an ordered Field : Implementation in Axiom. In proceedings
of the ISSAC’92 Conference, Berkeley 1992 pp. 206-215.
[2] Z. Ligatsikas, R. Rioboo, M. F. Roy : Generic computation of the real closure of an ordered field.
In Mathematics and Computers in Simulation Volume 42, Issue 4-6, November 1996.
EXAMPLES
We shall work with the real closure of the ordered field of rational numbers.
Ran := RECLOS ( FRAC INT )
RealClosure(Fraction(Integer)) (4)
Type
Some simple signs for square roots, these correspond to an extension of degree 16 of the rational
numbers. Examples provided by J. Abbot.
fourSquares ( a : Ran , b : Ran , c : Ran , d : Ran ) : Ran == sqrt ( a ) + sqrt ( b ) - sqrt ( c ) - sqrt ( d )
Function declaration fourSquares : ( RealClosure ( Fraction ( Integer )) , RealClosure
( Fraction ( Integer )) , RealClosure ( Fraction ( Integer )) , RealClosure ( Fraction (
Integer ))) -> RealClosure ( Fraction ( Integer )) has been added to workspace .
√ √ √ √
− 586 − 60 + 548 + 73 (6)
recip ( squareDiff1 )
√ √ √ √ √ √
54602 548 + 149602 73 60 + 49502 73 548 + 9900895 586 (7)
√ √ √ √ √
+ 154702 73 548 + 30941947 60 + 10238421 548 + 28051871 73
sign ( squareDiff1 )
1 (8)
9.70. REALCLOSURE 547
PositiveInteger
squareDiff2 := fourSquares (165 ,778 ,86 ,990)
√ √ √ √
− 990 − 86 + 778 + 165 (9)
recip ( squareDiff2 )
√ √ √ √ √ √
556778 778 + 1209010 165 86 + 401966 165 778 + 144019431 990 (10)
√ √ √ √ √
+ 1363822 165 778 + 488640503 86 + 162460913 778 + 352774119 165
sign ( squareDiff2 )
1 (11)
PositiveInteger
squareDiff3 := fourSquares (217 ,708 ,226 ,692)
√ √ √ √
− 692 − 226 + 708 + 217 (12)
recip ( squareDiff3 )
√ √ √ √ √ √
−34102 708 − 61598 217 226 − 34802 217 708 − 13641141 692 (13)
√ √ √ √ √
+ −60898 217 708 − 23869841 226 − 13486123 708 − 24359809 217
sign ( squareDiff3 )
−1 (14)
Integer
squareDiff4 := fourSquares (155 ,836 ,162 ,820)
√ √ √ √
− 820 − 162 + 836 + 155 (15)
recip ( squareDiff4 )
√ √ √ √ √ √
−37078 836 − 86110 155 162 − 37906 155 836 − 13645107 820 (16)
√ √ √ √ √
+ −85282 155 836 − 30699151 162 − 13513901 836 − 31384703 155
548 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
sign ( squareDiff4 )
−1 (17)
Integer
√ √ √ √
− 818 − 552 + 772 + 591 (18)
recip ( squareDiff5 )
√ √ √ √ √ √
70922 772 + 81058 591 552 + 68542 591 772 + 46297673 818 (19)
√ √ √ √ √
+ 83438 591 772 + 56359389 552 + 47657051 772 + 54468081 591
sign ( squareDiff5 )
1 (20)
PositiveInteger
√ √ √ √
− 1088 − 412 + 1053 + 434 (21)
recip ( squareDiff6 )
√ √ √ √ √ √
115442 1053 + 179818 434 412 + 112478 434 1053 + 76037291 1088 (22)
√ √ √ √ √
+ 182782 434 1053 + 123564147 412 + 77290639 1053 + 120391609 434
sign ( squareDiff6 )
1 (23)
PositiveInteger
√ √ √ √
− 1152 − 446 + 1049 + 514 (24)
9.70. REALCLOSURE 549
recip ( squareDiff7 )
√ √ √ √ √ √
349522 1049 + 499322 514 446 + 325582 514 1049 + 239072537 1152 (25)
√ √ √ √ √
+ 523262 514 1049 + 384227549 446 + 250534873 1049 + 357910443 514
sign ( squareDiff7 )
1 (26)
PositiveInteger
√ √ √ √
− 1698 − 208 + 1751 + 190 (27)
recip ( squareDiff8 )
√ √ √ √ √ √
−214702 1751 − 651782 190 208 − 224642 190 1751 − 129571901 1698 (28)
√ √ √ √ √
+ −641842 190 1751 − 370209881 208 − 127595865 1751 − 387349387 190
sign ( squareDiff8 )
−1 (29)
Integer
− 0.23405277715937700123E − 10 (30)
Float
?4 − 4 ?2 + 2
(32)
[0, 0] (34)
A more complicated test that involve an extension of degree 256. This is a way of checking nested
radical identities.
( s2 , s5 , s10 ) := ( sqrt (2) $ Ran , sqrt (5) $ Ran , sqrt (10) $ Ran )
√
10 (35)
eq1 := sqrt ( s10 +3) * sqrt ( s5 +2) - sqrt ( s10 -3) * sqrt ( s5 -2) = sqrt (10* s2 +10)
√ √ √ √ √
q q q q q
− 10 − 3 5−2+ 10 + 3 5 + 2 = 10 2 + 10 (36)
eq1 :: Boolean
true (37)
Boolean
eq2 := sqrt ( s5 +2) * sqrt ( s2 +1) - sqrt ( s5 -2) * sqrt ( s2 -1) = sqrt (2* s10 +2)
√ √ √ √ √
q q q q q
− 5−2 2−1+ 5+2 2+1= 2 10 + 2 (38)
eq2 :: Boolean
true (39)
9.70. REALCLOSURE 551
Boolean
√
3 (40)
√
7 (41)
√ √
q
3
2 7−3 3 (42)
√ √
q
3
2 7+3 3 (43)
0 (44)
A quartic polynomial
pol : UP (x , Ran ) := x ^4+(7/3) * x ^2+30* x -(100/3)
7 2 100
x4 + x + 30 x − (45)
3 3
UnivariatePolynomial (x, RealClosure( Fraction ( Integer )))
√
7633 (46)
√
q
1 3
5 7633 − 436 (47)
3
RealClosure( Fraction ( Integer ))
√
q
1 3
− 5 7633 + 436 (48)
3
RealClosure( Fraction ( Integer ))
0 (49)
A quintic polynomial
qol : UP (x , Ran ) := x ^5+10* x ^3+20* x +22
x5 + 10 x3 + 20 x + 22 (50)
√
153 (51)
5 √
q
153 − 11 (52)
√
q
5
− 153 + 11 (53)
0 (54)
Finally, some examples from the book Computer Algebra by Davenport, Siret and Tournier (page 77).
The last one is due to Ramanujan.
dst1 := sqrt (9+4* s2 ) =1+2* s2
√ √
q
4 2+9=2 2+1 (55)
dst1 :: Boolean
true (56)
Boolean
s6 : Ran := sqrt 6
√
6 (57)
√ √ √
q q
−2 6+5+ 2 6+5=2 3 (58)
dst2 :: Boolean
true (59)
Boolean
s29 : Ran := sqrt 29
√
29 (60)
dst4 := sqrt (16 -2* s29 +2* sqrt (55 -10* s29 ) ) = sqrt (22+2* s5 ) - sqrt (11+2* s29 ) + s5
r q
√ √ √ √ √
q q
2 −10 29 + 55 − 2 29 + 16 = − 2 29 + 11 + 2 5 + 22 + 5 (61)
dst4 :: Boolean
554 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
true (62)
Boolean
dst6 := sqrt ((112+70* s2 ) +(46+34* s2 ) * s5 ) = (5+4* s2 ) +(3+ s2 ) * s5
√ √ √ √ √ √
r
34 2 + 46 5 + 70 2 + 112 = 2+3 5+4 2+5 (63)
dst6 :: Boolean
true (64)
Boolean
f3 : Ran := sqrt (3 ,5)
√
5
3 (65)
r
5 1
(66)
25
RealClosure( Fraction ( Integer ))
r
5 32
(67)
5
RealClosure( Fraction ( Integer ))
r
5 27
(68)
5
RealClosure( Fraction ( Integer ))
s r
3 27
r
32 √ 2 √ r1
5 5 5 5 5
− + = − 3 + 3+1 (69)
5 5 25
dst5 :: Boolean
9.71. REGULARTRIANGULARSET 555
true (70)
Boolean
9.71 RegularTriangularSet
The RegularTriangularSet domain constructor implements regular triangular sets. These particular
triangular sets were introduced by M. Kalkbrener (1991) in his PhD Thesis under the name regular
chains. Regular chains and their related concepts are presented in the paper ”On the Theories of
Triangular sets” By P. Aubry, D. Lazard and M. Moreno Maza (to appear in the Journal of Symbolic
Computation). The RegularTriangularSet constructor also provides a new method (by the third
author) for solving polynomial system by means of regular chains. This method has two ways of
solving. One has the same specifications as Kalkbrener’s algorithm (1991) and the other is closer to
Lazard’s method (Discr. App. Math, 1991). Moreover, this new method removes redundant component
from the decompositions when this is not too expensive. This is always the case with square-free
regular chains. So if you want to obtain decompositions without redundant components just use the
SquareFreeRegularTriangularSet domain constructor or the LazardSetSolvingPackage package
constructor. See also the LexTriangularPackage and ZeroDimensionalSolvePackage for the case
of algebraic systems with a finite number of (complex) solutions.
One of the main features of regular triangular sets is that they naturally define towers of simple
extensions of a field. This allows to perform with multivariate polynomials the same kind of operations
as one can do in an EuclideanDomain.
The RegularTriangularSet constructor takes four arguments. The first one, R, is the coefficient ring
of the polynomials; it must belong to the category GcdDomain. The second one, E, is the exponent
monoid of the polynomials; it must belong to the category OrderedAbelianMonoidSup. the third
one, V, is the ordered set of variables; it must belong to the category OrderedSet. The last one is
the polynomial ring; it must belong to the category RecursivePolynomialCategory(R,E,V). The
abbreviation for RegularTriangularSet is REGSET. See also the constructor RegularChain which
only takes two arguments, the coefficient ring and the ordered set of variables; in that case, polynomials
are necessarily built with the NewSparseMultivariatePolynomial domain constructor.
We shall explain now how to use the constructor REGSET and how to read the decomposition of a
polynomial system by means of regular sets.
Let us give some examples. We start with an easy one (Donati-Traverso) in order to understand the two
ways of solving polynomial systems provided by the REGSET constructor. Define the coefficient
ring.
R := Integer
Integer (4)
Type
[x, y, z, t] (5)
List (Symbol)
Type
Type
x (9)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
y : P := ’y
y (10)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
z : P := ’z
z (11)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
t : P := ’t
t (12)
9.71. REGULARTRIANGULARSET 557
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
RegularTriangularSet(Integer, IndexedExponents(OrderedVariableList([x,
(13)
y, z, t])), OrderedVariableList([x, y, z,
t]), NewSparseMultivariatePolynomial(Integer, OrderedVariableList([x, y, z, t])))
Type
x31 − x6 − x − y (14)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
p2 := x ^ 8 - z
x8 − z (15)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
p3 := x ^ 10 - t
x10 − t (16)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
lp := [ p1 , p2 , p3 ]
x31 − x6 − x − y, x8 − z, x10 − t
(17)
z 5 − t4 , t z y 2 + 2 z 3 y − t8 + 2 t5 + t3 − t2 , t4 − t x − t y − z 2
(18)
z 5 − t4 , t z y 2 + 2 z 3 y − t8 + 2 t5 + t3 − t2 , t4 − t x − t y − z 2 , (19)
3
t − 1, z 5 − t, t z y 2 + 2 z 3 y + 1, z x2 − t , {t, z, y, x}
558 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
We can see that the first decomposition is a subset of the second. So how can both be correct ?
Recall first that polynomials from a domain of the category RecursivePolynomialCategory are
regarded as univariate polynomials in their main variable. For instance the second polynomial in the
first set of each decomposition has main variable y and its initial (i.e. its leading coefficient w.r.t. its
main variable) is t z.
Now let us explain how to read the second decomposition. Note that the non-constant initials of the
first set are t4 − t and tz. Then the solutions described by this first set are the common zeros of its
polynomials that do not cancel the polynomials t4 − t and tyz. Now the solutions of the input system
lp satisfying these equations are described by the second and the third sets of the decomposition.
Thus, in some sense, they can be considered as degenerated solutions. The solutions given by the first
set are called the generic points of the system; they give the general form of the solutions. The first
decomposition only provides these generic points. This latter decomposition is useful when they are
many degenerated solutions (which is sometimes hard to compute) and when one is only interested in
general information, like the dimension of the input system.
We can get the dimensions of each component of a decomposition as follows.
[ coHeight ( ts ) for ts in lts ]
[1, 0, 0] (20)
List (NonNegativeInteger)
Thus the first set has dimension one. Indeed t can take any value, except 0 or any third root of 1,
whereas z is completely determined from t, y is given by z and t, and finally x is given by the other
three variables. In the second and the third sets of the second decomposition the four variables are
completely determined and thus these sets have dimension zero.
We give now the precise specifications of each decomposition. This assumes some mathematical knowl-
edge. However, for the non-expert user, the above explanations will be sufficient to understand the
other features of the RSEGSET constructor.
The input system lp is decomposed in the sense of Kalkbrener as finitely many regular sets T1,...,Ts
such that the radical ideal generated by lp is the intersection of the radicals of the saturated ideals
of T1,...,Ts. In other words, the affine variety associated with lp is the union of the closures (w.r.t.
Zarisky topology) of the regular-zeros sets of T1,...,Ts.
N. B. The prime ideals associated with the radical of the saturated ideal of a regular triangular set
have all the same dimension; moreover these prime ideals can be given by characteristic sets with the
same main variables. Thus a decomposition in the sense of Kalkbrener is unmixed dimensional. Then
it can be viewed as a lazy decomposition into prime ideals (some of these prime ideals being merged
into unmixed dimensional ideals).
Now we explain the other way of solving by means of regular triangular sets. The input system lp is
decomposed in the sense of Lazard as finitely many regular triangular sets T1,...,Ts such that the affine
variety associated with lp is the union of the regular-zeros sets of T1,...,Ts. Thus a decomposition in
the sense of Lazard is also a decomposition in the sense of Kalkbrener; the converse is false as we have
seen before.
When the input system has a finite number of solutions, both ways of solving provide similar decom-
9.71. REGULARTRIANGULARSET 559
(2 t y − 2) x + z y 2 − z (21)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
− z x3 + (4 t y + 4) x2 + 4 z y 2 + 4 z x + 2 t y 3 − 10 y 2 − 10 t y + 2
(22)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
f3 := 2* y * z * t + x * t ^2 -x -2* z
t2 − 1 x + 2 t z y − 2 z
(23)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
−z 3 + 4 t2 + 4 z x + 4 t z 2 + 2 t3 − 10 t y + 4 z 2 − 10 t2 + 2
(24)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
lf := [ f1 , f2 , f3 , f4 ]
(2 t y − 2) x + z y 2 − z, −z x3 + (4 t y + 4) x2 + 4 z y 2 + 4 z x + 2 t y 3 − 10 y 2 − 10 t y + 2, (25)
t2 − 1 x + 2 t z y − 2 z, −z 3 + 4 t2 + 4 z x + 4 t z 2 + 2 t3 − 10 t y + 4 z 2 − 10 t2 + 2
y + t, x + z , t8 − 10 t6 + 10 t2 − 1, z, t3 − 5 t y − 5 t2 + 1, x , t2 + 3, z 2 − 4, y + t, x − z
z 3 − 8 z x − 8 z 2 + 16 , 3 t2 + 1, z 2 − 7 t2 − 1, y + t, x + z , t2 + 3, z 2 − 4, y + t, x − z
560 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
[0, 0, 0, 0] (28)
List (NonNegativeInteger)
List (NonNegativeInteger)
32 (30)
PositiveInteger
We study now the options of the zeroSetSplit operation. As we have seen yet, there is an optional second
argument which is a boolean value. If this value is true (this is the default) then the decomposition is
computed in the sense of Kalkbrener, otherwise it is computed in the sense of Lazard.
There is a second boolean optional argument that can be used (in that case the first optional argument
must be present). This second option allows you to get some information during the computations.
Therefore, we need to understand a little what is going on during the computations. An important
feature of the algorithm is that the intermediate computations are managed in some sense like the
processes of a Unix system. Indeed, each intermediate computation may generate other intermediate
computations and the management of all these computations is a crucial task for the efficiency. Thus
any intermediate computation may be suspended, killed or resumed, depending on algebraic consid-
erations that determine priorities for these processes. The goal is of course to go as fast as possible
towards the final decomposition which means to avoid as much as possible unnecessary computations.
To follow the computations, one needs to set to true the second argument. Then a lot of numbers
and letters are displayed. Between a [ and a ] one has the state of the processes at a given time. Just
after [ one can see the number of processes. Then each process is represented by two numbers between
< and >. A process consists of a list of polynomial ps and a triangular set ts; its goal is to compute
the common zeros of ps that belong to the regular-zeros set of ts. After the processes, the number
between pipes gives the total number of polynomials in all the sets ps. Finally, the number between
braces gives the number of components of a decomposition that are already computed. This number
may decrease.
Let us take a third example (Czapor-Geddes-Wang) to see how these informations are displayed.
Define a polynomial system.
9.71. REGULARTRIANGULARSET 561
u : R := 2
2 (31)
Integer
y 2 − 2 t y + t2 x2 + −2 y 2 + ((2 t + 4) z + 2 t) y + −2 t2 + 2 z − 4 t2 − 2 x (32)
+ y 2 + (−2 t z − 4 t) y + t2 + 10 z 2 − 8 z + 4 t2 + 2
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
(−3 z y + 2 t z + t) x + (z + 4) y + 4 t z 2 − 7 t z (33)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
(−2 z − 2) x − 2 z 2 + 8 z − 2 (34)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
3 y 2 − 3 t2 − 4 x2 + −6 y 2 + (12 t z + 12 t) y + 6 t2 z x + 3 y 2 (35)
+ (12 t z − 12 t) y + 9 t2 + 4 z 2 + −24 t2 − 4 z + 12 t2 + 4
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
lq := [ q1 , q2 , q3 , q4 ]
y 2 − 2 t y + t2 x2 + −2 y 2 + ((2 t + 4) z + 2 t) y + −2 t2 + 2 z − 4 t2 − 2 x + y 2
(−2 z − 2) x − 2 z 2 + 8 z − 2, 3 y 2 − 3 t2 − 4 x2 + −6 y 2 + (12 t z + 12 t) y + 6 t2 z x
+ 3 y 2 + (12 t z − 12 t) y + 9 t2 + 4 z 2 + −24 t2 − 4 z + 12 t2 + 4
Between a sequence of processes, thus between a ] and a [ you can see capital letters W, G, I and lower
case letters i, w. Each time a capital letter appears a non-trivial computation has been performed and
its result is put in a hash-table. Each time a lower case letter appears a needed result has been found
562 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
in an hash-table. The use of these hash-tables generally speed up the computations. However, on very
large systems, it may happen that these hash-tables become too big to be handled by your FriCAS
configuration. Then in these exceptional cases, you may prefer getting a result (even if it takes a long
time) than getting nothing. Hence you need to know how to prevent the RSEGSET constructor from
using these hash-tables. In that case you will be using the zeroSetSplit with five arguments. The first
one is the input system lp as above. The second one is a boolean value hash? which is true iff you
want to use hash-tables. The third one is boolean value clos? which is true iff you want to solve your
system in the sense of Kalkbrener, the other way remaining that of Lazard. The fourth argument is
boolean value info? which is true iff you want to display information during the computations. The
last one is boolean value prep? which is true iff you want to use some heuristics that are performed on
the input system before starting the real algorithm. The value of this flag is true when you are using
zeroSetSplit with less than five arguments. Note that there is no available signature for zeroSetSplit
with four arguments.
We finish this section by some remarks about both ways of solving, in the sense of Kalkbrener or in the
sense of Lazard. For problems with a finite number of solutions, there are theoretically equivalent and
the resulting decompositions are identical, up to the ordering of the components. However, when solving
in the sense of Lazard, the algorithm behaves differently. In that case, it becomes more incremental
than in the sense of Kalkbrener. That means the polynomials of the input system are considered one
after another whereas in the sense of Kalkbrener the input system is treated more globally.
This makes an important difference in positive dimension. Indeed when solving in the sense of Kalk-
brener, the Primeidealkettensatz of Krull is used. That means any regular triangular containing more
polynomials than the input system can be deleted. This is not possible when solving in the sense of
Lazard. This explains why Kalkbrener’s decompositions usually contain less components than those
of Lazard. However, it may happen with some examples that the incremental process (that cannot be
used when solving in the sense of Kalkbrener) provide a more efficient way of solving than the global
one even if the Primeidealkettensatz is used. Thus just try both, with the various options, before
concluding that you cannot solve your favorite system with zeroSetSplit. There exist more options at
the development level that are not listed above.
9.72 RomanNumeral
The Roman numeral package was added to FriCAS in MCMLXXXVI for use in denoting higher order
derivatives.
For example, let f be a symbolic operator.
f := operator ’f
f (4)
BasicOperator
Expression ( Integer )
You can have integers printed as Roman numerals by declaring variables to be of type RomanNumeral
(abbreviation ROMAN).
a := roman (1978 - 1965)
XIII (6)
RomanNumeral
This package now has a small but devoted group of followers that claim this domain has shown its
efficacy in many other contexts. They claim that Roman numerals are every bit as useful as ordinary
integers. In a sense, they are correct, because Roman numerals form a ring and you can therefore
construct polynomials with Roman numeral coefficients, matrices over Roman numerals, etc..
x : UTS ( ROMAN , ’x ,0) := x
x (7)
UnivariateTaylorSeries (RomanNumeral, x, 0)
You can also construct fractions with Roman numeral numerators and denominators, as this matrix
Hilberticus illustrates.
m : MATRIX FRAC ROMAN
I I I
II III IV
I I I
(10)
III IV V
I I I
IV V VI
Matrix(Fraction (RomanNumeral))
Note that the inverse of the matrix has integral ROMAN entries.
inverse m
LXXII −CCXL CLXXX
−CCXL CM −DCCXX (11)
CLXXX −DCCXX DC
Union(Matrix(Fraction(RomanNumeral)), ...)
Unfortunately, the spoil-sports say that the fun stops when the numbers get big—mostly because the
Romans didn’t establish conventions about representing very large numbers.
564 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
y := factorial 10
3628800 (12)
PositiveInteger
Issue the system command )show RomanNumeral to display the full list of operations defined by Ro-
manNumeral.
9.73 Segment
The Segment domain provides a generalized interval type.
Segments are created using the “..” construct by indicating the (included) end points.
s := 3..10
3 . . 10 (4)
Segment( PositiveInteger )
The first end point is called the low and the second is called high.
low ( s )
3 (5)
PositiveInteger
These names are used even though the end points might belong to an unordered set.
high ( s )
10 (6)
PositiveInteger
In addition to the end points, each segment has an integer “increment.” An increment can be specified
using the “by” construct.
t := 10..3 by -2
10 . . 3 by − 2 (7)
9.73. SEGMENT 565
Segment( PositiveInteger )
1 (8)
PositiveInteger
−2 (9)
Integer
A single value can be converted to a segment with equal end points. This happens if segments and
single values are mixed in a list.
l := [1..3 , 5 , 9 , 15..11 by -1]
[1 . . 3, 5 . . 5, 9 . . 9, 15 . . 11 by − 1] (10)
If the underlying type is an ordered ring, it is possible to perform additional operations. The expand
operation creates a list of points in a segment.
expand ( s )
List ( Integer )
If k > 0, then expand(l..h by k) creates the list [l, l+k, ..., lN] where lN <= h < lN+k. If
k < 0, then lN >= h > lN+k.
expand ( t )
[10, 8, 6, 4] (12)
List ( Integer )
It is also possible to expand a list of segments. This is equivalent to appending lists obtained by
expanding each segment individually.
expand ( l )
List ( Integer )
For more information on related topics, see ‘SegmentBinding’ on page 566 and ‘UniversalSegment’
on page 603. Issue the system command )show Segment to display the full list of operations defined
by Segment.
566 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
9.74 SegmentBinding
The SegmentBinding type is used to indicate a range for a named symbol.
First give the symbol, then an “=” and finally a segment of values.
x = a .. b
x = (a . . b) (4)
SegmentBinding(Symbol)
2 n3 + 3 n2 + n
(5)
6
Fraction (Polynomial( Integer ))
The draw operation uses a SegmentBinding argument as a range of coordinates. This is an example
of a two-dimensional parametrized plot; other draw options use more than one SegmentBinding
argument.
draw ( x ^2 , x = -2..2)
x^2
The left-hand side must be of type Symbol but the right-hand side can be a segment over any type.
sb := y = 1/2..3/2
1 3
y= .. (6)
2 2
SegmentBinding(Fraction(Integer))
The left- and right-hand sides can be obtained using the variable and segment operations.
variable ( sb )
9.75. SET 567
y (7)
Symbol
segment ( sb )
1 3
.. (8)
2 2
Segment(Fraction(Integer))
For more information on related topics, see ‘Segment’ on page 564 and ‘UniversalSegment’ on page
603. Issue the system command )show SegmentBinding to display the full list of operations defined
by SegmentBinding.
9.75 Set
The Set domain allows one to represent explicit finite sets of values. These are similar to lists, but
duplicate elements are not allowed. Sets can be created by giving a fixed set of values . . .
s := set [ x ^2 -1 , y ^2 -1 , z ^2 -1]
x2 − 1, y 2 − 1, z 2 − 1
(4)
Set(Polynomial( Integer ))
or by using a collect form, just as for lists. In either case, the set is formed from a finite collection of
values.
t := set [ x ^ i - i +1 for i in 2..10 | prime ? i ]
x2 − 1, x3 − 2, x5 − 4, x7 − 6
(5)
Set(Polynomial( Integer ))
The basic operations on sets are intersect, union, difference, and symmetricDifference.
i := intersect (s , t )
x2 − 1
(6)
Set(Polynomial( Integer ))
u := union (s , t )
2
x − 1, y 2 − 1, z 2 − 1, x3 − 2, x5 − 4, x7 − 6 (7)
Set(Polynomial( Integer ))
2
y − 1, z 2 − 1 (8)
Set(Polynomial( Integer ))
The set symmetricDifference(s,t) contains those elements which are in s or t but not in both.
s y m m e t r i c D i f f e r e n c e (s , t )
y 2 − 1, z 2 − 1, x3 − 2, x5 − 4, x7 − 6
(9)
Set(Polynomial( Integer ))
false (10)
Boolean
member ?(( y +1) *( y -1) , s )
true (11)
Boolean
true (12)
Boolean
subset ?( u , s )
false (13)
Boolean
When the base type is finite, the absolute complement of a set is defined. This finds the set of all
multiplicative generators of PrimeField 11—the integers mod 11.
gs := set [ g for i in 1..11 | primitive ?( g := i :: PF 11) ]
{2, 6, 7, 8} (14)
Set(PrimeField(11))
Set(PrimeField(11))
Often the members of a set are computed individually; in addition, values can be inserted or removed
from a set over the course of a computation. There are two ways to do this:
a := set [ i ^2 for i in 1..5]
Set( PositiveInteger )
Set( PositiveInteger )
remove !(25 , a )
Set( PositiveInteger )
Set( PositiveInteger )
The other way is to view a set as a mathematical entity and to create new sets from old.
b := b0 := set [ i ^2 for i in 1..5]
Set( PositiveInteger )
b := union (b , {32})
Set( PositiveInteger )
b := difference (b , {25})
Set( PositiveInteger )
b0
Set( PositiveInteger )
For more information about lists, see ‘List’ on page 490. Issue the system command )show Set to
display the full list of operations defined by Set.
9.76 SingleInteger
The SingleInteger domain is intended to provide support in FriCAS for machine integer arithmetic.
It is generally much faster than (bignum) Integer arithmetic but suffers from a limited range of values.
Since FriCAS can be implemented on top of various dialects of Lisp, the actual representation of small
integers may not correspond exactly to the host machines integer representation.
The underlying Lisp primitives treat machine-word sized computations specially.
You can discover the minimum and maximum values in your implementation by using min and max.
min () $ Sing leInteg er
− 4611686018427387904 (4)
SingleInteger
4611686018427387903 (5)
SingleInteger
To avoid confusion with Integer, which is the default type for integers, you usually need to work with
declared variables (Section 2.3 on page 74) . . .
a := 1234 :: SingleInteger
1234 (6)
SingleInteger
124 (7)
SingleInteger
You can add, multiply and subtract SingleInteger objects, and ask for the greatest common divisor
(gcd).
gcd (a , b )
2 (8)
9.76. SINGLEINTEGER 571
SingleInteger
76508 (9)
SingleInteger
Operations mulmod, addmod, submod, and invmod are similar—they provide arithmetic modulo a given
small integer. Here is 5 * 6 mod 13.
mulmod (5 ,6 ,13) $ Sing leInteg er
4 (10)
SingleInteger
11 (11)
SingleInteger
Operations And, Or, xor, and Not provide bit level operations on small integers.
And (3 ,4) $ Singl eIntege r
0 (12)
SingleInteger
Use shift(int,numToShift) to shift bits, where i is shifted left if numToShift is positive, right if
negative.
shift (1 ,4) $ Sing leIntege r
16 (13)
SingleInteger
15 (14)
SingleInteger
Many other operations are available for small integers, including many of those provided for Integer.
To see the other operations, use the Browse HyperDoc facility (Section 14 on page 689). Issue the sys-
tem command )show SingleInteger to display the full list of operations defined by SingleInteger..
572 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
9.77 SparseTable
The SparseTable domain provides a general purpose table type with default entries. Here we create
a table to save strings under integer keys. The value "Try again!" is returned if no other value has
been stored for a key.
t : SparseTable ( Integer , String , " Try again !") := table ()
table () (4)
String
String
These values can be retrieved as usual, but if a look up fails the default entry will be returned.
t .3
String
t .2
String
To see which values are explicitly stored, the keys and entries functions can be used.
keys t
[4, 3] (9)
List ( Integer )
entries t
List ( String )
9.78. SQUAREFREEREGULARTRIANGULARSET 573
9.78 SquareFreeRegularTriangularSet
The SquareFreeRegularTriangularSet domain constructor implements square-free regular trian-
gular sets. See the RegularTriangularSet domain constructor for general regular triangular sets.
Let T be a regular triangular set consisting of polynomials t1, ..., tm ordered by increasing main vari-
ables. The regular triangular set T is square-free if T is empty or if t1, ..., tm-1 is square-free and
if the polynomial tm is square-free as a univariate polynomial with coefficients in the tower of simple
extensions associated with t1, ..., tm-1.
The main interest of square-free regular triangular sets is that their associated towers of simple exten-
sions are product of fields. Consequently, the saturated ideal of a square-free regular triangular set is
radical. This property simplifies some of the operations related to regular triangular sets. However,
building square-free regular triangular sets is generally more expensive than building general regular
triangular sets.
As the RegularTriangularSet domain constructor, the SquareFreeRegularTriangularSet domain
constructor also implements a method for solving polynomial systems by means of regular triangular
sets. This is in fact the same method with some adaptations to take into account the fact that the
computed regular chains are square-free. Note that it is also possible to pass from a decomposition
into general regular triangular sets to a decomposition into square-free regular triangular sets. This
conversion is used internally by the LazardSetSolvingPackage package constructor.
N.B. When solving polynomial systems with the SquareFreeRegularTriangularSet domain con-
structor or the LazardSetSolvingPackage package constructor, decompositions have no redundant
components. See also LexTriangularPackage and ZeroDimensionalSolvePackage for the case of
algebraic systems with a finite number of (complex) solutions.
We shall explain now how to use the constructor SquareFreeRegularTriangularSet.
This constructor takes four arguments. The first one, R, is the coefficient ring of the polynomials;
it must belong to the category GcdDomain. The second one, E, is the exponent monoid of the
polynomials; it must belong to the category OrderedAbelianMonoidSup. the third one, V, is the
ordered set of variables; it must belong to the category OrderedSet. The last one is the polynomial
ring; it must belong to the category RecursivePolynomialCategory(R,E,V). The abbreviation for
SquareFreeRegularTriangularSet is SREGSET.
Note that the way of understanding triangular decompositions is detailed in the example of the Reg-
ularTriangularSet constructor.
Let us illustrate the use of this constructor with one example (Donati-Traverso). Define the coefficient
ring.
R := Integer
Integer (4)
574 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Type
[x, y, z, t] (5)
List (Symbol)
Type
Type
Type
x (9)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
y : P := ’y
y (10)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
z : P := ’z
z (11)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
t : P := ’t
9.78. SQUAREFREEREGULARTRIANGULARSET 575
t (12)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
SquareFreeRegularTriangularSet(Integer, IndexedExponents(OrderedVariableList([x,
(13)
y, z, t])), OrderedVariableList([x, y, z,
t]), NewSparseMultivariatePolynomial(Integer, OrderedVariableList([x, y, z, t])))
Type
x31 − x6 − x − y (14)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
p2 := x ^ 8 - z
x8 − z (15)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
p3 := x ^ 10 - t
x10 − t (16)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
lp := [ p1 , p2 , p3 ]
x31 − x6 − x − y, x8 − z, x10 − t
(17)
z 5 − t4 , t z y 2 + 2 z 3 y − t8 + 2 t5 + t3 − t2 , t4 − t x − t y − z 2
(18)
z 5 − t4 , t z y 2 + 2 z 3 y − t8 + 2 t5 + t3 − t2 , t4 − t x − t y − z 2 , (19)
3
t − 1, z 5 − t, t y + z 2 , z x2 − t , {t, z, y, x}
Now to see the difference with the RegularTriangularSet domain constructor, we define:
T := REGSET (R ,E ,V , P )
RegularTriangularSet(Integer, IndexedExponents(OrderedVariableList([x,
(20)
y, z, t])), OrderedVariableList([x, y, z,
t]), NewSparseMultivariatePolynomial(Integer, OrderedVariableList([x, y, z, t])))
Type
and compute:
lts := zeroSetSplit ( lp , false ) $ T
z 5 − t4 , t z y 2 + 2 z 3 y − t8 + 2 t5 + t3 − t2 , t4 − t x − t y − z 2 , (21)
3
t − 1, z 5 − t, t z y 2 + 2 z 3 y + 1, z x2 − t , {t, z, y, x}
If you look at the second set in both decompositions in the sense of Lazard, you will see that the
polynomial with main variable y is not the same.
Let us understand what has happened. We define:
ts := lts .2
t3 − 1, z 5 − t, t z y 2 + 2 z 3 y + 1, z x2 − t
(22)
pol := select ( ts , ’ y ) $ T
t z y2 + 2 z3 y + 1 (23)
tower := collectUnder ( ts , ’ y ) $ T
3
t − 1, z 5 − t (24)
pack := R e g u l a r T r i a n g u l a r S e t G c d P a c k a g e (R ,E ,V ,P , T )
9.79. SQUAREMATRIX 577
RegularTriangularSetGcdPackage(Integer, IndexedExponents(OrderedVariableList([x,
y, z, t])), OrderedVariableList([x, y, z,
t]), NewSparseMultivariatePolynomial(Integer, OrderedVariableList([x, y, z, (25)
t])), RegularTriangularSet(Integer, IndexedExponents(OrderedVariableList([x,
y, z, t])), OrderedVariableList([x, y, z,
t]), NewSparseMultivariatePolynomial(Integer, OrderedVariableList([x, y, z, t]))))
Type
Then we compute:
t o s e S q u a r e F r e e P a r t ( pol , tower ) $ pack
val = t y + z 2 , tower = t3 − 1, z 5 − t
(26)
9.79 SquareMatrix
The top level matrix type in FriCAS is Matrix (see ‘Matrix’ on page 504), which provides basic
arithmetic and linear algebra functions. However, since the matrices can be of any size it is not true
that any pair can be added or multiplied. Thus Matrix has little algebraic structure.
Sometimes you want to use matrices as coefficients for polynomials or in other algebraic contexts. In
this case, SquareMatrix should be used. The domain SquareMatrix(n,R) gives the ring of n by n
square matrices over R.
Since SquareMatrix is not normally exposed at the top level, you must expose it before it can be
used.
) set expose add constructor SquareMatrix
SquareMatrix is now explicitly exposed in frame initial
Once SQMATRIX has been exposed, values can be created using the squareMatrix function.
m := squareMatrix [[1 , -% i ] ,[% i ,4]]
1 −i
(4)
i 4
SquareMatrix(2, Complex(Integer))
1 −4 i
(5)
4i 13
578 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
SquareMatrix(2, Complex(Integer))
Square matrices can be used where ring elements are required. For example, here is a matrix with
matrix entries.
mm := squareMatrix [[ m , 1] , [1 -m , m ^2]]
1 −i 1 0
i 4 0 1
(6)
0 i 2 −5 i
−i −3 5i 17
2 −2 i 2 −5 i
x2 + x+ (7)
2i 8 5i 17
Polynomial(SquareMatrix(2, Complex(Integer)))
x2 + 2 x + 2
−2 i x − 5 i
(8)
2ix + 5i x2 + 8 x + 17
SquareMatrix(2, Polynomial(Complex(Integer)))
For more information on related topics, see Section 2.2.4 on page 73, Section 2.11 on page 94, and
‘Matrix’ on page 504. Issue the system command )show SquareMatrix to display the full list of
operations defined by SquareMatrix.
9.80 Stream
A Stream object is represented as a list whose last element contains the wherewithal to create the
next element, should it ever be required. Let ints be the infinite stream of non-negative integers.
ints := [ i for i in 0..]
[0, 1, 2, 3, 4, 5, 6, . . .] (4)
Stream(NonNegativeInteger)
By default, ten stream elements are calculated. This number may be changed to something else by the
system command )set streams calculate. For the display purposes of this book, we have chosen
a smaller value. More generally, you can construct a stream by specifying its initial value and a
function which, when given an element, creates the next element.
f : List INT -> List INT
9.80. STREAM 579
f x == [ x .1 + x .2 , x .1]
Stream(Integer)
You can create the stream of odd non-negative integers by either filtering them from the integers, or
by evaluating an expression for each integer.
[ i for i in ints | odd ? i ]
Stream(NonNegativeInteger)
Stream(NonNegativeInteger)
You can accumulate the initial segments of a stream using the scan operation.
scan (0 ,+ , odds )
Stream(NonNegativeInteger)
The corresponding elements of two or more streams can be combined in this way.
[ i * j for i in ints for j in odds ]
Stream(NonNegativeInteger)
Stream(NonNegativeInteger)
Many operations similar to those applicable to lists are available for streams.
first ints
0 (13)
NonNegativeInteger
rest ints
580 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
[1, 2, 3, 4, 5, 6, 7, . . .] (14)
Stream(NonNegativeInteger)
fibs 20
6765 (15)
PositiveInteger
9.81 String
The type String provides character strings. Character strings provide all the operations for a one-
dimensional array of characters, plus additional operations for manipulating text. For more information
on related topics, see ‘Character’ on page 363 and ‘CharacterClass’ on page 365. You can also issue
the system command )show String to display the full list of operations defined by String.
String values can be created using double quotes.
hello := " Hello , I ’ m FriCAS !"
String
Note, however, that double quotes and underscores must be preceded by an extra underscore.
said := " Jane said , _ " Look ! _ ""
String
It is also possible to use new to create a string of any size filled with a given character. Since there are
many new functions it is necessary to indicate the desired type.
gasp : String := new (32 , char " x ")
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" (7)
9.81. STRING 581
String
32 (8)
PositiveInteger
Indexing operations allow characters to be extracted or replaced in strings. For any string s, indices
lie in the range 1..#s.
hello .2
e (9)
Character
Indexing is really just the application of a string to a subscript, so any application syntax works.
hello 2
e (10)
Character
hello (2)
e (11)
Character
If it is important not to modify a given string, it should be copied before any updating operations are
used.
hullo := copy hello
String
List ( String )
Operations are provided to split and join strings. The concat operation allows several strings to be
joined together.
saidsaw := concat [" alpha " ," ---”,”omega”]
"alpha---omega" (14)
582 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
String
String
String
"Hello" (17)
String
hello (8..)
String
A string can be split into several substrings by giving a separation character or character class.
split ( hello , char " ")
List ( String )
List ( String )
Unwanted characters can be trimmed from the beginning or end of a string using the operations trim,
leftTrim and rightTrim.
trim ("## ++ relax ++ ##" , char "#")
String
Each of these functions takes a string and a second argument to specify the characters to be discarded.
trim ("## ++ relax ++ ##" , other )
"relax" (23)
String
The second argument can be given either as a single character or as a character class.
leftTrim ("## ++ relax ++ ##" , other )
String
Strings can be changed to upper case or lower case using the operations upperCase, upperCase!, lower-
Case and lowerCase!.
upperCase hello
The versions with the exclamation mark change the original string, while the others produce a copy.
lowerCase hello
Some basic string matching is provided. The function prefix? tests whether one string is an initial
prefix of another.
prefix ?(" He " , " Hello ")
true (28)
Boolean
prefix ?(" Her " , " Hello ")
false (29)
584 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Boolean
true (30)
Boolean
suffix ?(" LO " , " Hello ")
false (31)
Boolean
true (32)
Boolean
substring ?(" ll " , " Hello " , 4)
false (33)
Boolean
A number of position functions locate things in strings. If the first argument to position is a string,
then position(s,t,i) finds the location of s as a substring of t starting the search at position i.
n := position (" nd " , " underground " , 1)
2 (34)
PositiveInteger
10 (35)
PositiveInteger
0 (36)
NonNegativeInteger
To search for a specific character or a member of a character class, a different first argument is used.
position ( char " d " , " underground " , 1)
9.82. STRINGTABLE 585
3 (37)
PositiveInteger
3 (38)
PositiveInteger
9.82 StringTable
This domain provides a table type in which the keys are known to be strings so special techniques
can be used. Other than performance, the type StringTable(S) should behave exactly the same way
as Table(String,S). See ‘Table’ on page 589 for general information about tables. Issue the system
command )show StringTable to display the full list of operations defined by StringTable.
This creates a new table whose keys are strings.
t : StringTable ( Integer ) := table ()
table () (4)
StringTable ( Integer )
The value associated with each string key is the number of characters in the string.
for s in split (" My name is Ian Watt ." , char " ")
repeat
t . s := # s
9.83 Symbol
Symbols are one of the basic types manipulated by FriCAS. The Symbol domain provides ways to
create symbols of many varieties. Issue the system command )show Symbol to display the full list of
operations defined by Symbol.
The simplest way to create a symbol is to “single quote” an identifier.
X : Symbol := ’x
x (4)
586 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Symbol
This gives the symbol even if x has been assigned a value. If x has not been assigned a value, then it
is possible to omit the quote.
XX : Symbol := x
x (5)
Symbol
Declarations must be used when working with symbols, because otherwise the interpreter tries to place
values in a more specialized type Variable.
A := ’a
a (6)
Variable (a)
B := b
b (7)
Variable (b)
x2 + 1 (8)
Polynomial( Integer )
Another convenient way to create symbols is to convert a string. This is useful when the name is to
be constructed by a program.
" Hello ":: Symbol
Hello (9)
Symbol
Sometimes it is necessary to generate new unique symbols, for example, to name constants of integra-
tion. The expression new() generates a symbol starting with %.
new () $ Symbol
%A (10)
Symbol
%B (11)
Symbol
%xyz0 (12)
Symbol
A symbol can be adorned in various ways. The most basic thing is applying a symbol to a list of
subscripts.
X [i , j ]
xi, j (13)
Symbol
u1, 2, 1, 2 (14)
Symbol
V := superscript (v , [ n ])
vn (15)
Symbol
P := argscript (p , [ t ])
p(t) (16)
Symbol
It is possible to test whether a symbol has scripts using the scripted? test.
scripted ? U
true (17)
Boolean
scripted ? X
false (18)
588 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Boolean
"x" (19)
String
The basic parts can always be extracted using the name and scripts operations.
name U
u (20)
Symbol
scripts U
Record(sub: List (OutputForm), sup: List (OutputForm), presup: List (OutputForm), presub: List (OutputForm), args: List (
OutputForm))
name X
x (22)
Symbol
scripts X
Record(sub: List (OutputForm), sup: List (OutputForm), presup: List (OutputForm), presub: List (OutputForm), args: List (
OutputForm))
The most general form is obtained using the script operation. This operation takes an argument which
is a list containing, in this order, lists of subscripts, superscripts, presuperscripts, presubscripts and
arguments to a symbol.
M := script ( Mammoth , [[ i , j ] ,[k , l ] ,[0 ,1] ,[2] ,[ u ,v , w ]])
0, 1 k, l
2M ammothi, j (u, v, w) (24)
Symbol
scripts M
[sub = [i, j] , sup = [k, l] , presup = [0, 1] , presub = [2] , args = [u, v, w]] (25)
Record(sub: List (OutputForm), sup: List (OutputForm), presup: List (OutputForm), presub: List (OutputForm), args: List (
OutputForm))
0, 1
N utk, l
i, j (26)
Symbol
scripts N
[sub = [i, j] , sup = [k, l] , presup = [0, 1] , presub = [] , args = []] (27)
Record(sub: List (OutputForm), sup: List (OutputForm), presup: List (OutputForm), presub: List (OutputForm), args: List (
OutputForm))
9.84 Table
The Table constructor provides a general structure for associative storage. This type provides hash
tables in which data objects can be saved according to keys of any type. For a given table, specific
types must be chosen for the keys and entries.
In this example the keys to the table are polynomials with integer coefficients. The entries in the table
are strings.
t : Table ( Polynomial Integer , String ) := table ()
table () (4)
To save an entry in the table, the setelt! operation is used. This can be called directly, giving the table
a key and an entry.
setelt !( t , x ^2 - 1 , " Easy to factor ")
String
String
Entries are retrieved from the table by calling the elt operation.
590 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
elt (t , x )
String
This operation is called when a table is “applied” to a key using this or the following syntax.
t.x
String
t x
String
Parentheses are used only for grouping. They are needed if the key is an infixed expression.
t .( x ^2 - 1)
String
Note that the elt operation is used only when the key is known to be in the table—otherwise an error
is generated.
t ( x ^3 + 1)
String
You can get a list of all the keys to a table using the keys operation.
keys t
x, x3 + 1, x2 − 1
(13)
If you wish to test whether a key is in a table, the search operation is used. This operation returns
either an entry or "failed".
search (x , t )
Union(String , ...)
search ( x ^2 , t )
9.84. TABLE 591
"failed" (15)
The return type is a union so the success of the search can be tested using case.
search ( x ^2 , t ) case " failed "
true (16)
Boolean
Union(String , ...)
If an entry exists under the key, then it is returned. Otherwise remove! returns "failed".
remove !( x -1 , t )
"failed" (18)
2 (19)
PositiveInteger
Just as keys returns a list of keys to the table, a list of all the entries can be obtained using the members
operation.
members t
List ( String )
A number of useful operations take functions and map them on to the table to compute the result.
Here we count the entries which have "Hard" as a prefix.
count ( s : String + - > prefix ?(" Hard " , s ) , t )
1 (21)
PositiveInteger
AssociationList gives a list with a table view. This allows new entries to be appended onto
the front of the list to cover up old entries. This is useful when table entries need to be stacked
or when frequent list traversals are required. See ‘AssociationList’ on page 341 for more
information.
EqTable gives tables in which keys are considered equal only when they are in fact the same
instance of a structure. See ‘EqTable’ on page 397 for more information.
StringTable should be used when the keys are known to be strings. See ‘StringTable’ on page
585 for more information.
SparseTable provides tables with default entries, so lookup never fails. The GeneralSparseTable
constructor can be used to make any table type behave this way. See ‘SparseTable’ on page 572
for more information.
KeyedAccessFile allows values to be saved in a file, accessed as a table. See ‘KeyedAccessFile’
on page 457 for more information.
Issue the system command )show Table to display the full list of operations defined by Table.
9.85 TextFile
The domain TextFile allows FriCAS to read and write character data and exchange text with other
programs. This type behaves in FriCAS much like a File of strings, with additional operations to
cause new lines. We give an example of how to produce an upper case copy of a file. This is the file
from which we read the text.
f1 : TextFile := open ("/ etc / group " , " input ")
"/etc/group" (4)
TextFile
"/tmp/MOTD" (5)
TextFile
Entire lines are handled using the readLine! and writeLine! operations.
l := readLine ! f1
"root:x:0:" (6)
String
writeLine !( f2 , upperCase l )
"ROOT:X:0:" (7)
9.86. TWODIMENSIONALARRAY 593
String
Use the endOfFile? operation to check if you have reached the end of the file.
while not endOfFile ? f1 repeat
s := readLine ! f1
writeLine !( f2 , upperCase s )
"/etc/group" (9)
TextFile
It is sometimes useful to write lines a bit at a time. The write! operation allows this.
write !( f2 , " - The -")
"-The-" (10)
String
"-End-" (11)
String
"" (12)
String
close ! f2
"/tmp/MOTD" (13)
TextFile
For more information on related topics, see ‘File’ on page 412, ‘KeyedAccessFile’ on page 457, and
‘Library’ on page 474. Issue the system command )show TextFile to display the full list of operations
defined by TextFile.
9.86 TwoDimensionalArray
The TwoDimensionalArray domain is used for storing data in a two-dimensional data structure
indexed by row and by column. Such an array is a homogeneous data structure in that all the entries
594 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
of the array must belong to the same FriCAS domain (although see Section 2.6 on page 83). Each
array has a fixed number of rows and columns specified by the user and arrays are not extensible. In
FriCAS, the indexing of two-dimensional arrays is one-based. This means that both the “first” row of
an array and the “first” column of an array are given the index 1. Thus, the entry in the upper left
corner of an array is in position (1,1).
The operation new creates an array with a specified number of rows and columns and fills the compo-
nents of that array with a specified entry. The arguments of this operation specify the number of rows,
the number of columns, and the entry. This creates a five-by-four array of integers, all of whose
entries are zero.
arr : ARRAY2 INT := new (5 ,4 ,0)
0 0 0 0
0 0 0 0
0 0 0 0 (4)
0 0 0 0
0 0 0 0
TwoDimensionalArray(Integer)
The entries of this array can be set to other integers using the operation setelt!.
Issue this to set the element in the upper left corner of this array to 17.
setelt !( arr , 1 , 1 , 17)
17 (5)
PositiveInteger
17 0 0 0
0 0 0 0
0 0 0 0 (6)
0 0 0 0
0 0 0 0
TwoDimensionalArray(Integer)
17 (7)
PositiveInteger
Another way to use these two operations is as follows. This sets the element in position (3,2) of the
array to 15.
arr (3 ,2) := 15
9.86. TWODIMENSIONALARRAY 595
15 (8)
PositiveInteger
15 (9)
PositiveInteger
The operations elt and setelt! come equipped with an error check which verifies that the indices are
in the proper ranges. For example, the above array has five rows and four columns, so if you ask for
the entry in position (6,2) with arr(6,2) FriCAS displays an error message. If there is no need for
an error check, you can call the operations qelt and qsetelt! which provide the same functionality but
without the error check. Typically, these operations are called in well-tested programs.
The operations row and column extract rows and columns, respectively, and return objects of One-
DimensionalArray with the same underlying element type.
row ( arr ,1)
[17, 0, 0, 0] (10)
OneDimensionalArray(Integer)
[17, 0, 0, 0, 0] (11)
OneDimensionalArray(Integer)
You can determine the dimensions of an array by calling the operations nrows and ncols, which return
the number of rows and columns, respectively.
nrows ( arr )
5 (12)
PositiveInteger
ncols ( arr )
4 (13)
PositiveInteger
To apply an operation to every element of an array, use map. This creates a new array. This expression
negates every element.
map ( - , arr )
596 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
−17 0 0 0
0 0 0 0
0
−15 0 0 (14)
0 0 0 0
0 0 0 0
TwoDimensionalArray(Integer)
34 0 0 0
0 0 0 0
0 30 0 0 (15)
0 0 0 0
0 0 0 0
TwoDimensionalArray(Integer)
To change the array destructively, use map! instead of map. If you need to make a copy of any array,
use copy.
arrc := copy ( arr )
17 0 0 0
0 0 0 0
0 15 0 0 (16)
0 0 0 0
0 0 0 0
TwoDimensionalArray(Integer)
map !( - , arrc )
−17 0 0 0
0 0 0 0
0
−15 0 0 (17)
0 0 0 0
0 0 0 0
TwoDimensionalArray(Integer)
arrc
−17 0 0 0
0 0 0 0
0
−15 0 0 (18)
0 0 0 0
0 0 0 0
9.87. UNIVARIATEPOLYNOMIAL 597
TwoDimensionalArray(Integer)
arr
17 0 0 0
0 0 0 0
0 15 0 0 (19)
0 0 0 0
0 0 0 0
TwoDimensionalArray(Integer)
true (20)
Boolean
member ?(10317 , arr )
false (21)
Boolean
1 (22)
PositiveInteger
count (0 , arr )
18 (23)
PositiveInteger
For more information about the operations available for TwoDimensionalArray, issue )show TwoDimensionalArray.
For information on related topics, see ‘Matrix’ on page 504 and ‘OneDimensionalArray’ on page 518.
9.87 UnivariatePolynomial
The domain constructor UnivariatePolynomial (abbreviated UP) creates domains of univariate
polynomials in a specified variable. For example, the domain UP(a1,POLY FRAC INT) provides
polynomials in the single variable a1 whose coefficients are general polynomials with rational number
coefficients.
598 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Restriction:
FriCAS does not allow you to create types where UnivariatePolynomial is contained
in the coefficient type of Polynomial. Therefore, UP(x,POLY INT) is legal but
POLY UP(x,INT) is not.
UP(x,INT) is the domain of polynomials in the single variable x with integer coefficients.
(p , q ) : UP (x , INT )
18 x3 + 60 x2 − 46 x + 8 (5)
q := (1 - 6* x + 9* x ^2) ^2
81 x4 − 108 x3 + 54 x2 − 12 x + 1 (6)
The operation leadingCoefficient extracts the coefficient of the term of highest degree.
leadingCoefficient p
18 (8)
PositiveInteger
The operation degree returns the degree of the polynomial. Since the polynomial has only one variable,
the variable is not supplied to operations like degree.
degree p
3 (9)
PositiveInteger
The reductum of the polynomial, the polynomial obtained by subtracting the term of highest order, is
returned by reductum.
reductum p
9.87. UNIVARIATEPOLYNOMIAL 599
60 x2 − 46 x + 8 (10)
The operation gcd computes the greatest common divisor of two polynomials.
gcd (p , q )
9 x2 − 6 x + 1 (11)
The operation resultant computes the resultant of two univariate polynomials. In the case of p and q,
the resultant is 0 because they share a common root.
resultant (p , q )
0 (13)
NonNegativeInteger
To compute the derivative of a univariate polynomial with respect to its variable, use D.
D p
54 x2 + 120 x − 46 (14)
Univariate polynomials can also be used as if they were functions. To evaluate a univariate polynomial
at some point, apply the polynomial to the point.
p (2)
300 (15)
PositiveInteger
The same syntax is used for composing two univariate polynomials, i.e. substituting one polynomial
for the variable in another. This substitutes q for the variable in p.
p(q)
9565938 x12 − 38263752 x11 + 70150212 x10 − 77944680 x9 + 58852170 x8 − 32227632 x7 (16)
6 5 4 3 2
+ 13349448 x − 4280688 x + 1058184 x − 192672 x + 23328 x − 1536 x + 40
600 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
List ( Integer )
From this you can use gcd and reduce to compute the content of the polynomial.
reduce ( gcd , l )
2 (19)
PositiveInteger
2 (20)
PositiveInteger
Note that the operation coefficients omits the zero coefficients from the list. Sometimes it is useful to
convert a univariate polynomial to a vector whose ith position contains the degree i-1 coefficient of
the polynomial.
ux := ( x ^4+2* x +3) :: UP (x , INT )
x4 + 2 x + 3 (21)
To get a complete vector of coefficients, use the operation vectorise, which takes a univariate polynomial
and an integer denoting the length of the desired vector.
vectorise ( ux ,5)
[3, 2, 0, 0, 1] (22)
9.87. UNIVARIATEPOLYNOMIAL 601
Vector( Integer )
18 x3 + 60 x2 − 46 x + 8 (24)
When the coefficients of the univariate polynomial belong to a field,7 it is possible to compute quotients
and remainders.
(r , s ) : UP ( a1 , FRAC INT )
r := a1 ^2 - 2/3
2
a12 − (27)
3
UnivariatePolynomial (a1, Fraction ( Integer ))
s := a1 + 4
a1 + 4 (28)
When the coefficients are rational numbers or rational expressions, the operation quo computes the
quotient of two polynomials.
r quo s
a1 − 4 (29)
7 Forexample, when the coefficients are rational numbers, as opposed to integers. The important property of a field is
that non-zero elements can be divided and produce another element. The quotient of the integers 2 and 3 is not another
integer.
602 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
46
(30)
3
UnivariatePolynomial (a1, Fraction ( Integer ))
46
quotient = a1 − 4, remainder = (31)
3
Record(quotient : UnivariatePolynomial (a1, Fraction ( Integer )) , remainder: UnivariatePolynomial (a1, Fraction ( Integer ))
)
0 (32)
It is also possible to integrate univariate polynomials when the coefficients belong to a field.
integrate r
1 3 2
a1 − a1 (33)
3 3
UnivariatePolynomial (a1, Fraction ( Integer ))
integrate s
1 2
a1 + 4 a1 (34)
2
UnivariatePolynomial (a1, Fraction ( Integer ))
Since in this case we are not talking about using multivariate polynomials in only two variables, we
use Polynomial. We also use Fraction because we want fractions.
t := a1 ^2 - a1 / b2 + ( b1 ^2 - b1 ) /( b2 +3)
9.88. UNIVERSALSEGMENT 603
1 b12 − b1
a12 − a1 + (36)
b2 b2 + 3
UnivariatePolynomial (a1, Fraction (Polynomial( Integer )))
Alternatively, we can view this as a polynomial in the variable This is a mode-directed conversion: you
indicate as much of the structure as you care about and let FriCAS decide on the full type and how to
do the transformation.
u :: UP ( b1 ,?)
1 1 a12 b2 − a1
b12 − b1 + (38)
b2 + 3 b2 + 3 b2
UnivariatePolynomial (b1, Fraction (Polynomial( Integer )))
See Section 8.2 on page 260 for a discussion of the factorization facilities in FriCAS for univariate poly-
nomials. For more information on related topics, see Section 1.9 on page 48, Section 2.7 on page 84,
‘Polynomial’ on page 533, ‘MultivariatePolynomial’ on page 513, and ‘DistributedMultivariatePolynomial’
on page 394. Issue the system command )show UnivariatePolynomial to display the full list of op-
erations defined by UnivariatePolynomial.
9.88 UniversalSegment
The UniversalSegment domain generalizes Segment by allowing segments without a “high” end
point.
pints := 1..
1.. (4)
UniversalSegment( PositiveInteger )
nevens := (0..) by -2
0 . . by − 2 (5)
UniversalSegment(NonNegativeInteger)
Values of type Segment are automatically converted to type UniversalSegment when appropriate.
3 . . 10 (6)
UniversalSegment(Integer)
The operation hasHi is used to test whether a segment has a high end point.
hasHi pints
false (7)
Boolean
hasHi nevens
false (8)
Boolean
hasHi useg
true (9)
Boolean
All operations available on type Segment apply to UniversalSegment, with the proviso that expan-
sions produce streams rather than lists. This is to accommodate infinite expansions.
expand pints
[1, 2, 3, 4, 5, 6, 7, . . .] (10)
Stream(Integer)
expand nevens
Stream(Integer)
Stream(Integer)
For more information on related topics, see ‘Segment’ on page 564, ‘SegmentBinding’ on page 566,
‘List’ on page 490, and ‘Stream’ on page 578. Issue the system command )show UniversalSegment
to display the full list of operations defined by UniversalSegment.
9.89 Vector
The Vector domain is used for storing data in a one-dimensional indexed data structure. A vector is a
homogeneous data structure in that all the components of the vector must belong to the same FriCAS
9.89. VECTOR 605
domain. Each vector has a fixed length specified by the user; vectors are not extensible. This domain is
similar to the OneDimensionalArray domain, except that when the components of a Vector belong
to a Ring, arithmetic operations are provided. For more examples of operations that are defined for
both Vector and OneDimensionalArray, see ‘OneDimensionalArray’ on page 518.
As with the OneDimensionalArray domain, a Vector can be created by calling the operation new,
its components can be accessed by calling the operations elt and qelt, and its components can be reset
by calling the operations setelt! and qsetelt!. This creates a vector of integers of length 5 all of whose
components are 12.
u : VECTOR INT := new (5 ,12)
Vector( Integer )
[1, 2, 3, 4, 5] (5)
Vector( Integer )
Indexing for vectors begins at 1. The last element has index equal to the length of the vector, which
is computed by #.
#( v )
5 (6)
PositiveInteger
This is the standard way to use elt to extract an element. Functionally, it is the same as if you had
typed elt(v,2).
v .2
2 (7)
PositiveInteger
This is the standard way to use setelt! to change an element. It is the same as if you had typed
setelt!(v, 3, 99).
v .3 := 99
99 (8)
PositiveInteger
Now look at v to see the change. You can use qelt and qsetelt! (instead of elt and setelt!, respectively)
but only when you know that the index is within the valid range.
v
606 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Vector( Integer )
When the components belong to a Ring, FriCAS provides arithmetic operations for Vector. These
include left and right scalar multiplication.
5 * v
Vector( Integer )
v * 7
Vector( Integer )
[2, 3, 4, 5, 6] (12)
Vector( Integer )
Vector( Integer )
Of course, when adding or subtracting, the two vectors must have the same length or an error message
is displayed.
v - w
Vector( Integer )
For more information about other aggregate domains, see the following: ‘List’ on page 490, ‘Matrix’
on page 504, ‘OneDimensionalArray’ on page 518, ‘Set’ on page 567, ‘Table’ on page 589, and
‘TwoDimensionalArray’ on page 593. Issue the system command )show Vector to display the full
list of operations defined by Vector.
9.90 Void
When an expression is not in a value context, it is given type Void. For example, in the expression
values are used only from the subexpressions c and f: all others are thrown away. The subexpressions
a, b, d and e are evaluated for side-effects only and have type Void. There is a unique value of type
Void.
You will most often see results of type Void when you declare a variable.
a : Integer
Usually no output is displayed for Void results. You can force the display of a rather ugly object by
issuing )set message void on.
) set message void on
b : Fraction Integer
"()" (5)
9.91 WuWenTsunTriangularSet
The WuWenTsunTriangularSet domain constructor implements the characteristic set method of
Wu Wen Tsun. This algorithm computes a list of triangular sets from a list of polynomials such
that the algebraic variety defined by the given list of polynomials decomposes into the union of the
regular-zero sets of the computed triangular sets. The constructor takes four arguments. The first one,
R, is the coefficient ring of the polynomials; it must belong to the category IntegralDomain. The
second one, E, is the exponent monoid of the polynomials; it must belong to the category Ordered-
AbelianMonoidSup. The third one, V, is the ordered set of variables; it must belong to the category
OrderedSet. The last one is the polynomial ring; it must belong to the category RecursivePolyno-
mialCategory(R,E,V). The abbreviation for WuWenTsunTriangularSet is WUTSET.
Let us illustrate the facilities by an example.
Define the coefficient ring.
R := Integer
Integer (4)
Type
[x, y, z, t] (5)
List (Symbol)
Type
Type
x (9)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
y : P := ’y
y (10)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
z : P := ’z
z (11)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
t : P := ’t
t (12)
9.91. WUWENTSUNTRIANGULARSET 609
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
WuWenTsunTriangularSet(Integer, IndexedExponents(OrderedVariableList([x,
(13)
y, z, t])), OrderedVariableList([x, y, z,
t]), NewSparseMultivariatePolynomial(Integer, OrderedVariableList([x, y, z, t])))
Type
x31 − x6 − x − y (14)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
p2 := x ^ 8 - z
x8 − z (15)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
p3 := x ^ 10 - t
x10 − t (16)
NewSparseMultivariatePolynomial(Integer , OrderedVariableList ([ x, y, z , t ]) )
lp := [ p1 , p2 , p3 ]
x31 − x6 − x − y, x8 − z, x10 − t
(17)
z 5 − t4 , t4 z 2 y 2 + 2 t3 z 4 y + −t7 + 2 t4 − t z 6 + t6 z, t3 − 1 z 3 x − z 3 y − t3
(18)
{t, z, y, x} , t3 − 1, z 5 − t4 , z 3 y + t3 , z x2 − t , z 5 − t4 , (19)
t4 z 2 y 2 + 2 t3 z 4 y + −t7 + 2 t4 − t z 6 + t6 z, t3 − 1 z 3 x − z 3 y − t3
610 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
9.92 XPBWPolynomial
Initialisations
a : Symbol := ’a
a (4)
Symbol
b : Symbol := ’b
b (5)
Symbol
RN := Fraction ( Integer )
Fraction(Integer) (6)
Type
FreeMonoid(Symbol) (7)
Type
LyndonWord(Symbol) (8)
9.92. XPBWPOLYNOMIAL 611
Type
base := P o i n c a r e B i r k h o f f W i t t L y n d o n B a s i s Symbol
PoincareBirkhoffWittLyndonBasis(Symbol) (9)
Type
dpoly := X D i s t r i b u t e d P o l y n o m i a l ( Symbol , RN )
Type
rpoly := X R e c u r s i v e P o l y n o m i a l ( Symbol , RN )
Type
Type
List (LyndonWord(Symbol))
0 (15)
XPBWPolynomial(Symbol, Fraction(Integer))
1 $ poly
1 (16)
XPBWPolynomial(Symbol, Fraction(Integer))
p : poly := a
612 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
[a] (17)
XPBWPolynomial(Symbol, Fraction(Integer))
q : poly := b
[b] (18)
XPBWPolynomial(Symbol, Fraction(Integer))
pq : poly := p * q
XPBWPolynomial(Symbol, Fraction(Integer))
ab (20)
XPBWPolynomial(Symbol, Fraction(Integer))
listOfTerms pq
reductum pq
[a b] (23)
XPBWPolynomial(Symbol, Fraction(Integer))
l ea di ng M on om ia l pq
XPBWPolynomial(Symbol, Fraction(Integer))
coefficients pq
9.92. XPBWPOLYNOMIAL 613
[1, 1] (25)
leadingTerm pq
degree pq
2 (27)
PositiveInteger
1 1 2 1 3 1
a b [a] + [b] a2 b + [b] [a b] [a] + [b] [b] [a] [a]
1 + [a b] + [b] [a] + [a b] [a b] + (28)
2 2 2 2 2
XPBWPolynomial(Symbol, Fraction(Integer))
0 (29)
XPBWPolynomial(Symbol, Fraction(Integer))
3 2
a b (30)
2
a bab (31)
a3 b2 a2 b a b
(32)
a3 b2 − 2 a2 b a b − a2 b2 a + 4 a b a b a − a b2 a2 − 2 b a b a2 + b2 a3 (33)
614 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
a2 b a b − a2 b2 a − 3 a b a2 b + 4 a b a b a − a b2 a2 + 2 b a3 b − 3 b a2 b a + b a b a2 (34)
a3 b2 a2 b a b − a3 b2 a2 b2 a − 3 a3 b2 a b a2 b + 4 a3 b2 a b a b a − a3 b2 a b2 a2
+ 2 a3 b3 a3 b − 3 a3 b3 a2 b a + a3 b3 a b a2 − a2 b a b a3 b2 + 3 a2 b a b a2 b2 a
+ 6 a2 b a b a b a2 b − 12 a2 b a b a b a b a + 3 a2 b a b a b2 a2 − 4 a2 b a b2 a3 b
+ 6 a2 b a b2 a2 b a − a2 b a b3 a3 + a2 b2 a4 b2 − 3 a2 b2 a3 b a b + 3 a2 b2 a2 b a2 b
− 2 a2 b2 a b a3 b + 3 a2 b2 a b a2 b a − 3 a2 b2 a b a b a2 + a2 b2 a b2 a3 + 3 a b a2 b a3 b2
− 6 a b a2 b a2 b a b − 3 a b a2 b a2 b2 a + 12 a b a2 b a b a b a − 3 a b a2 b a b2 a2
− 6 a b a2 b2 a b a2 + 3 a b a2 b3 a3 − 4 a b a b a4 b2 + 12 a b a b a3 b a b
− 12 a b a b a2 b a2 b + 8 a b a b a b a3 b − 12 a b a b a b a2 b a + 12 a b a b a b a b a2 (35)
2 3 2 5 2 2 4 2 3 2 2 2 3
− 4ababab a + ab a b − 3ab a bab + 3ab a ba b − 2ab a ba b
+ 3 a b2 a2 b a2 b a − 3 a b2 a2 b a b a2 + a b2 a2 b2 a3 − 2 b a3 b a3 b2 + 4 b a3 b a2 b a b
+ 2 b a3 b a2 b2 a − 8 b a3 b a b a b a + 2 b a3 b a b2 a2 + 4 b a3 b2 a b a2 − 2 b a3 b3 a3
+ 3 b a2 b a4 b2 − 6 b a2 b a3 b a b − 3 b a2 b a3 b2 a + 12 b a2 b a2 b a b a
− 3 b a2 b a2 b2 a2 − 6 b a2 b a b a b a2 + 3 b a2 b a b2 a3 − b a b a5 b2 + 3 b a b a4 b2 a
+ 6 b a b a3 b a2 b − 12 b a b a3 b a b a + 3 b a b a3 b2 a2 − 4 b a b a2 b a3 b
+ 6 b a b a2 b a2 b a − b a b a2 b2 a3 + b2 a5 b a b − b2 a5 b2 a − 3 b2 a4 b a2 b
+ 4 b2 a4 b a b a − b2 a4 b2 a2 + 2 b2 a3 b a3 b − 3 b2 a3 b a2 b a + b2 a3 b a b a2
XDistributedPolynomial(Symbol, Fraction( Integer ))
lp :: dpoly - lpd
0 (36)
3 a3 b2 a2 b a b
(37)
XPBWPolynomial(Symbol, Fraction(Integer))
q := lp1
3 2
a b (38)
9.93. XPOLYNOMIAL 615
XPBWPolynomial(Symbol, Fraction(Integer))
pq := p * q
3 a3 b2 a2 b a b a3 b2
(39)
XPBWPolynomial(Symbol, Fraction(Integer))
pr : rpoly := p :: rpoly
qr : rpoly := q :: rpoly
pq :: rpoly - pr * qr
0 (42)
9.93 XPolynomial
The XPolynomial domain constructor implements multivariate polynomials whose set of variables is
Symbol. These variables do not commute. The only parameter of this constructor is the coefficient
ring which may be non-commutative. However, coefficients and variables commute. The representation
of the polynomials is recursive. The abbreviation for XPolynomial is XPOLY.
Other constructors like XPolynomialRing, XRecursivePolynomial, XDistributedPolynomial,
LiePolynomial and XPBWPolynomial implement multivariate polynomials in non-commutative
variables.
We illustrate now some of the facilities of the XPOLY domain constructor.
Define a polynomial ring over the integers.
poly := XPolynomial ( Integer )
XPolynomial(Integer) (4)
616 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Type
− 5 + 2x + 3y (5)
XPolynomial(Integer)
XPolynomial(Integer)
− 5 + 2x + 3y (7)
XDistributedPolynomial(Symbol, Integer )
25 − 20 x − 30 y + 4 x2 + 6 x y + 6 y x + 9 y 2 (8)
XDistributedPolynomial(Symbol, Integer )
0 (9)
XDistributedPolynomial(Symbol, Integer )
We define:
qr := pr ^3
XPolynomial(Integer)
and:
qd := pd ^3
9.93. XPOLYNOMIAL 617
We truncate qd at degree 3:
trunc ( qd ,2)
XDistributedPolynomial(Symbol, Integer )
XPolynomial(Integer)
We define:
Word := FreeMonoid Symbol
FreeMonoid(Symbol) (14)
Type
and:
w : Word := x * y ^2
x y2 (15)
FreeMonoid(Symbol)
18 (16)
XPolynomial(Integer)
2 x y y x + (2 x y x + ((−5 + 4 x + 3 y) x + 9 x y) y) y (17)
XPolynomial(Integer)
618 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
9.94 XPolynomialRing
The XPolynomialRing domain constructor implements generalized polynomials with coefficients
from an arbitrary Ring (not necessarily commutative) and whose exponents are words from an arbi-
trary OrderedMonoid (not necessarily commutative too). Thus these polynomials are (finite) linear
combinations of words.
This constructor takes two arguments. The first one is a Ring and the second is an OrderedMonoid.
The abbreviation for XPolynomialRing is XPR.
Other constructors like XPolynomial, XRecursivePolynomial, XDistributedPolynomial, LiePoly-
nomial and XPBWPolynomial implement multivariate polynomials in non-commutative variables.
We illustrate now some of the facilities of the XPR domain constructor.
Define the free ordered monoid generated by the symbols.
Word := FreeMonoid ( Symbol )
FreeMonoid(Symbol) (4)
Type
Type
1 + 2x − 3y (6)
XPolynomialRing(Integer, FreeMonoid(Symbol))
1 + 2x (7)
XPolynomialRing(Integer, FreeMonoid(Symbol))
2 + 4x − 3y (8)
XPolynomialRing(Integer, FreeMonoid(Symbol))
their product,
9.94. XPOLYNOMIALRING 619
p * q
1 + 4 x − 3 y + 4 x2 − 6 y x (9)
XPolynomialRing(Integer, FreeMonoid(Symbol))
XPolynomialRing(Integer, FreeMonoid(Symbol))
Type
Type
1 2
(13)
4 8
a second one,
m2 : M := m1 - 5/4
1
−4 2
27 (14)
4 4
129
16
13
857 (15)
26 16
620 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Define a polynomial,
pm : poly1 := m1 * x + m2 * y + m3 * z - 2/3
2 1 129
−3 0 1 2 −4 2 16
13
+ x+ y+ z (16)
0 − 23 4 8 4 27
4
26 857
16
a second one,
qm : poly1 := pm - m1 * x
2 1 129
−3 0 −4 2 16
13
2 + 27 y+ 857 z (17)
0 −3 4 4
26 16
8
1 8 43 52
129 3199
− 831
− 27 0 −3 3 4 3
− 8 −26 2 − 32 4
+ 16 y + 104 857 z + y + yz
0 −8 9 −52 − 857 − 831 − 26467
319927 831
3
3
103169 12
6409
31998 831
2
103169 32 6409
− 32 − 4 − 128 − 4
+ zy+ z 2 + 831 64 8 y 3 + 6409256 8 y2 z
− 831
2
− 26467
32
− 6409
2
− 820977
128 4
26467
64 4
820977
256
(18)
103169 6409
3178239 795341
103169 6409
+ 6409256 8
820977
1024
y z y + 795341 128
25447787 y z 2 + 6409 256 8
820977 z y2
4 256 64 1024 4 256
3178239 795341
3178239 795341
98625409 12326223
2
1024
+ 795341 128
25447787 z y z + 1024
795341
128
25447787 z y + 4096
12326223
256
788893897 z3
64 1024 64 1024 128 4096
9.95 ZeroDimensionalSolvePackage
The ZeroDimensionalSolvePackage package constructor provides operations for computing sym-
bolically the complex or real roots of zero-dimensional algebraic systems.
The package provides no multiplicity information (i.e. some returned roots may be double or higher)
but only distinct roots are returned.
Complex roots are given by means of univariate representations of irreducible regular chains. These
representations are computed by the univariateSolve operation (by calling the InternalRationalU-
nivariateRepresentationPackage package constructor which does the job).
Real roots are given by means of tuples of coordinates lying in the RealClosure of the coefficient ring.
They are computed by the realSolve and positiveSolve operations. The former computes all the
solutions of the input system with real coordinates whereas the later concentrate on the solutions with
(strictly) positive coordinates. In both cases, the computations are performed by the RealClosure
constructor.
9.95. ZERODIMENSIONALSOLVEPACKAGE 621
Both computations of complex roots and real roots rely on triangular decompositions. These decom-
positions can be computed in two different ways. First, by a applying the zeroSetSplit operation
from the REGSET domain constructor. In that case, no Groebner bases are computed. This strategy
is used by default. Secondly, by applying the zeroSetSplit from LEXTRIPK. To use this later
strategy with the operations univariateSolve, realSolve and positiveSolve one just needs to use
an extra boolean argument.
Note that the way of understanding triangular decompositions is detailed in the example of the Reg-
ularTriangularSet constructor.
The ZeroDimensionalSolvePackage constructor takes three arguments. The first one R is the
coefficient ring; it must belong to the categories OrderedRing, EuclideanDomain, Characteris-
ticZero and RealConstant. This means essentially that R is Integer or Fraction(Integer). The
second argument ls is the list of variables involved in the systems to solve. The third one MUST BE
concat(ls,s) where s is an additional symbol used for the univariate representations. The abbreviation
for ZeroDimensionalSolvePackage is ZDSOLVE.
We illustrate now how to use the constructor ZDSOLVE by two examples: the Arnborg and Lazard
system and the L-3 system (Aubry and Moreno Maza). Note that the use of this package is also
demonstrated in the example of the LexTriangularPackage constructor.
Define the coefficient ring.
R := Integer
Integer (4)
Type
[x, y, z, t] (5)
List (Symbol)
and:
ls2 : List Symbol := [x ,y ,z ,t , new () $ Symbol ]
List (Symbol)
Type
x y z 2 + x y 2 + x2 + x + 1 y + x z + x y
(8)
Polynomial( Integer )
p2 := x ^2* y ^2* z + x * y ^2* z ^2 + x ^2* y * z + x * y * z + y * z + x + z
x y 2 z 2 + x2 y 2 + x2 + x + 1 y + 1 z + x
(9)
Polynomial( Integer )
p3 := x ^2* y ^2* z ^2 + x ^2* y ^2* z + x * y ^2* z + x * y * z + x * z + z + 1
x2 y 2 z 2 + x2 + x y 2 + x y + x + 1 z + 1
(10)
Polynomial( Integer )
lp := [ p1 , p2 , p3 ]
x y z 2 + x y 2 + x2 + x + 1 y + x z + x y, x y 2 z 2 + x2 y 2 + x2 + x + 1 y + 1 z + x, (11)
x2 y 2 z 2 + x2 + x y 2 + x y + x + 1 z + 1
Note that these polynomials do not involve the variable t; we will use it in the second example.
First compute a decomposition into regular chains (i.e. regular triangular sets).
triangSolve ( lp ) $ pack
We can see easily from this decomposition (consisting of a single regular chain) that the input system
has 20 complex roots.
Then we compute a univariate representation of this regular chain.
u ni va ri a te So lv e ( lp ) $ pack
coordinates = 63 x+62 %A11 −721 %A10 +1220 %A9 +705 %A8 −285 %A7 +1512 %A6 −735 %A5 +1401 %A4 −21 %A3 +215 %A2 +1
63 y−75 %A11 +890 %A10 −1682 %A9 −516 %A8 +588 %A7 −1953 %A6 +1323 %A5 −1815 %A4 +426 %A3 −243 %A2 −1801 %A+679
z − %A , complexRoots = ?6 + ?5 + ?4 + ?3 + ?2 + ? + 1, coordinates = x − %A5 ,
We see that the zeros of our regular chain are split into three components. This is due to the use of
univariate polynomial factorization.
Each of these components consist of two parts. The first one is an irreducible univariate polynomial
p(?) which defines a simple algebraic extension of the field of fractions of R. The second one consists
of multivariate polynomials pol1(x,%A), pol2(y,%A) and pol3(z,%A). Each of these polynomials
involve two variables: one is an indeterminate x, y or z of the input system lp and the other is %A
which represents any root of p(?). Recall that this %A is the last element of the third parameter
of ZDSOLVE. Thus any complex root ? of p(?) leads to a solution of the input system lp by
replacing %A by this ? in pol1(x,%A), pol2(y,%A) and pol3(z,%A). Note that the polynomials
pol1(x,%A), pol2(y,%A) and pol3(z,%A) have degree one w.r.t. x, y or z respectively. This is
always the case for all univariate representations. Hence the operation univariateSolve replaces a
system of multivariate polynomials by a list of univariate polynomials, what justifies its name. Another
example of univariate representations illustrates the LexTriangularPackage package constructor.
We now compute the solutions with real coordinates:
lr := realSolve ( lp ) $ pack ;
List ( List (RealClosure( Fraction ( Integer ))))
8 (15)
PositiveInteger
Each of these real solutions is given by a list of elements in RealClosure(R). In these 8 lists, the
first element is a value of z, the second of y and the last of x. This is logical since by setting the
list of variables of the package to [x,y,z,t] we mean that the elimination ordering on the variables is
t < z < y < x. Note that each system treated by the ZDSOLVE package constructor needs only to
be zero-dimensional w.r.t. the variables involved in the system it-self and not necessarily w.r.t. all the
variables used to define the package.
We can approximate these real numbers as follows. This computation takes between 30 sec. and 5
min, depending on your machine.
[[ approximate (r ,1/1000000) for r in point ] for point in lr ];
List ( List ( Fraction ( Integer )))
We can also concentrate on the solutions with real (strictly) positive coordinates:
lpr := positiveSolve ( lp ) $ pack
[] (17)
Thus we have checked that the input system has no solution with strictly positive coordinates.
Let us define another polynomial system (L-3).
f0 := x ^3 + y + z + t - 1
624 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
z + y + x3 + t − 1 (18)
Polynomial( Integer )
f1 := x + y ^3 + z + t -1
z + y3 + x + t − 1 (19)
Polynomial( Integer )
f2 := x + y + z ^3 + t -1
z3 + y + x + t − 1 (20)
Polynomial( Integer )
f3 := x + y + z + t ^3 -1
z + y + x + t3 − 1 (21)
Polynomial( Integer )
lf := [ f0 , f1 , f2 , f3 ]
z + y + x3 + t − 1, z + y 3 + x + t − 1, z 3 + y + x + t − 1, z + y + x + t3 − 1
(22)
First compute a decomposition into regular chains (i.e. regular triangular sets).
lts := triangSolve ( lf ) $ pack
9.95. ZERODIMENSIONALSOLVEPACKAGE 625
t2 + t + 1, z 3 − z − t3 + t, 3 z + 3 t3 − 3 y 2 + 3 z 2 + 6 t3 − 6 z + 3 t6 − 6 t3 + 3 y + 3 t3 − 3 z 2
(23)
+ 3 t6 − 6 t3 + 3 z + t9 − 3 t6 + 5 t3 − 3 t, x + y + z , t16 − 6 t13 + 9 t10 + 4 t7 + 15 t4 − 54 t2 + 27,
4907232 t15 +40893984 t14 −115013088 t13 +22805712 t12 +36330336 t11 +162959040 t10 −159859440 t9 −156802608 t8 +117168768 t7
+ 48 t54 − 912 t51 + 8232 t48 − 72 t46 − 46848 t45 + 1152 t43 + 186324 t42 − 3780 t40 − 543144 t39 − 3168 t38
− 21384 t37 + 1175251 t36 + 41184 t35 + 278003 t34 − 1843242 t33 − 301815 t32 − 1440726 t31
+ 1912012 t30 + 1442826 t29 + 4696262 t28 − 922481 t27 − 4816188 t26 − 10583524 t25 − 208751 t24
+ 11472138 t23 + 16762859 t22 − 857663 t21 − 19328175 t20 − 18270421 t19 + 4914903 t18 + 22483044 t17
+ 12926517 t16 − 8605511 t15 − 17455518 t14 − 5014597 t13 + 8108814 t12 + 8465535 t11 + 190542 t10
− 4305624 t9 − 2226123 t8 + 661905 t7 + 1169775 t6 + 226260 t5 − 209952 t4 − 141183 t3 + 27216 t,
3 z + 3 t3 − 3 y 2 + 3 z 2 + 6 t3 − 6 z + 3 t6 − 6 t3 + 3 y + 3 t3 − 3 z 2 + 3 t6 − 6 t3 + 3 z + t9
− 3 t6 + 5 t3 − 3 t, x + y + z + t3 − 1 , t, z − 1, y 2 − 1, x + y , t − 1, z, y 2 − 1,
4907232 t29 +40893984 t28 −115013088 t27 −1730448 t26 −168139584 t25 +738024480 t24 −195372288 t23 +315849456 t22 −2567279232
− 48 t68 + 1152 t65 − 13560 t62 + 360 t60 + 103656 t59 − 7560 t57 − 572820 t56 + 71316 t54 + 2414556 t53
+ 2736 t52 − 402876 t51 − 7985131 t50 − 49248 t49 + 1431133 t48 + 20977409 t47 + 521487 t46 − 2697635 t45
− 43763654 t44 − 3756573 t43 − 2093410 t42 + 71546495 t41 + 19699032 t40 + 35025028 t39 − 89623786 t38
− 77798760 t37 − 138654191 t36 + 87596128 t35 + 235642497 t34 + 349607642 t33 − 93299834 t32
−551563167 t31 −630995176 t30 +186818962 t29 +995427468 t28 +828416204 t27 −393919231 t26 −1076617485 t25
−1609479791 t24 +595738126 t23 +1198787136 t22 +4342832069 t21 −2075938757 t20 −4390835799 t19 −4822843033 t18
+6932747678 t17 +6172196808 t16 +1141517740 t15 −4981677585 t14 −9819815280 t13 −7404299976 t12 −157295760 t11
+29124027630 t10 +14856038208 t9 −16184101410 t8 −26935440354 t7 −3574164258 t6 +10271338974 t5 +11191425264 t4
+ 6869861262 t3 − 9780477840 t2 − 3586674168 t + 2884297248,
3 z 3 + 6 t3 −6 z 2 + 6 t6 −12 t3 +3 z +2 t9 −6 t6 +t3 +3 t y+ 3 t3 −3 z 3 + 6 t6 −12 t3 +6 z 2 + 4 t9 −12 t6 +11 t3 −3 z
+ t12 − 4 t9 + 5 t6 − 2 t3 , x + y + z + t3 − 1 , t − 1, z 2 − 1,
y, x + z , t8 + t7 + t6 − 2 t5 − 2 t4 − 2 t3 + 19 t2 + 19 t − 8,
+ 9 t6 −18 t3 +9 z 3 + −181 t3 +270 t−89 z 2 + −92 t6 +135 t4 +49 t3 −135 t+43 z +27 t7 −27 t6 −54 t4 +396 t3
− 486 t + 144, x + y + z + t3 − 1 , t, z − t3 + 1, y − 1, x − 1 ,
{t − 1, z, y, x} , {t, z − 1, y, x} , {t, z, y − 1, x} , {t, z, y, x − 1}
[complexRoots = ?, coordinates = [x − 1, y − 1, z + 1, t − %A]] , [complexRoots = ?, coordinates = [x, y − 1,
z, t − %A]] , [complexRoots = ? − 1, coordinates = [x, y, z, t − %A]] , [complexRoots = ?, coordinates = [x − 1,
y, z, t − %A]] , [complexRoots = ?, coordinates = [x, y, z − 1, t − %A]] , [complexRoots = ?,
coordinates = [x + 1, y − 1, z, t − 1]] , [complexRoots = ? − 2, coordinates = [x − 1, y + 1, z, t − 1]] ,
[complexRoots = ? − 1, coordinates = [x − 1, y + 1, z − 1, t]] , [complexRoots = ? + 1, coordinates = [x + 1,
y − 1, z − 1, t]] , complexRoots = ?6 − 2 ?3 + 3 ?2 − 3, coordinates = 2 x + %A3 + %A − 1, 2 y + %A3 + %A − 1,
(24)
Note that this computation is made from the input system lf. However it is possible to reuse a
pre-computed regular chain as follows:
ts := lts .1
t2 + t + 1, z 3 − z − t3 + t, 3 z + 3 t3 − 3 y 2 + 3 z 2 + 6 t3 − 6 z + 3 t6 − 6 t3 + 3 y (25)
+ 3 t3 − 3 z 2 + 3 t6 − 6 t3 + 3 z + t9 − 3 t6 + 5 t3 − 3 t, x + y + z
u ni va ri a te So lv e ( ts ) $ pack
9.95. ZERODIMENSIONALSOLVEPACKAGE 627
complexRoots = ?4 + 5 ?3 + 16 ?2 + 30 ? + 57,
realSolve ( ts ) $ pack
[] (27)
27 (29)
PositiveInteger
1 1 1 1 1 1
%B40, − %B403 + , − %B403 + , − %B403 + (30)
3 3 3 3 3 3
List (Float)
628 CHAPTER 9. SOME EXAMPLES OF DOMAINS AND PACKAGES
Part III
629
Chapter 10
Interactive Programming
Programming in the interpreter is easy. So is the use of FriCAS’s graphics facility. Both are rather
flexible and allow you to use them for many interesting applications. However, both require learning
some basic ideas and skills.
All graphics examples in the FriCAS Images section are either produced directly by interactive com-
mands or by interpreter programs. Four of these programs are introduced here. By the end of this
chapter you will know enough about graphics and programming in the interpreter to not only under-
stand all these examples, but to tackle interesting and difficult problems on your own. Appendix B
lists all the remaining commands and programs used to create these images.
631
632 CHAPTER 10. INTERACTIVE PROGRAMMING
x^2
X Y
Now that was easy! What you get is a “wire-mesh” rendition of the ribbon. That’s fine for now. Notice
that the mesh-size is small in both the x and the y directions. FriCAS normally computes points in
both these directions. This is unnecessary. One step is all we need in the y-direction. To have FriCAS
economize on y-points, we re-draw the ribbon with option var2Steps == 1.
Re-draw the ribbon, but with option var2Steps == 1 so that only 1 step is computed in the y direc-
tion.
vp := draw ( x ^2 , x = -1..1 , y =0..1 , var2Steps ==1)
x^2
X Y
The operation has created a viewport, that is, a graphics window on your screen. We assigned the
viewport to vp and now we manipulate its contents.
Graphs are objects, like numbers and algebraic expressions. You may want to do some experimenting
with graphs. For example, say
showRegion(vp, "on")
to put a bounding box around the ribbon. Try it! Issue rotate(vp, -45, 90) to rotate the figure
−45 longitudinal degrees and 90 latitudinal degrees.
Here is a different rotation. This turns the graph so you can view it along the y-axis.
rotate ( vp , 0 , -90)
10.1. DRAWING RIBBONS INTERACTIVELY 633
x^2
X
Y
There are many other things you can do. In fact, most everything you can do interactively using
the three-dimensional control panel (such as translating, zooming, resizing, coloring, perspective and
lighting selections) can also be done directly by operations (see Chapter 7 for more details).
When you are done experimenting, say reset(vp) to restore the picture to its original position and
settings.
Let’s add another ribbon to our picture—one for x3 . Since y ranges from 0 to 1 for the first ribbon,
now let y range from 1 to 2. This puts the second ribbon next to the first one.
How do you add a second ribbon to the viewport? One method is to extract the “space” component
from the viewport using the operation subspace. You can think of the space component as the object
inside the window (here, the ribbon). Let’s call it sp. To add the second ribbon, you draw the second
ribbon using the option space == sp.
Extract the space component of vp.
sp := subspace ( vp )
x^3
Z
X Y
Unless you moved the original viewport, the new viewport covers the old one. You might want to check
that the old object is still there by moving the top window.
634 CHAPTER 10. INTERACTIVE PROGRAMMING
Let’s show quadrilateral polygon outlines on the ribbons and then enclose the ribbons in a box.
Show quadrilateral polygon outlines.
drawStyle ( vp ," shade ") ; outlineRender ( vp ," on ")
x^3
Z
X Y
x^3
Z
This process has become tedious! If we had to add two or three more ribbons, we would have to repeat
the above steps several more times. It is time to write an interpreter program to help us take care of
the details.
We now create a function drawRibbons of two arguments: flist, a list of formulas for the ribbons
you want to draw, and xrange, the range over which you want them drawn. Using this function, you
can just say
to do all of the work required in the last section. Here is the drawRibbons program. Invoke your
favorite editor and create a file called ribbon.input containing the following program.
Here are some remarks on the syntax used in the drawRibbons function (consult Chapter 6 for more
details). Unlike most other programming languages which use semicolons, parentheses, or begin–end
brackets to delineate the structure of programs, the structure of an FriCAS program is determined by
indentation. The first line of the function definition always begins in column 1. All other lines of the
function are indented with respect to the first line and form a pile (see Section 5.2 on page 126).
The definition of drawRibbons consists of a pile of expressions to be executed one after another.
Each expression of the pile is indented at the same level. Lines 4-7 designate one single expression:
since lines 5-7 are indented with respect to the others, these lines are treated as a continuation of line
4. Also since lines 5 and 7 have the same indentation level, these lines designate a pile within the outer
pile.
The last line of a pile usually gives the value returned by the pile. Here it is also the value returned
by the function. FriCAS knows this is the last line of the function because it is the last line of the file.
In other cases, a new expression beginning in column one signals the end of a function.
The line drawStyle(vp,"shade") is given after the viewport has been created to select the draw style.
We have also used the zoom option. Without the zoom, the viewport region would be scaled equally
in all three coordinate directions.
Let’s try the function drawRibbons. First you must read the file to give FriCAS the function
definition.
Read the input file.
) read ribbon
Ribbons
0.0 (1)
DoubleFloat
1.0 (2)
DoubleFloat
The “@” sign means “of the type.” Thus zero is 0.0 of the type DoubleFloat. You can also say
0.0::DFLOAT.
Points can have four small float components: x, y, z coordinates and an optional color. A “curve” is
simply a list of points connected by straight line segments. Create the point origin with color zero,
that is, the lowest color on the color map.
origin := point [ zero , zero , zero , zero ]
Point(DoubleFloat)
Point(DoubleFloat)
List (Point(DoubleFloat))
We make this line segment into an arrow by adding an arrowhead. The arrowhead extends to, say, p3
on the left, and to, say, p4 on the right. To describe an arrow, you tell FriCAS to draw the two curves
[p1, p2, p3] and [p2, p4]. We also decide through experimentation on values for arrowScale, the
ratio of the size of the arrowhead to the stem of the arrow, and arrowAngle, the angle between the
arrowhead and the arrow.
638 CHAPTER 10. INTERACTIVE PROGRAMMING
Invoke your favorite editor and create an input file called arrows.input. This input file first defines
the values of arrowAngle and arrowScale, then defines the function makeArrow(p1 , p2 ) to draw an
arrow from point p1 to p2 .
1 arrowAngle := % pi -% pi /10.0 @DFLOAT -- The angle of the arrowhead.
2 arrowScale := 0.2 @DFLOAT -- The size of the arrowhead
3 -- relative to the stem.
4 makeArrow ( p1 , p2 ) ==
5 delta := p2 - p1 -- The arrow.
6 len := arrowScale * length delta -- The length of the arrowhead.
7 theta := atan ( delta .1 , delta .2) -- The angle from the x-axis
8 c1 := len * cos ( theta + arrowAngle ) -- The x-coord of left endpoint.
9 s1 := len * sin ( theta + arrowAngle ) -- The y-coord of left endpoint.
10 c2 := len * cos ( theta - arrowAngle ) -- The x-coord of right endpoint.
11 s2 := len * sin ( theta - arrowAngle ) -- The y-coord of right endpoint.
12 z := p2 .3*(1 - arrowScale ) -- The z-coord of both endpoints.
13 p3 := point [ p2 .1 + c1 , p2 .2 + s1 , z , p2 .4] -- The left endpoint of head.
14 p4 := point [ p2 .1 + c2 , p2 .2 + s2 , z , p2 .4] -- The right endpoint of head.
15 [[ p1 , p2 , p3 ] , [ p2 , p4 ]] -- The arrow as a list of curves.
Read the file and then create an arrow from the point origin to the point unit. Read the input file
defining makeArrow.
) read arrows
[[[0.0, 0.0, 0.0, 0.0] , [1.0, 1.0, 1.0, 0.0] , [0.6913462860460797, 0.842733077659504, (9)
0.8, 0.0]] , [[1.0, 1.0, 1.0, 0.0] , [0.842733077659504, 0.6913462860460797, 0.8, 0.0]]]
ThreeSpace(DoubleFloat)
Arrow
X Y
Arrow
A Dozen Arrows
X Y
Notice that we identify clipValue as a small float but do not declare the type of the function clipFun.
As it turns out, clipFun is called with a small float value. This declaration ensures that clipFun never
does a conversion when it is called.
10.6. DRAWING COMPLEX VECTOR FIELDS 641
The second matter concerns the possible “poles” of a function, the actual points where the spikes have
infinite values. FriCAS uses normal DoubleFloat arithmetic which does not directly handle infinite
values. If your function has poles, you must adjust your step size to avoid landing directly on them
(FriCAS calls error when asked to divide a value by 0, for example).
We set the variables realSteps and imagSteps to hold the number of steps taken in the real and
imaginary directions, respectively. Most examples will have ranges centered around the origin. To
avoid a pole at the origin, the number of points is taken to be odd.
1 realSteps : INT := 25 -- Number of real steps.
2 imagSteps : INT := 25 -- Number of imaginary steps.
3 ) read arrows
Now define the function drawComplexVectorField to draw the arrows. It is good practice to declare
the type of the main function in the file. This one declaration is usually sufficient to ensure that other
lower-level functions are compiled with the correct types.
4 C := Complex DoubleFloat
5 S := Segment DoubleFloat
6 d r a w C o m p l e x V e c t o r F i e l d : ( C -> C , S , S ) -> VIEW3D
The first argument is a function mapping complex small floats into complex small floats. The second
and third arguments give the range of real and imaginary values as segments like a..b. The result is
a three-dimensional viewport. Here is the full function definition:
1 d r a w C o m p l e x V e c t o r F i e l d (f , realRange , imagRange ) ==
2 delReal := ( high ( realRange ) - low ( realRange ))/ realSteps -- The real step size.
3 delImag := ( high ( imagRange ) - low ( imagRange ))/ imagSteps -- The imaginary step size.
4 sp := c r e a t e T h r e e S p a c e () -- Create empty space sp.
5 real := low ( realRange ) -- The initial real value.
6 for i in 1.. realSteps +1 repeat -- Begin real iteration.
7 imag := low ( imagRange ) -- The initial imaginary value.
8 for j in 1.. imagSteps +1 repeat -- Begin imaginary iteration.
9 z := f complex ( real , imag ) -- The value of f at the point.
10 arg := argument z -- The direction of the arrow.
11 len := clipFun sqrt norm z -- The length of the arrow.
12 p1 := point [ real , imag , 0.0 @DFLOAT , arg ] -- The base point of the arrow.
13 scaleLen := delReal * len -- The scaled length of the arrow.
14 p2 := point [ p1 .1 + scaleLen * cos ( arg ) , -- The tip point of the arrow.
15 p1 .2 + scaleLen * sin ( arg ) ,0.0 @DFLOAT , arg ]
16 arrow := makeArrow ( p1 , p2 ) -- Create the arrow.
17 for a in arrow repeat curve ( sp , a ) -- Add arrow to the space sp.
18 imag := imag + delImag -- The next imaginary value.
19 real := real + delReal -- The next real value.
20 makeV iewport 3D ( sp , " Complex Vector Field ") -- Draw it!
As a first example, let us draw f(z) == sin(z). There is no need to create a user function: just pass
the sin from Complex DoubleFloat. Read the file.
) read vectors
X Y
Variables delReal and delImag give the step sizes along the real and imaginary directions as computed
by the values of the global variables realSteps and imagSteps. The mesh is represented by a list of
lists of points llp, initially empty. Now [ ] alone is ambiguous, so to set this initial value you have
to tell FriCAS what type of empty list it is. Next comes the loop which builds llp.
1 real := low ( realRange ) -- The initial real value.
2 for i in 1.. realSteps +1 repeat -- Begin real iteration.
3 imag := low ( imagRange ) -- The initial imaginary value.
4 lp := [] $ ( List Point DFLOAT ) -- The initial list of points lp.
5 for j in 1.. imagSteps +1 repeat -- Begin imaginary iteration.
6 z := f complex ( real , imag ) -- The value of f at the point.
7 pt := point [ real , imag , clipFun sqrt norm z , -- Create a point.
8 argument z ]
9 lp := cons ( pt , lp ) -- Add the point to lp.
10 imag := imag + delImag -- The next imaginary value.
11 real := real + delReal -- The next real value.
12 llp := cons ( lp , llp ) -- Add lp to llp.
The code consists of both an inner and outer loop. Each pass through the inner loop adds one list lp
of points to the list of lists of points llp. The elements of lp are collected in reverse order.
10.8. FUNCTIONS PRODUCING FUNCTIONS 643
1 makeV iewport 3D ( mesh ( llp ) , " Complex Function ") -- Create a mesh and display.
The operation mesh then creates an object of type ThreeSpace(DoubleFloat) from the list of lists
of points. This is then passed to makeViewport3D to display the image.
Now add this function directly to your vectors.input file and re-read the file using )read vectors.
We try drawComplex using a user-defined function f.
Read the file.
) read vectors
Complex Function
X Y
5 4 10 3 10 2 5 1
x5 + x + x + x + x+ (1)
3 9 27 81 243
Polynomial(Fraction ( Integer ))
Convert this to an anonymous function of x. Assign it to the variable p to give the function a name.
p := c o mp i l e d F u n c t i o n (% , x ) $ M a k e U n a r y C o m p i l e d F u n c t i o n ( POLY FRAC INT , DFLOAT , DFLOAT )
Compiling function % A with type DoubleFloat -> DoubleFloat
theMap(unaryFunction) (2)
(DoubleFloat → DoubleFloat)
3.668751115057229 (3)
DoubleFloat
12 v := theVariableIn f -- function.
13 c o m p i l e d Fu n c t i o n (f , v ) $ c om pl ex F un Pa c k
14
15 c o m p l e x D e r i v a t i v e F u n c t i o n (f , n ) == -- Create an nth derivative
16 v := theVariableIn f -- function.
17 df := D (f ,v , n )
18 c o m p i l e d Fu n c t i o n ( df , v ) $ c om pl ex F un Pa c k
19
20 theVariableIn f == -- Returns the variable in f .
21 vl := variables f -- The list of variables.
22 nv := # vl -- The number of variables.
23 nv > 1 = > error " Expression is not univariate ."
24 nv = 0 = > ’x -- Return a dummy variable.
25 first vl
Do you see what is going on here? A formula f is passed into the function newtonStep. First, the
function turns f into a compiled program mapping complex numbers into complex numbers. Next, it
does the same thing for the derivative of f. Finally, it returns a function which computes a single step
of Newton’s iteration.
The function complexNumericFunction extracts the variable from the expression f and then turns
f into a function which maps complex numbers into complex numbers. The function complexDeriva-
tiveFunction does the same thing for the derivative of f. The function theVariableIn extracts the
variable from the expression f, calling the function error if f has more than one variable. It returns
the dummy variable x if f has no variables.
Let’s now apply newtonStep to the formula for computing cube roots of two. Read the input file
with the definitions.
) read newton
) read vectors
x3 − 2 (19)
Polynomial( Integer )
theMap(?) (20)
646 CHAPTER 10. INTERACTIVE PROGRAMMING
(Complex(DoubleFloat)→ Complex(DoubleFloat))
Let a denote the result of applying Newton’s iteration once to the complex number 1 + %i.
a := g (1.0 + % i )
Complex(DoubleFloat)
Stream(Complex(DoubleFloat))
Complex(DoubleFloat)
In ‘MappingPackage1’ on page 501, we show how functions can be manipulated as objects in FriCAS.
A useful operation to consider here is *, which means composition. For example g*g causes the Newton
iteration formula to be applied twice. Correspondingly, g^n means to apply the iteration formula n
times.
Apply g twice to the point 1 + %i.
( g * g ) (1.0 + % i )
Complex(DoubleFloat)
Apply g 11 times.
( g ^11) (1.0 + % i )
1.2599210498948732 (25)
Complex(DoubleFloat)
Look now at the vector field and surface generated after two steps of Newton’s formula for the cube
root of two. The poles in these pictures represent bad starting values, and the flat areas are the regions
of convergence to the three roots. The vector field.
d r a w C o m p l e x V e c t o r F i e l d ( g ^3 , -3..3 , -3..3)
10.9. AUTOMATIC NEWTON ITERATION FORMULAS 647
X Y
The surface.
drawComplex ( g ^3 , -3..3 , -3..3)
Complex Function
X Y
648 CHAPTER 10. INTERACTIVE PROGRAMMING
Chapter 11
Packages
Packages provide the bulk of FriCAS’s algorithmic library, from numeric packages for computing special
functions to symbolic facilities for differential equations, symbolic integration, and limits.
In Chapter 10, we developed several useful functions for drawing vector fields and complex functions.
We now show you how you can add these functions to the FriCAS library to make them available for
general use.
The way we created the functions in Chapter 10 is typical of how you, as an advanced FriCAS user,
may interact with FriCAS. You have an application. You go to your editor and create an input file
defining some functions for the application. Then you run the file and try the functions. Once you
get them all to work, you will often want to extend them, add new features, perhaps write additional
functions.
Eventually, when you have a useful set of functions for your application, you may want to add them
to your local FriCAS library. To do this, you embed these function definitions in a package and add
that package to the library.
To introduce new packages, categories, and domains into the system, you need to use the FriCAS
compiler to convert the constructors into executable machine code. An existing compiler in FriCAS is
available on an “as-is” basis. A new, faster compiler will be available in version 2.0 of FriCAS.
649
650 CHAPTER 11. PACKAGES
the name S can be used in the file as a shorthand for Segment DoubleFloat.2 The abbreviation
command for the package
11.2 Syntax
The definition of a package has the syntax:
The syntax for defining a package constructor is the same as that for defining any function in FriCAS.
In practice, the definition extends over many lines so that this syntax is not practical. Also, the type
of a package is expressed by the operator with followed by an explicit list of operations. A preferable
way to write the definition of a package is with a where expression:
The DrawComplex package takes no parameters and exports five operations, each a separate item
of a pile. Each operation is described as a declaration: a name, followed by a colon (“:”), followed by
the type of the operation. All operations have types expressed as mappings with the syntax
source → target
arrows emanating from the surface to indicate the direction of the complex argument.
652 CHAPTER 11. PACKAGES
11.4 Capsules
The part to the right of add in the Implementation part of the definition is called a capsule. The
purpose of a capsule is:
What is a local environment? First, what is an environment? Think of the capsule as an input file that
FriCAS reads from top to bottom. Think of the input file as having a )clear all at the top so that
initially no variables or functions are defined. When this file is read, variables such as realSteps and
arrowSize in DrawComplex are set to initial values. Also, all the functions defined in the capsule
are compiled. These include those that are exported (like drawComplex), and those that are not
(like makeArrow). At the end, you get a set of name-value pairs: variable names (like realSteps and
arrowSize) are paired with assigned values, while operation names (like drawComplex and makeArrow)
are paired with function values.
This set of name-value pairs is called an environment. Actually, we call this environment the “initial
environment” of a package: it is the environment that exists immediately after the package is first
built. Afterwards, functions of this capsule can access or reset a variable in the environment. The
environment is called local since any changes to the value of a variable in this environment can be seen
only by these functions.
Only the functions from the package can change the variables in the local environment. When two
functions are called successively from a package, any changes caused by the first function called are
seen by the second.
Since the environment is local to the package, its names don’t get mixed up with others in the system
or your workspace. If you happen to have a variable called realSteps in your workspace, it does not
affect what the DrawComplex functions do in any way.
The functions in a package are compiled into machine code. Unlike function definitions in input files
that may be compiled repeatedly as you use them with varying argument types, functions in packages
have a unique type (generally parameterized by the argument parameters of a package) and a unique
compilation residing on disk.
The capsule itself is turned into a compiled function. This so-called capsule function is what builds
the initial environment spoken of above. If the package has arguments (see below), then each call to
the package constructor with a distinct pair of arguments builds a distinct package, each with its own
local environment.
mind. FriCAS sometimes fails to get it right. Then—and only then—do you need a declaration to tell
FriCAS what type you want.
Input files are usually written to be read by FriCAS—and by you. Without suitable documentation
and declarations, your input files are likely incomprehensible to a colleague—and to you some months
later!
Packages are designed for legibility, as well as run-time efficiency. There are few new concepts you
need to learn to write packages. Rather, you just have to be explicit about types and type conversions.
The types of all functions are pre-declared so that FriCAS—and the reader— knows precisely what
types of arguments can be passed to and from the functions (certainly you don’t want a colleague to
guess or to have to work this out from context!). The types of local variables are also declared. Type
conversions are explicit, never automatic.4
In summary, packages are more tedious to write than input files. When writing input files, you
can casually go ahead, giving some facts now, leaving others for later. Writing packages requires
forethought, care and discipline.
51 (1)
PositiveInteger
setImagSteps 51
51 (2)
PositiveInteger
7.0 (4)
DoubleFloat
Complex Function
X Y
11.7 Parameters
The power of packages becomes evident when packages have parameters. Usually these parameters are
domains and the exported operations have types involving these parameters.
In Chapter 2, you learned that categories denote classes of domains. Although we cover this notion in
detail in the next chapter, we now give you a sneak preview of its usefulness.
In Section 6.15 on page 172, we defined functions bubbleSort(m) and insertionSort(m) to sort a
list of integers. If you look at the code for these functions, you see that they may be used to sort any
structure m with the right properties. Also, the functions can be used to sort lists of any elements—not
just integers. Let us now recall the code for bubbleSort.
bubbleSort(m) ==
n := #m
for i in 1..(n-1) repeat
for j in n..(i+1) by -1 repeat
if m.j < m.(j-1) then swap!(m,j,j-1)
m
What properties of “lists of integers” are assumed by the sorting algorithm? In the first line, the
operation # computes the maximum index of the list. The first obvious property is that m must have
a finite number of elements. In FriCAS, this is done by your telling FriCAS that m has the category
finiteAggregate. As we show later in Section 12.9 on page 667, by using category tests programs can
query domains as to the presence or absence of property (attribute) represented by a category.
11.7. PARAMETERS 655
The operation swap! swaps elements of m. Using Browse, you find that swap! requires its elements to
come from a domain of category IndexedAggregate which also has category shallowlyMutable.
This category means that you can change the internal components of m without changing its external
structure. Shallowly-mutable data structures include lists, streams, one- and two-dimensional arrays,
vectors, and matrices.
The category IndexedAggregate designates the class of aggregates whose elements can be accessed
by the notation m(s) for suitable selectors s. The category IndexedAggregate takes two arguments:
Index, a domain of selectors for the aggregate, and Entry, a domain of entries for the aggregate.
Since the sort functions access elements by integers, we must choose Index = Integer. The most
general class of domains for which bubbleSort and insertionSort are defined are those of cate-
gory IndexedAggregate(Integer,Entry) with the two additional categories shallowlyMutable
and finiteAggregate.
Using Browse, you can also discover that FriCAS has many kinds of domains of category shallowly-
Mutable. Those of class IndexedAggregate(Integer,Entry) include Bits, FlexibleArray, One-
DimensionalArray, List, String, and Vector, and also HashTable and EqTable with integer
keys. Although you may never want to sort all such structures, we nonetheless demonstrate FriCAS’s
ability to do so.
Another requirement is that Entry has an operation <. One way to get this operation is to assume
that Entry has category OrderedSet. By definition, will then export a < operation. A more general
approach is to allow any comparison function f to be used for sorting. This function will be passed as
an argument to the sorting functions.
Our sorting package then takes two arguments: a domain S of objects of any type, and a domain A, an
aggregate of type IndexedAggregate(Integer, S) with the above two additional categories. Here
is its definition using what are close to the original definitions of bubbleSort and insertionSort for
sorting lists of integers. The symbol “!” is added to the ends of the operation names. This uniform
naming convention is used for FriCAS operation names that destructively change one or more of their
arguments.
1 SortPackage (S , A ) : Exports == I mplement ation where
2 S : Object
3 A : I n d e x ed Ag g r e g a t e ( Integer , S )
4 with ( fin it e Ag gr eg a te ; sh a l l o w l y M u t a b l e )
5
6 Exports == with
7 bubbleSort !: (A ,( S , S ) -> Boolean ) -> A
8 insertionSort !: (A , (S , S ) -> Boolean ) -> A
9
10 Imple mentati on == add
11 bubbleSort !( m , f ) ==
12 n := # m
13 for i in 1..( n -1) repeat
14 for j in n ..( i +1) by -1 repeat
15 if f ( m .j , m .( j -1)) then swap !( m ,j ,j -1)
16 m
17 insertionSort !( m , f ) ==
18 for i in 2..# m repeat
19 j := i
20 while j > 1 and f ( m .j , m .( j -1)) repeat
21 swap !( m ,j ,j -1)
22 j := ( j - 1) pretend Po s it iv eI n te ge r
23 m
656 CHAPTER 11. PACKAGES
11.8 Conditionals
When packages have parameters, you can say that an operation is or is not exported depending on
the values of those parameters. When the domain of objects S has an < operation, we can supply
one-argument versions of bubbleSort and insertionSort which use this operation for sorting. The
presence of the operation < is guaranteed when S is an ordered set.
1 Exports == with
2 bubbleSort !: (A ,( S , S ) -> Boolean ) -> A
3 insertionSort !: (A , (S , S ) -> Boolean ) -> A
4
5 if S has OrderedSet then
6 bubbleSort !: A -> A
7 insertionSort !: A -> A
In addition to exporting the one-argument sort operations conditionally, we must provide conditional
definitions for the operations in the Implementation part. This is easy: just have the one-argument
functions call the corresponding two-argument functions with the operation < from S.
1 Imple mentati on == add
2 ...
3 if S has OrderedSet then
4 bubbleSort !( m ) == bubbleSort !( m , < $ S )
5 insertionSort !( m ) == insertionSort !( m , < $ S )
In Section 6.15 on page 172, we give an alternative definition of bubbleSort using first and rest that
is more efficient for a list (for which access to any element requires traversing the list from its first
node). To implement a more efficient algorithm for lists, we need the operation setelt! which allows us
to destructively change the first and rest of a list. Using Browse, you find that these operations come
from category UnaryRecursiveAggregate. Several aggregate types are unary recursive aggregates
including those of List and AssociationList. We provide two different implementations for bubbleSort!
and insertionSort!: one for list-like structures, another for array-like structures.
1 Impl ementati on == add
2 ...
3 if A has U n a r y R e c u r s i v e A g g r e g a t e ( S ) then
4 bubbleSort !( m , fn ) ==
5 empty ? m = > m
6 l := m
7 while not empty ? ( r := l . rest ) repeat
8 r := bubbleSort ! r
9 x := l . first
10 if fn ( r . first , x ) then
11 l . first := r . first
12 r . first := x
13 l . rest := r
14 l := l . rest
15 m
16 insertionSort !( m , fn ) ==
17 ...
The ordering of definitions is important. The standard definitions come first and then the predicate
A has UnaryRecursiveAggregate(S)
11.9 Testing
Once you have written the package, embed it in a file, for example, sortpak.spad. Be sure to include
an )abbrev command at the top of the file:
Now compile the file (using )compile sortpak.spad). Expose the constructor. You are then ready
to begin testing.
) expose SORTPAK
SortPackage is now explicitly exposed in frame initial
Define a list.
l := [1 ,7 ,4 ,2 ,11 , -7 ,3 ,2]
List ( Integer )
Since the integers are an ordered set, a one-argument operation will do.
bubbleSort !( l )
List ( Integer )
List ( Integer )
List ( Integer )
String
true (6)
Boolean
Good! Create a bit string representing ten consecutive boolean values true.
u : Bits := new (10 , true )
"1111111111" (7)
Bits
"1100011111" (8)
Bits
"0001111111" (9)
Bits
Create an “eq-table” (see ‘EqTable’ on page 397), a table having integers as keys and strings as values.
t : EqTable ( Integer , String ) := table ()
table () (10)
EqTable(Integer , String )
"robert" (11)
String
And a second.
t .2 := " richard "
11.10. HOW PACKAGES WORK 659
"richard" (12)
String
EqTable(Integer , String )
EqTable(Integer , String )
What happens if you ask for bubbleSort!([1,-5,3])? There is a unique modemap for an operation
named bubbleSort! with one argument. Since [1,-5,3] is a list of integers, the symbolic domain D1 is
defined as List(Integer). For some operation to apply, it must satisfy the predicate for some D2. What
D2? The third expression of the and requires D1 has IndexedAggregate(Integer, D2) with two
additional categories. So the interpreter searches for an IndexedAggregate among the ancestors of
List (Integer) (see Section 12.4 on page 664). It finds one: IndexedAggregate(Integer, Integer).
The interpreter tries defining D2 as Integer. After substituting for D1 and D2, the predicate evaluates
to true. An applicable operation has been found!
Now FriCAS builds the package SortPackage(List(Integer), Integer). According to its definition,
this package exports the required operation: bubbleSort!: List Integer→List Integer. The interpreter
660 CHAPTER 11. PACKAGES
then asks the package for a function implementing this operation. The package gets all the functions
it needs (for example, rest and swap!) from the appropriate domains and then it returns a bubbleSort!
to the interpreter together with the local environment for bubbleSort!. The interpreter applies the
function to the argument [1,-5,3]. The bubbleSort! function is executed in its local environment and
produces the result.
Chapter 12
Categories
This chapter unravels the mysteries of categories—what they are, how they are related to domains
and packages, how they are defined in FriCAS, and how you can extend the system to include new
categories of your own.
We assume that you have read the introductory material on domains and categories in Section 2.1.1
on page 66. There you learned that the notion of packages covered in the previous chapter are special
cases of domains. While this is in fact the case, it is useful here to regard domains as distinct from
packages.
Think of a domain as a datatype, a collection of objects (the objects of the domain). From your “sneak
preview” in the previous chapter, you might conclude that categories are simply named clusters of op-
erations exported by domains. As it turns out, categories have a much deeper meaning. Categories are
fundamental to the design of FriCAS. They control the interactions between domains and algorithmic
packages, and, in fact, between all the components of FriCAS.
Categories form hierarchies as shown on the inside cover pages of this book. The inside front-cover
pages illustrate the basic algebraic hierarchy of the FriCAS programming language. The inside back-
cover pages show the hierarchy for data structures.
Think of the category structures of FriCAS as a foundation for a city on which superstructures (do-
mains) are built. The algebraic hierarchy, for example, serves as a foundation for constructive mathe-
matical algorithms embedded in the domains of FriCAS. Once in place, domains can be constructed,
either independently or from one another.
Superstructures are built for quality—domains are compiled into machine code for run-time efficiency.
You can extend the foundation in directions beyond the space directly beneath the superstructures,
then extend selected superstructures to cover the space. Because of the compilation strategy, changing
components of the foundation generally means that the existing superstructures (domains) built on
the changed parts of the foundation (categories) have to be rebuilt—that is, recompiled.
Before delving into some of the interesting facts about categories, let’s see how you define them in
FriCAS.
661
662 CHAPTER 12. CATEGORIES
12.1 Definitions
A category is defined by a function with exactly the same format as any other function in FriCAS.
The first example of a category definition is SetCategory, the most basic of the algebraic categories
in FriCAS.
1 SetCategory (): Category ==
2 Join ( Type , CoercibleTo OutputForm ) with
3 "=" : (% , %) -> Boolean
The definition starts off with the name of the category (SetCategory); this is always in column one
in the source file. All parts of a category definition are then indented with respect to this first line.
In Chapter 2, we talked about Ring as denoting the class of all domains that are rings, in short,
the class of all rings. While this is the usual naming convention in FriCAS, it is also common to
use the word “Category” at the end of a category name for clarity. The interpretation of the name
SetCategory is, then, “the category of all domains that are (mathematical) sets.”
The name SetCategory is followed in the definition by its formal parameters enclosed in parentheses
“()”. Here there are no parameters. As required, the type of the result of this category function is the
distinguished name Category.
Then comes the “==”. As usual, what appears to the right of the “==” is a definition, here, a category
definition. A category definition always has two parts separated by the reserved word with.
The first part tells what categories the category extends. Here, the category extends two categories:
Type, the category of all domains, and CoercibleTo(OutputForm). The operation Join is a
system-defined operation that forms a single category from two or more other categories.
Every category other than Type is an extension of some other category. If, for example, SetCategory
extended only the category Type, the definition here would read “Type with ...”. In fact, the Type
is optional in this line; “with ...” suffices.
12.2 Exports
To the right of the with is a list of all the exports of the category. Each exported operation has a name
and a type expressed by a declaration of the form “name: type”.
Categories can export symbols, as well as 0 and 1 which denote domain constants.1 In the current
implementation, all other exports are operations with types expressed as mappings with the syntax
source → target
1 The numbers 0 and 1 are operation names in FriCAS.
12.3. DOCUMENTATION 663
The category SetCategory has a single export: the operation = whose type is given by the mapping
(%, %) → Boolean. The “%” in a mapping type always means “the domain.” Thus the operation =
takes two arguments from the domain and returns a value of type Boolean.
The source part of the mapping here is given by a tuple consisting of two or more types separated
by commas and enclosed in parentheses. If an operation takes only one argument, you can drop the
parentheses around the source type. If the mapping has no arguments, the source part of the mapping
is either left blank or written as “()”. Here are examples of formats of various operations with some
contrived names.
someIntegerConstant : %
aZeroArgumentOperation: () -> Integer
aOneArgumentOperation: Integer -> %
aTwoArgumentOperation: (Integer,%) -> Void
aThreeArgumentOperation: (%,Integer,%) -> Fraction(%)
12.3 Documentation
The definition of SetCategory above is missing an important component: its library documentation.
Here is its definition, complete with documentation.
1 ++ Description :
2 ++ \ spadtype { SetCategory } is the basic category
3 ++ for describing a collection of elements with
4 ++ \ spadop {=} ( equality ) and a \ spadfun { coerce }
5 ++ to \ spadtype { OutputForm }.
6
7 SetCategory (): Category ==
8 Join ( Type , CoercibleTo OutputForm ) with
9 "=": (% , %) -> Boolean
10 ++ \ spad { x = y } tests if \ spad { x } and
11 ++ \ spad { y } are equal .
\spadtype{Polynomial(Integer)}
Similarly, mark an operator name with \spadop, a FriCAS operation (function) with \spadfun, and
a variable or FriCAS expression with \spad. Library documentation is given in a TEX-like language
so that it can be used both for hard-copy and for Browse. These different wrappings cause operations
and types to have mouse-active buttons in Browse. For hard-copy output, wrapped expressions appear
in a different font. The above documentation appears in hard-copy as:
SetCategory is the basic category for describing a collection of elements with = (equal-
ity) and a coerce to OutputForm.
2 Other information such as the author’s name, date of creation, and so on, can go in this area as well but are currently
ignored by FriCAS.
664 CHAPTER 12. CATEGORIES
and
For our purposes in this chapter, we omit the documentation from further category descriptions.
12.4 Hierarchies
A second example of a category is SemiGroup, defined by:
1 SemiGroup (): Category == SetCategory with
2 "*": (% ,%) -> %
3 "^": (% , P os it i ve In te g er ) -> %
This definition is as simple as that for SetCategory, except that there are two exported operations.
Multiple exported operations are written as a pile, that is, they all begin in the same column. Here
you see that the category mentions another type, PositiveInteger, in a signature. Any domain can
be used in a signature.
Since categories extend one another, they form hierarchies. Each category other than Type has one
or more parents given by the one or more categories mentioned before the with part of the defini-
tion. SemiGroup extends SetCategory and SetCategory extends both Type and CoercibleTo
(OutputForm). Since CoercibleTo (OutputForm) also extends Type, the mention of Type in
the definition is unnecessary but included for emphasis.
12.5 Membership
We say a category designates a class of domains. What class of domains? That is, how does FriCAS
know what domains belong to what categories? The simple answer to this basic question is key to the
design of FriCAS:
When a domain is defined, it is asserted to belong to one or more categories. Suppose, for example, that
an author of domain String wishes to use the binary operator * to denote concatenation. Thus "hello
" * "there" would produce the string "hello there"3 . The author of String could then assert that
String is a member of SemiGroup. According to our definition of SemiGroup, strings would then
also have the operation ^ defined automatically. Then "--" ^ 4 would produce a string of eight dashes
"--------". Since String is a member of SemiGroup, it also is a member of SetCategory and
thus has an operation = for testing that two strings are equal.
Now turn to the algebraic category hierarchy inside the front cover of this book. Any domain that is a
member of a category extending SemiGroup is a member of SemiGroup (that is, it is a semigroup).
In particular, any domain asserted to be a Ring is a semigroup since Ring extends Monoid, that, in
3 Actually, concatenation of strings in FriCAS is done by juxtaposition or by using the operation concat. The expression
turn, extends SemiGroup. The definition of Integer in FriCAS asserts that Integer is a member of
category IntegerNumberSystem, that, in turn, asserts that it is a member of EuclideanDomain.
Now EuclideanDomain extends PrincipalIdealDomain and so on. If you trace up the hierarchy,
you see that EuclideanDomain extends Ring, and, therefore, SemiGroup. Thus Integer is a
semigroup and also exports the operations * and ^.
12.6 Defaults
We actually omitted the last part of the definition of SemiGroup in Section 12.4 on page 664. Here
now is its complete FriCAS definition.
1 SemiGroup (): Category == SetCategory with
2 "*": (% , %) -> %
3 "^": (% , P os it i ve In te g er ) -> %
4 add
5 import R e p e a t e dS q u a r i n g (%)
6 x : % ^ n : Po s it iv eI n te ge r == expt (x , n )
The add part at the end is used to give “default definitions” for exported operations. Once you have a
multiplication operation *, you can define exponentiation for positive integer exponents using repeated
multiplication:
xn = x
| x x{z· · · x}
n times
This definition for ^ is called a default definition. In general, a category can give default definitions for
any operation it exports. Since SemiGroup and all its category descendants in the hierarchy export
^, any descendant category may redefine ^ as well.
A domain of category SemiGroup (such as Integer) may or may not choose to define its own ^
operation. If it does not, a default definition that is closest (in a “tree-distance” sense of the hierarchy)
to the domain is chosen.
The part of the category definition following an “add” operation is a capsule, as discussed in the
previous chapter. The line
import RepeatedSquaring(%)
references the package RepeatedSquaring(%), that is, the package RepeatedSquaring that takes
“this domain” as its parameter. For example, if the semigroup Polynomial (Integer) does not define
its own exponentiation operation, the definition used may come from the package RepeatedSquaring
(Polynomial (Integer)). The next line gives the definition in terms of expt from that package.
The default definitions are collected to form a “default package” for the category. The name of the
package is the same as the category but with an ampersand (“&”) added at the end. A default
package always takes an additional argument relative to the category. Here is the definition of the
default package SemiGroup& as automatically generated by FriCAS from the above definition of
SemiGroup.
1 SemiGroup_ &(%): Exports == Im plementa tion where
2 %: SemiGroup
3 Exports == with
4 "^": (% , P os it i ve In te g er ) -> %
5 Imple mentati on == add
666 CHAPTER 12. CATEGORIES
6 import R e p e a t ed S q u a r i n g (%)
7 x :% ^ n : Po si t iv eI nt e ge r == expt (x , n )
12.7 Axioms
In the previous section you saw the complete FriCAS program defining SemiGroup. According to
this definition, semigroups (that is, are sets with the operations * and ^.
You might ask: “Aside from the notion of default packages, isn’t a category just a macro, that is, a
shorthand equivalent to the two operations * and ^ with their types?” If a category were a macro,
every time you saw the word SemiGroup, you would rewrite it by its list of exported operations.
Furthermore, every time you saw the exported operations of SemiGroup among the exports of a
constructor, you could conclude that the constructor exported SemiGroup.
A category is not a macro and here is why. The definition for SemiGroup has documentation that
states:
Category SemiGroup denotes the class of all multiplicative semigroups, that is, a set
with an associative operation *.
Axioms:
associative("*" : (%,%)→%) (x*y)*z = x*(y*z)
According to the author’s remarks, the mere exporting of an operation named * and ^ is not enough
to qualify the domain as a SemiGroup. In fact, a domain can be a semigroup only if it explicitly
exports a ^ and a * satisfying the associativity axiom.
In general, a category name implies a set of axioms, even mathematical theorems. There are numerous
axioms from Ring, for example, that are well-understood from the literature. No attempt is made to
list them all. Nonetheless, all such mathematical facts are implicit by the use of the name Ring.
12.8 Correctness
While such statements are only comments, FriCAS can enforce their intention simply by shifting the
burden of responsibility onto the author of a domain. A domain belongs to category Ring only if the
author asserts that the domain belongs to Ring or to a category that extends Ring.
This principle of assertion is important for large user-extendable systems. FriCAS has a large library
of operations offering facilities in many areas. Names such as norm and product, for example, have
diverse meanings in diverse contexts. An inescapable hindrance to users would be to force those who
wish to extend FriCAS to always invent new names for operations. FriCAS allows you to reuse names,
and then use context to disambiguate one from another.
Here is another example of why this is important. Some languages, such as APL, denote the Boolean
constants true and false by the integers 1 and 0. You may want to let infix operators + and * serve
as the logical operators or and and, respectively. But note this: Boolean is not a ring. The inverse
axiom for Ring states:
Boolean is not a ring since true has no inverse—there is no inverse element a such that 1 + a = 0 (in
terms of booleans, (true or a)= false). Nonetheless, FriCAS could easily and correctly implement
Boolean this way. Boolean simply would not assert that it is of category Ring. Thus the + for
Boolean values is not confused with the one for Ring. Since the Polynomial constructor requires its
argument to be a ring, FriCAS would then refuse to build the domain Polynomial(Boolean). Also,
FriCAS would refuse to wrongfully apply algorithms to Boolean elements that presume that the ring
axioms for + hold.
true (1)
Boolean
false (2)
Boolean
Using categories to assert axioms and category conditions to test if axioms are satisfied, we can con-
ditionally export and define operations for a domain depending on axioms (see Section 13.3 on page
673). Of course categories can also be asserted in a category definition.
After mentioning category Ring many times in this book, it is high time that we show you its definition:
As you can see Ring just combines properties of other categories. So let us see NonAssociativeRing:
1 N o n A s s o c i a t i v e R i n g () : Category == Join ( NonAssociativeRng ,
2 N o n A s s o c i a t i v e S e m i R i n g ) with
3 --operations
4 characterist ic : -> N o n N e g a t i v e I n t e g e r
668 CHAPTER 12. CATEGORIES
There is one new thing here. Look at the “$%” on the last line. This is not a typographic error! The
“$” says that the 1 is to come from some domain. The “%” says that the domain is “this domain.” If
“%” is Fraction(Integer), this line reads coerce(n)== n * 1$Fraction(Integer).
Let us comment on category unitsKnown appearing in definition of Ring above. The category
unitsKnown asserts a rather subtle mathematical fact that is normally taken for granted when working
with rings.4 Because programs can test for this category, FriCAS can correctly handle rather more
complicated mathematical structures (ones that are similar to rings but do not have this category).
12.10 Parameters
Like domain constructors, category constructors can also have parameters. For example, category
MatrixCategory is a parameterized category for defining matrices over a ring R so that the matrix
domains can have different representations and indexing schemes. Its definition has the form:
1 Matr ixCatego ry (R , Row , Col ): Category ==
2 T w o D i m e n s i o n a l A r r a y C a t e g o r y (R , Row , Col ) with ...
The category extends TwoDimensionalArrayCategory with the same arguments. You cannot find
TwoDimensionalArrayCategory in the algebraic hierarchy listing. Rather, it is a member of the
data structure hierarchy, given inside the back cover of this book. In particular, TwoDimension-
alArrayCategory is an extension of HomogeneousAggregate since its elements are all one type.
The domain Matrix(R), the class of matrices with coefficients from domain R, asserts that it is a
member of category MatrixCategory(R, Vector(R), Vector(R)). The parameters of a category
must also have types. The first parameter to MatrixCategory R is required to be a ring. The second
and third are required to be domains of category FiniteLinearAggregate(R).5 In practice, examples
of categories having parameters other than domains are rare.
Adding the declarations for parameters to the definition for MatrixCategory, we have:
1 R : Ring
2 ( Row , Col ): F i n i t e L i n e a r A g g r e g a t e ( R )
3
4 Matr ixCatego ry (R , Row , Col ): Category ==
5 T w o D i m e n s i o n a l A r r a y C a t e g o r y (R , Row , Col ) with ...
4 With this axiom, the units of a domain are the set of elements x that each have a multiplicative inverse y in the
domain. Thus 1 and -1 are units in domain Integer. Also, for Fraction Integer, the domain of rational numbers, all
non-zero elements are units.
5 This is another extension of HomogeneousAggregate that you can see in the data structure hierarchy.
12.11. CONDITIONALS 669
12.11 Conditionals
As categories have parameters, the actual operations exported by a category can depend on these pa-
rameters. As an example, the operation determinant from category MatrixCategory is only exported
when the underlying domain R has commutative multiplication:
Conditionals can also define conditional extensions of a category. Here is a portion of the definition of
QuotientFieldCategory:
1 Q u o t i e n t F i e l d C a t e g o r y ( R ) : Category == ... with ...
2 if R has OrderedSet then OrderedSet
3 if R has I n t e g e r N u m b e r S y s t e m then
4 ceiling : % -> R
5 ...
Here the predicate used is identical to the predicate in the Exports part. This need not be the case.
See Section 11.8 on page 656 for a more complicated example.
There is no reason, however, to give this list of exports a name since no other domain or package
exports it. In fact, it is rare for a package to export a named category. As you will see in the next
chapter, however, it is very common for the definition of domains to mention one or more category
before the with.
Chapter 13
Domains
We finally come to the domain constructor. A few subtle differences between packages and domains
turn up some interesting issues. We first discuss these differences then describe the resulting issues
by illustrating a program for the QuadraticForm constructor. After a short example of an algebraic
constructor, CliffordAlgebra, we show how you use domain constructors to build a database query
facility.
13.2 Definitions
The syntax for defining a domain constructor is the same as for any function in FriCAS:
As this definition usually extends over many lines, a where expression is generally used instead.
671
672 CHAPTER 13. DOMAINS
A complete domain constructor definition for QuadraticForm is shown in Figure 13.1. Interestingly,
this little domain illustrates all the new concepts you need to learn.
A domain constructor can take any number and type of parameters. QuadraticForm takes a positive
integer n and a field K as arguments. Like a package, a domain has a set of explicit exports and an
implementation described by a capsule. Domain constructors are documented in the same way as
package constructors.
Domain QuadraticForm(n, K), for a given positive integer n and domain K, explicitly exports three
operations:
Compared with the corresponding syntax given for the definition of a package, you see that a do-
main constructor has three optional parts to its definition: Category Assertions, Add Domain, and
Representation.
UnivariatePolynomialCategory(R) with
if R has Finite then Finite
...
Join(ExtensibleLinearAggregate(S),
OneDimensionalArrayAggregate(S)) with...
13.4 A Demo
Before looking at the Implementation part of QuadraticForm, let’s try some examples.
Type
1
−1 2
1 (2)
2
1
Matrix(Fraction ( Integer ))
Construct the quadratic form. A package call $QF is necessary since there are other QuadraticForm
domains.
q : QF := quadraticForm ( A )
1
−1 2
1 (3)
2
1
Looks like a matrix. Try computing the number of rows. FriCAS won’t let you.
nrows q
There are 2 exposed and 2 unexposed library operations named nrows having 1
argument ( s ) but none was determined to be applicable . Use HyperDoc Browse ,
or issue
) display op nrows
to learn more about the available operations . Perhaps package - calling the
operation or using coercions on the arguments will allow you to apply the
operation .
Cannot find a definition or applicable library operation named nrows with
argument type ( s )
QuadraticForm (2 , Fraction ( Integer ))
Perhaps you should use " @ " to indicate the required return type , or " $ " to
specify which version of the function you need .
Create a direct product element v. A package call is again necessary, but FriCAS understands your
list as denoting a vector.
v := directProduct ([2 , -1]) $ Dire ctProduc t (2 , Fraction Integer )
−5 (5)
13.5. BROWSE 675
Fraction ( Integer )
3
−3 2
3 (6)
2
3
13.5 Browse
The Browse facility of HyperDoc is useful for investigating the properties of domains, packages, and
categories. From the main HyperDoc menu, move your mouse to Browse and click on the left mouse
button. This brings up the Browse first page. Now, with your mouse pointer somewhere in this
window, enter the string “quadraticform” into the input area (all lower case letters will do). Move
your mouse to Constructors and click. Up comes a page describing QuadraticForm that includes
a part labeled by “Description:”. You also see the types for arguments n and K displayed as well as
the fact that QuadraticForm returns an AbelianGroup.
Select Operations to get a list of operations for QuadraticForm. You can select an operation by
clicking on it to get an individual page with information about that operation. Or you can select the
buttons along the bottom to see alternative views or get additional information on the operations.
Eventually, use to return to the first page on QuadraticForm.
You can go and experiment a bit by selecting Field and n with your mouse. Going back to Operations
you will see that Implementations view now works (it is disabled if some domain parameter is
unspecified). Then return to the page on QuadraticForm.
At the bottom the QuadraticForm page has buttons for Parents, Ancestors, and others. Clicking
on Parents, you see that QuadraticForm has AbelianGroup and ConvertibleTo as parents (note
that QuadraticForm distributed with FriCAS is richer then the demo version presented before).
13.6 Representation
The Implementation part of an FriCAS capsule for a domain constructor uses the special variable
Rep to identify the lower level data type used to represent the objects of the domain. The Rep for
quadratic forms is SquareMatrix(n, K). This means that all objects of the domain are required to
be n by n matrices with elements from K.
The code for quadraticForm in Figure 13.1 on page 672 checks that the matrix is symmetric and then
converts it to “%”, which means, as usual, “this domain.” Such explicit conversions are generally
required by the compiler. Aside from checking that the matrix is symmetric, the code for this function
essentially does nothing. The m :: % on line 28 coerces m to a quadratic form. In fact, the quadratic
form you created in step (3) of Section 13.4 on page 673 is just the matrix you passed it in disguise!
Without seeing this definition, you would not know that. Nor can you take advantage of this fact now
that you do know! When we try in the next step of Section 13.4 on page 673 to regard q as a matrix by
676 CHAPTER 13. DOMAINS
asking for nrows, the number of its rows, FriCAS gives you an error message saying, in effect, “Good
try, but this won’t work!”
The definition for the matrix function could hardly be simpler: it just returns its argument after
explicitly coercing its argument to a matrix. Since the argument is already a matrix, this coercion does
no computation.
Within the context of a capsule, an object of “%” is regarded both as a quadratic form and as a matrix.1
This makes the definition of q.v easy—it just calls the dot product from DirectProduct to perform
the indicated operation.
if you want the one from “Rep”, you must package call it using a “$Rep” suffix.
2 You can make that representation a Union type, however. See Section 2.5 on page 79 for examples of unions.
13.9. DEFAULTS 677
the value of 3*q-q+q. Where do the operations *, +, and - come from? There is no definition for them
in the capsule!
The Implementation part of a definition can optionally specify an “add-domain” to the left of an
add (for QuadraticForm, defines SquareMatrix(n,K) is the add-domain). The meaning of an
add-domain is simply this: if the capsule part of the Implementation does not supply a function
for an operation, FriCAS goes to the add-domain to find the function. So do *, + and - come from
SquareMatrix(n,K)?
13.9 Defaults
In Chapter 11, we saw that categories can provide default implementations for their operations. How
and when are they used? When FriCAS finds that QuadraticForm(2, Fraction Integer) does not
implement the operations *, +, and -, it goes to SquareMatrix(2,Fraction Integer) to find it. As
it turns out, SquareMatrix(2, Fraction Integer) does not implement any of these operations!
What does FriCAS do then? Here is its overall strategy. First, FriCAS looks for a function in the
capsule for the domain. If it is not there, FriCAS looks in the add-domain for the operation. If that fails,
FriCAS searches the add-domain of the add-domain, and so on. If all those fail, it then searches the
default packages for the categories of which the domain is a member. In the case of QuadraticForm,
it searches AbelianGroup, then its parents, grandparents, and so on. If this fails, it then searches
the default packages of the add-domain. Whenever a function is found, the search stops immediately
and the function is returned. When all fails, the system calls error to report this unfortunate news to
you. To find out the actual order of constructors searched for QuadraticForm, consult Browse: from
the QuadraticForm, and click on Search Path.
Let’s apply this search strategy for our example 3*q-q+q. The scalar multiplication comes first. FriCAS
finds a default implementation in AbelianGroup&. Remember from Section 12.6 on page 665 that
SemiGroup provides a default definition for xn by repeated squaring? AbelianGroup similarly
provides a definition for n ∗ x by repeated doubling.
But the search of the defaults for QuadraticForm fails to find any + or * in the default packages
for the ancestors of QuadraticForm. So it now searches among those for SquareMatrix. Category
MatrixCategory, which provides a uniform interface for all matrix domains, is a grandparent of
SquareMatrix and has a capsule defining many functions for matrices, including matrix addition,
subtraction, and scalar multiplication. The default package MatrixCategory& is where the functions
for + and - come from.
You can use Browse to discover where the operations for QuadraticForm are implemented. First,
get the page describing QuadraticForm. With your mouse somewhere in this window, type a “2”,
press the Tab key, and then enter “Fraction Integer” to indicate that you want the domain Quad-
raticForm(2, Fraction Integer). Now click on Operations to get a table of operations and on *
to get a page describing the * operation. Finally, click on implementation at the bottom.
13.10 Origins
Aside from the notion of where an operation is implemented, a useful notion is the origin or “home”
of an operation. When an operation (such as quadraticForm) is explicitly exported by a domain (such
as QuadraticForm), you can say that the origin of that operation is that domain. If an operation is
678 CHAPTER 13. DOMAINS
not explicitly exported from a domain, it is inherited from, and has as origin, the (closest) category
that explicitly exports it. The operations + and - of QuadraticForm, for example, are inherited from
AbelianMonoid. As it turns out, AbelianMonoid is the origin of virtually every + operation in
FriCAS!
Again, you can use Browse to discover the origins of operations. From the Browse page on Quadrat-
icForm, click on Operations, then on origins at the bottom of the page.
The origin of the operation is the only place where on-line documentation is given. However, you
can re-export an operation to give it special documentation. Suppose you have just invented the
world’s fastest algorithm for inverting matrices using a particular internal representation for matrices.
If your matrix domain just declares that it exports MatrixCategory, it exports the inverse operation,
but the documentation the user gets from Browse is the standard one from MatrixCategory. To
give your version of inverse the attention it deserves, simply export the operation explicitly with new
documentation. This redundancy gives inverse a new origin and tells Browse to present your new
documentation.
The Exports part of this definition is missing and is taken to be equivalent to that of Fraction(Integer).
Because of the add-domain philosophy, you get precisely what you want. The effect is to create a little
stub of a domain. When a user asks to add two rational numbers, FriCAS would ask RationalNum-
ber for a function implementing this +. Since the domain has no capsule, the domain then immediately
sends its request to Fraction (Integer).
The short form definition for domains is used to define such domains as MultivariatePolynomial:
1 M u l t i v a r i a t e P o l y n o m i a l ( vl : List Symbol , R : Ring ) ==
2 S p a r s e M u l t i v a r i a t e P o l y n o m i a l (R ,
3 O r d e re d V a r i a b l e L i s t vl )
ei ei = Q(ei )
ei ej = −ej ei for i ̸= j
Now look at the snapshot of its definition given in Figure 13.2. Lines 9-10 show part of the definitions
of the Exports. A Clifford algebra over a field K is asserted to be a ring, an algebra over K, and a
vector space over K. Its explicit exports include e(n), which returns the nth unit element.
The Implementation part begins by defining a local variable Qeelist to hold the list of all q.v
where v runs over the unit vectors from 1 to the dimension n. Another local variable dim is set to 2n ,
computed once and for all. The representation for the domain is PrimitiveArray(K), which is a basic
array of elements from domain K. Line 18 defines New as shorthand for the more lengthy expression
new(dim, 0$K)$Rep, which computes a primitive array of length 2n filled with 0’s from domain K.
Lines 19-22 define the sum of two elements x and y straightforwardly. First, a new array of all 0
’s is created, then filled with the sum of the corresponding elements. Indexing for primitive arrays
starts at 0. The definition of the product of x and y first requires the definition of a local function
addMonomProd. FriCAS knows it is local since it is not an exported function. The types of all local
functions must be declared.
For a demonstration of CliffordAlgebra, see ‘CliffordAlgebra’ on page 367.
680 CHAPTER 13. DOMAINS
o‘determinant‘$->R‘1‘x‘d‘Matrix(R)‘has(R,commutative("*"))
Our task is to create a little query language that allows us to get useful information from this database.
First we design a simple language for accessing information from the database. We have the following
simple model in mind for its design. Think of the database as a box of index cards. There is only one
search operation—it takes the name of a field and a predicate (a boolean-valued function) defined on
the fields of the index cards. When applied, the search operation goes through the entire box selecting
only those index cards for which the predicate is true. The result of a search is a new box of index
cards. This process can be repeated again and again.
The predicates all have a particularly simple form: symbol = pattern, where symbol designates one of the
fields, and pattern is a “search string”—a string that may contain a “*” as a wildcard. Wildcards match
any substring, including the empty string. Thus the pattern "*ma*t" matches "mat", "doormat" and
"smart".
To illustrate how queries are given, we give you a sneak preview of the facility we are about to create.
Extract the database of all FriCAS operations.
ops := getDatabase (" o ")
8275 (1)
Database(IndexCard)
3 (2)
Database(IndexCard)
As usual, the arguments of elt (“.”) associate to the left. The first elt produces the set of all operations
with name map. The second elt produces the set of all map operations with three arguments. The third
elt produces the set of all three-argument map operations having a type mentioning Stream.
13.13. EXAMPLE 2: BUILDING A QUERY FACILITY 681
Another thing we’d like to do is to extract one field from each of the index cards in the box and look
at the result. Here is an example of that kind of request.
What constructors explicitly export a determinant operation?
elt ( elt ( elt ( elt ( ops , name =" determinant ") , origin ) , sort ) , unique )
DataList( String )
The first elt produces the set of all index cards with name determinant. The second elt extracts the
origin component from each index card. Each origin component is the name of a constructor which
directly exports the operation represented by the index card. Extracting a component from each index
card produces what we call a datalist. The third elt, sort, causes the datalist of origins to be sorted
in alphabetic order. The fourth, unique, causes duplicates to be removed.
Before giving you a more extensive demo of this facility, we now build the necessary domains and
packages to implement it.
We work from the top down. First, we define a database, our box of index cards, as an abstract
datatype. For sake of illustration and generality, we assume that an index card is some type S, and
that a database is a box of objects of type S. Here is the FriCAS program defining the Database
domain.
1 PI == > Po s it iv eI n te ge r
2 Database ( S ): Exports == Implem entation where
3 S : Object with
4 elt : (% , Symbol ) -> String
5 display : % -> Void
6 fullDisplay : % -> Void
7
8 Exports == with
9 elt : (% , QueryEquation ) -> % -- Select by an equation.
10 elt : (% , Symbol ) -> DataList String -- Select by a field name.
11 "+": (% ,%) -> % -- Combine two databases.
12 " -": (% ,%) -> % -- Subtract one from another.
13 display : % -> Void -- A brief database display.
14 fullDisplay : % -> Void -- A full database display.
15 fullDisplay : (% , PI , PI ) -> Void -- A selective display.
16 coerce : % -> OutputForm -- Display a database.
17 Imple mentati on == add
18 ...
The domain constructor takes a parameter S, which stands for the class of index cards. We describe an
index card later. Here think of an index card as a string which has the eight fields mentioned above.
First, we tell FriCAS what operations we are going to require from index cards. We need an elt to
extract the contents of a field (such as name and type) as a string. For example, c.name returns a
string that is the content of the name field on the index card c. We need to display an index card in
two ways: display shows only the name and type of an operation; fullDisplay displays all fields. The
display operations return no useful information and thus have return type Void.
682 CHAPTER 13. DOMAINS
Next, we tell FriCAS what operations the user can apply to the database. This part defines our
little query language. The most important operation is db . field = pattern which returns a new
database, consisting of all index cards of db such that the field part of the index card is matched by the
string pattern called pattern. The expression field = pattern is an object of type QueryEquation
(defined in the next section).
Another elt is needed to produce a DataList object. Operation + is to merge two databases together;
- is used to subtract away common entries in a second database from an initial database. There are
three display functions. The fullDisplay function has two versions: one that prints all the records, the
other that prints only a fixed number of records. A coerce to OutputForm creates a display object.
The Implementation part of Database is straightforward.
1 Imple mentati on == add
2 s : Symbol
3 Rep := List S
4 elt ( db , equation ) == ...
5 elt ( db , key ) == [ x . key for x in db ]:: DataList ( String )
6 display ( db ) == for x in db repeat display x
7 fullDisplay ( db ) == for x in db repeat fullDisplay x
8 fullDisplay ( db , n , m ) == for x in db for i in 1.. m
9 repeat
10 if i >= n then fullDisplay x
11 x + y == r e m o v e D u p l i c at e s ! merge (x , y )
12 x - y == m er g eD if fe r en ce ( copy ( x :: Rep ) ,
13 y :: Rep ) $ MergeThing ( S )
14 coerce ( db ): OutputForm == (# db ):: OutputForm
The database is represented by a list of elements of S (index cards). We leave the definition of the
first elt operation (on line 4) until the next section. The second elt collects all the strings with field
name key into a list. The display function and first fullDisplay function simply call the corresponding
functions from S. The second fullDisplay function provides an efficient way of printing out a portion
of a large list. The + is defined by using the existing merge operation defined on lists, then removing
duplicates from the result. The - operation requires writing a corresponding subtraction operation. A
package MergeThing (not shown) provides this.
The coerce function converts the database to an OutputForm by computing the number of index
cards. This is a good example of the independence of the representation of an FriCAS object from how
it presents itself to the user. We usually do not want to look at a database—but do care how many
“hits” we get for a given query. So we define the output representation of a database to be simply the
number of index cards our query finds.
The predicate for our search is given by an object of type QueryEquation. FriCAS does not have
such an object yet so we have to invent it.
1 QueryEquation (): Exports == I mplemen tation where
2 Exports == with
3 equation : ( Symbol , String ) -> %
4 variable : % -> Symbol
5 value : % -> String
6
7 Imple mentati on == add
8 Rep := Record ( var : Symbol , val : String )
9 equation (x , s ) == [x , s ]
13.13. EXAMPLE 2: BUILDING A QUERY FACILITY 683
10 variable q == q . var
11 value q == q . val
FriCAS converts an input expression of the form a = b to equation(a, b). Our equations always
have a symbol on the left and a string on the right. The Exports part thus specifies an operation
equation to create a query equation, and variable and value to select the left- and right-hand sides. The
Implementation part uses Record for a space-efficient representation of an equation.
Here is the missing definition for the elt function of Database in the last section:
1 elt ( db , eq ) ==
2 field := variable eq
3 value := value eq
4 [ x for x in db | matches ?( value , x . field )]
Recall that a database is represented by a list. Line 4 simply runs over that list collecting all elements
such that the pattern (that is, value) matches the selected field of the element.
13.13.4 DataLists
Type DataList is a new type invented to hold the result of selecting one field from each of the index
cards in the box. It is useful to make datalists extensions of lists—lists that have special elt operations
defined on them for sorting and removing duplicates.
1 DataList ( S : OrderedSet ) : Exports == Impleme ntation where
2 Exports == ListAggregate ( S ) with
3 elt : (% ," unique ") -> %
4 elt : (% ," sort ") -> %
5 elt : (% ," count ") -> N o n N e g a t i v e I n t e g e r
6 coerce : List S -> %
7
8 Imple mentati on == List ( S ) add
9 Rep := List S
10 elt (x ," unique ") == r e m o v e D u p l i c a t e s ( x )
11 elt (x ," sort ") == sort ( x )
12 elt (x ," count ") == # x
13 coerce ( x : List S ) == x :: %
The Exports part asserts that datalists belong to the category ListAggregate. Therefore, you can use
all the usual list operations on datalists, such as first, rest, and concat. In addition, datalists have four
explicit operations. Besides the three elt operations, there is a coerce operation that creates datalists
from lists.
The Implementation part needs only to define four functions. All the rest are obtained from List(S).
An index card comes from a file as one long string. We define functions that extract substrings from
the long string. Each field has a name that is passed as a second argument to elt.
1 IndexCard () == I mplement ation where
2 Exports == with
3 elt : (% , Symbol ) -> String
4 display : % -> Void
684 CHAPTER 13. DOMAINS
We leave the Implementation part to the reader. All operations involve straightforward string ma-
nipulations.
We must not forget one important operation: one that builds the database in the first place! We’ll
name it getDatabase and put it in a package. This function is implemented by calling the Common
LISP function getBrowseDatabase(s) to get appropriate information from Browse. This operation
takes a string indicating which lines you want from the database: "o" gives you all operation lines,
and "k", all constructor lines. Similarly, "c", "d", and "p" give you all category, domain and package
lines respectively.
1 O pe ra ti o ns Qu er y (): Exports == Imple mentatio n where
2 Exports == with
3 getDatabase : String -> Database ( IndexCard )
4
5 Imple mentati on == add
6 getDatabase ( s ) == g e t B r o w s e D a t a b a s e ( s ) $ Lisp
We do not bother creating a special name for databases of index cards. Database(IndexCard) will
do. Notice that we used the package OperationsQuery to create, in effect, a new kind of domain:
Database(IndexCard).
To create the database facility, you put all these constructors into one file.3 At the top of the file put
)abbrev commands, giving the constructor abbreviations you created.
1 ) abbrev domain ICARD IndexCard
2 ) abbrev domain QEQUAT QueryEquation
3 ) abbrev domain MTHING MergeThing
4 ) abbrev domain DLIST DataList
5 ) abbrev domain DBASE Database
6 ) abbrev package OPQUERY Op er at i on sQ ue r y
)compile alql
to do.
13.13. EXAMPLE 2: BUILDING A QUERY FACILITY 685
Our first set of queries give some statistics on constructors in the current FriCAS system.
How many constructors does FriCAS have?
ks := getDatabase " k "
1250 (1)
Database(IndexCard)
Break this down into the number of categories, domains, and packages.
[ ks .( kind = k ) for k in [" c " ," d " ," p "]]
List (Database(IndexCard))
DataList( String )
39 (4)
Database(IndexCard)
["ComplexDoubleFloatMatrix", "DenavitHartenbergMatrix",
"DirectProductMatrixModule", "DoubleFloatMatrix", "I16Matrix", "I32Matrix",
(5)
"I8Matrix", "IndexedMatrix", "LieSquareMatrix", "LinearMultivariateMatrixPencil",
"Matrix", "RectangularMatrix", "SparseEchelonMatrix", "SquareMatrix",
"ThreeDimensionalMatrix", "U16Matrix", "U32Matrix", "U8Matrix"]
DataList( String )
8275 (6)
Database(IndexCard)
List (Database(IndexCard))
The query language is helpful in getting information about a particular operation you might like to
apply. While this information can be obtained with Browse, the use of the query database gives you
data that you can manipulate in the workspace.
How many operations have “eigen” in the name?
eigens := o .( name ="* eigen *")
9 (8)
Database(IndexCard)
DataList( String )
DataList( String )
The operations + and - are useful for constructing small databases and combining them. However,
remember that the only matching you can do is string matching. Thus a pattern such as "*Matrix*"
on the type field matches any type containing Matrix, MatrixCategory, SquareMatrix, and so
on.
How many operations mention “Matrix” in their type?
tm := o .( type ="* Matrix *")
383 (11)
13.13. EXAMPLE 2: BUILDING A QUERY FACILITY 687
Database(IndexCard)
How many operations come from constructors with “Matrix” in their name?
fm := o .( origin ="* Matrix *")
321 (12)
Database(IndexCard)
272 (13)
Database(IndexCard)
Display the first 5 operations that both mention “Matrix” in their type and come from a constructor
having “Matrix” in their name.
fullDisplay ( fm -% , 1 , 5)
^ : ( Matrix ( R ) , N o n N e g a t i v e I n t e g e r ) - > Matrix ( R )
from S t o r a g e E f f i c i e n t M a t r i x O p e r a t i o n s ( R ) ( unexposed )
- : (% ,%) - >% from Ma trixCat egory (R , Row , Col ) if has (R , AbelianGroup )
* : (% ,%) - >% from Matr ixCatego ry (R , Row , Col ) if has (R , SemiRng )
+ : (% ,%) - >% from Matr ixCatego ry (R , Row , Col )
* : (% , Col ) - > Col from Matri xCategor y (R , Row , Col ) if has (R , SemiRng )
639 (15)
Database(IndexCard)
Display 4 of them.
fullDisplay (m , 202 , 205)
elRow2 ! : (M ,R , Integer , Integer ) - > M from M a t r i x L i n e a r A l g e b r a F u n c t i o n s (R , Row , Col , M )
elt : (% , Integer , C ) - > D from S p a r s e E c h e l o n M a t r i x (C , D ) ( unexposed )
elt : (% , NonNegativeInteger , N o n N e g a t i v e I n t e g e r ) - > List ( R )
from L i n e a r M u l t i v a r i a t e M a t r i x P e n c i l ( R ) ( unexposed )
elt : (% , Integer , Integer ) - > R from R e c t a n g u l a r M a t r i x C a t e g o r y (m ,n ,R , Row , Col )
355 (17)
PositiveInteger
688 CHAPTER 13. DOMAINS
Chapter 14
Browse
This chapter discusses the Browse component of HyperDoc. We suggest you invoke FriCAS and work
through this chapter, section by section, following our examples to gain some familiarity with Browse.
To use this page, you first enter a search string into the input area at the top, then click on one of the
buttons below. We show the use of each of the buttons by example.
689
690 CHAPTER 14. BROWSE
Constructors
First enter the search string Matrix into the input area and click on Constructors. What you get
is the constructor page for Matrix. We show and describe this page in detail in Section 14.2 on page
693. By convention, FriCAS does a case-insensitive search for a match. Thus matrix is just as good as
Matrix, has the same effect as MaTrix, and so on. We recommend that you generally use small letters
for names however. A search string with only capital letters has a special meaning (see Section 14.3.3
on page 706).
All constructors containing the string are listed, whether exposed or unexposed. You can hide the
names of the unexposed constructors by clicking on the *=unexposed button in the Views panel at
the bottom of the window. (The button will change to exposed only.)
One of the names in this table is Matrix. Click on Matrix. What you get is again the constructor
page for Matrix. As you see, Browse gives you a large network of information in which there are many
ways to reach the same pages.
Again click on the to return to the table of constructors whose names contain matrix. Below the
table is a Views panel. This panel contains buttons that let you view constructors in different ways.
To learn about views of constructors, skip to Section 14.2.2 on page 700.
Operations
Enter *matrix into the input area and click on Operations. This time you get a table of operations
whose names end with matrix or Matrix.
If you select an operation name, you go to a page describing all the operations in FriCAS of that name.
At the bottom of an operation page is another kind of Views panel, one for operation pages. To learn
more about these views, skip to Section 14.3.2 on page 703.
General
This button does a general search for all constructor and operation names matching the search string.
Enter the search string *matrix* into the input area. Click on General to find all constructs that
have matrix as a part of their name.
The summary gives you all the names under a heading when the number of entries is less than 10.
Documentation
Again enter the search key *matrix* and this time click on Documentation. This search matches
any constructor and operation name whose documentation contains a substring matching matrix.
Complete
There is also a brief description of constructor Matrix and its abbreviation MATRIX.
If you have access to the source code of FriCAS, this header part also gives you the name of the source
file containing the definition of Matrix. Click on it to pop up an editor window containing the source
code of Matrix.
We recommend that you leave the editor window up while working through this chapter as you occa-
sionally may want to refer to it.
696 CHAPTER 14. BROWSE
Operations
Click here to get a table of operations exported by Matrix. You may wish to widen the window to
have multiple columns as below.
If you click on an operation name, you bring up a description page for the operations. For a detailed
description of these pages, skip to Section 14.3.2 on page 703.
Examples
Click here to get an examples page with examples of operations to create and manipulate matrices.
Read through this section. Try selecting the various buttons. Notice that if you click on an operation
name, such as new, you bring up a description page for that operation from Matrix.
Example pages have several examples of FriCAS commands. Each example has an active button to its
left. Click on it! A pre-computed answer is pasted into the page immediately following the command.
If you click on the button a second time, the answer disappears. This button thus acts as a toggle:
“now you see it; now you don’t.”
Note also that the FriCAS commands themselves are active. If you want to see FriCAS execute the
command, then click on it! A new FriCAS window appears on your screen and the command is
executed.
14.2. THE CONSTRUCTOR PAGE 697
Exports
Click here to see a page describing the exports of Matrix exactly as described by the source code.
As you see, Matrix declares that it exports all the operations and categories exported by category
MatrixCategory(R, Row, Col). In addition, two operations, diagonalMatrix and invertIfCan, are
explicitly exported.
To learn a little about the structure of FriCAS, we suggest you do the following exercise. Otherwise, go
on to the next section. Matrix explicitly exports only two operations. The other operations are thus
exports of MatrixCategory. In general, operations are usually not explicitly exported by a domain.
Typically they are inherited from several different categories. Let’s find out from where the operations
of Matrix come.
1. Click on MatrixCategory, then on Exports. Here you see that MatrixCategory explicitly
exports many matrix operations. Also, it inherits its operations from TwoDimensionalArray-
Category.
2. Click on TwoDimensionalArrayCategory, then on Exports. Here you see explicit operations
dealing with rows and columns. In addition, it inherits operations from HomogeneousAggre-
gate.
Parents
The parents of a domain are the same as the categories mentioned under the Exports button on the
first page. Domain Matrix has two parents but in general a domain can have any number.
698 CHAPTER 14. BROWSE
Ancestors
The ancestors of a constructor consist of its parents, the parents of its parents, and so on. Did you
perform the exercise in the last section under Exports? If so, you see here all the categories you found
while ascending the Exports chain for Matrix.
Dependents
The dependents of a constructor are those domains or packages that mention that constructor either
as an argument or in its exports.
If you click on Dependents two entries may surprise you: RectangularMatrix and SquareMatrix.
This happens because Matrix, as it turns out, appears in signatures of operations exported by these
domains.
Search Path
The term search path refers to the search order for functions. If you are an expert user or curious about
how the FriCAS system works, try the following exercise. Otherwise, you best skip this button and go
on to Users.
Clicking on Search Path gives you a list of domain constructors: InnerIndexedTwoDimension-
alArray, MatrixCategory&, TwoDimensionalArrayCategory&, HomogeneousAggregate&,
Aggregate&, Evalable&, SetCategory&, Hashable&, InnerEvalable&, BasicType&. What
are these constructors and how are they used?
We explain by an example. Suppose you create a matrix using the interpreter, then ask for its rank.
FriCAS must then find a function implementing the rank operation for matrices. The first place FriCAS
looks for rank is in the Matrix domain.
14.2. THE CONSTRUCTOR PAGE 699
If not there, the search path of Matrix tells FriCAS where else to look. Associated with the matrix
domain are ten other search path domains. Their order is important. FriCAS first searches the first one,
InnerIndexedTwoDimensionalArray. If not there, it searches the second MatrixCategory&.
And so on.
Where do these search path constructors come from? The source code for Matrix contains this syntax
for the function body of Matrix:2
InnerIndexedTwoDimensionalArray(R,mnRow,mnCol,Row,Col)
add ...
where the “...” denotes all the code that follows. In English, this means: “The functions for matrices
are defined as those from InnerIndexedTwoDimensionalArray domain augmented by those defined
in ‘...’,” where the latter take precedence.
This explains InnerIndexedTwoDimensionalArray. The other names, those with names ending
with an ampersand “&” are default packages for categories to which Matrix belongs. Default packages
are ordered by the notion of “closest ancestor.”
Users
A user of Matrix is any constructor that uses Matrix in its implementation. For example, Complex
is a user of Matrix; it exports several operations that take matrices as arguments or return matrices
as values.3
Uses
A benefactor of Matrix is any constructor that Matrix uses in its implementation. This information,
like that for clients, is gathered from run-time structures.4
Cross reference pages for categories have some different buttons on them. Starting with the front page
of Browse, search for Ring and enter its constructor page. Here are buttons Parents and Ancestors
similar to the notion for domains, except for categories the relationship between parent and child is
defined through category extension.
Children
Descendants
sight!
700 CHAPTER 14. BROWSE
Category hierarchies are complicated by the fact that categories take parameters. Where a parame-
terized category fits into a hierarchy may depend on values of its parameters. In general, the set of
categories in FriCAS forms a directed acyclic graph, that is, a graph with directed arcs and no cycles.
Domains
This produces a table of all domain constructors that can possibly be rings (members of category Ring).
Some domains are unconditional rings. Others are rings for some parameters and not for others. To
find out which, select the conditions button in the views panel. For example, DirectProduct(n,
R) is a ring if R is a ring.
Below every constructor table page is a Views panel. As an example, click on Uses from the constructor
page of Matrix to produce a short table of constructor names.
The Views panel is at the bottom of the page. Two items, names and conditions, are in italics. Others
are active buttons. The active buttons are those that give you useful alternative views on this table of
constructors. Once you select a view, you notice that the button turns off (becomes italicized) so that
you cannot reselect it.
names
This view gives you a table of names. Selecting any of these names brings up the constructor page for
that constructor.
abbrs
This view gives you a table of abbreviations, in the same order as the original constructor names.
Abbreviations are in capitals and they can be used interchangeably with constructor names in input
areas.
kinds
This view organizes constructor names into the three kinds: categories, domains and packages.
parameters
This view presents constructors with the arguments. This view of the benefactors of Matrix shows
that Matrix uses as many as ten different List domains in its implementation.
filter
This button is used to refine the list of names or abbreviations. Starting with the names view, enter
m* into the input area and click on filter. You then get a shorter table with only the names beginning
14.2. THE CONSTRUCTOR PAGE 701
with m.
descriptions
conditions
This page organizes the constructors according to predicates. The view is not available for your
example page since all constructors are unconditional. For a table with conditions, return to the
Ancestors page for Matrix, click on conditions in the view panel. This page shows you that
CoercibleTo(OutputForm) and SetCategory are ancestors of Matrix(R) only if R belongs to
category SetCategory.
Notice the input area at the bottom of the constructor page. If you leave this blank, then the infor-
mation you get is for the domain constructor Matrix(R), that is, Matrix for an arbitrary underlying
domain R.
In general, however, the exports and other information do usually depend on the actual value of R. For
example, Matrix exports the inverse operation only if the domain R is a Field. To see this, try this
from the main constructor page:
1. Enter Integer into the input area at the bottom of the page.
2. Click on Operations, producing a table of operations. Note the number of operation names
that appear at the top of the page.
4. Use the Delete or Backspace keys to erase Integer from the input area.
5. Click on Operations to produce a new table of operations. Look at the number of operations
you get. This number is greater than what you had before. Find, for example, the operation
inverse.
6. Click on inverse to produce a page describing the operation inverse. At the bottom of the
description, you notice that the Conditions line says “R has Field.” This operation is not
exported by Matrix(Integer) since Integer is not a field.
Try putting the name of a domain such as Fraction Integer (which is a field) into the input
area, then clicking on Operations. As you see, the operation inverse is exported.
702 CHAPTER 14. BROWSE
From the constructor page of Matrix, click on Operations to bring up the table of operations for
Matrix.
Find the operation inverse in the table and click on it. This takes you to a page showing the docu-
mentation for this operation.
Arguments
This lists each of the arguments of the operation in turn, paraphrasing the signature of the operation.
As for signatures, a “%” is used to designate this domain, that is, Matrix(R).
Returns
This describes the return value for the operation, analogous to the Arguments part.
Origin
This tells you which domain or category explicitly exports the operation. In this example, the Origin
is MatrixCategory.
14.3. MISCELLANEOUS FEATURES OF BROWSE 703
Conditions
This tells you that the operation is exported by Matrix(R) only if “R has Field,” that is, “R is a
member of category Field.” When no Conditions part is given, the operation is exported for all
values of R.
Description
Here are the “++” comments that appear in the source code of its Origin, here Matrix. You find these
comments in the source code for Matrix.
Click on to return to the table of operations. Click on map. Here you find three different
operations named map. This should not surprise you. Operations are identified by name and signature.
There are three operations named map, each with different signatures. What you see is the descriptions
view of the operations. If you like, select the button in the heading of one of these descriptions to get
only that operation.
Where
This part qualifies domain parameters mentioned in the arguments to the operation.
We suggest that you go to the constructor page for Matrix and click on Operations to bring up a
table of operations with a Views panel at the bottom.
704 CHAPTER 14. BROWSE
names
This view lists the names of the operations. Unlike constructors, however, there may be several
operations with the same name. The heading for the page tells you the number of unique names and
the number of distinct operations when these numbers are different.
filter
As for constructors, you can use this button to cut down the list of operations you are looking at. Click
on filter and enter, for example, m* into the input area, then click on filter. As usual, any logical
expression is permitted. For example, use
*! or *?
descriptions
This gives you the most information: a detailed description of all the operations in the form you have
seen before. Every other button summarizes these operations in some form.
signatures
parameters
This views the operations by their distinct syntactic forms with parameters.
origins
This organizes the operations according to the constructor that explicitly exports them.
conditions
This view organizes the operations into conditional and unconditional operations.
usage
This button is only available if your user-level is set to development. The usage button produces a
table of constructors that reference this operation.5
5 FriCAS requires an especially long time to produce this table, so anticipate this when requesting this information.
14.3. MISCELLANEOUS FEATURES OF BROWSE 705
implementation
This button is only available if your user-level is set to development. If you enter values for all domain
parameters on the constructor page, then the implementation button can be clicked. This button
tells you what domains or packages actually implement the various operations.6
With your user-level set to development, we suggest you try this exercise. Return to the main construc-
tor page for Matrix, then enter Integer into the input area at the bottom as the value of R. Then
click on Operations to produce a table of operations. Click on implementation. After some delay,
you get a page describing what implements each of the matrix operations, organized by the various
domains and packages.
6 This button often takes a long time; expect a delay while you wait for an answer.
706 CHAPTER 14. BROWSE
When entering search keys for constructors, you can use capital letters to search for abbreviations.
For example, enter UTS into the input area and click on Constructors. Up comes a page describing
UnivariateTaylorSeries whose abbreviation is UTS.
Constructor abbreviations always have three or more capital letters. For short constructor names (six
letters or less), abbreviations are not generally helpful as their abbreviation is typically the constructor
name in capitals. For example, the abbreviation for Matrix is MATRIX.
Abbreviations can also contain numbers. For example, POLY2 is the abbreviation for constructor
PolynomialFunctions2. For default packages, the abbreviation is the same as the abbreviation for
the corresponding category with the “&” replaced by “-”. For example, for the category default package
MatrixCategory& the abbreviation is MATCAT- since the corresponding category MatrixCate-
gory has abbreviation MATCAT.
Chapter 15
FriCAS 1.3.11
Old factorizers for univariate polynomials over finite fields are removed.
Implemented inverse trigonometric and hyperbolic functions for power series at branch points.
Prevent exits from page viewer when content is less than one page.
707
708 CHAPTER 15. WHAT’S NEW IN FRICAS
FriCAS 1.3.10
Improvements to runtime accounting subsystem, in particular FriCAS can now print info about
storage use.
Improved handling of roots during integration.
Improved ’simplifyExp’.
FriCAS 1.3.9
Fixed varius build problems, in particular build with sbcl-2.3.2 and newer.
FriCAS 1.3.8
Improvements to integrator, in particular integrator can now express some integrals in terms of
elliptic integrals.
More specialized array domains.
Better handling of cyclotomic polynomials. Roots of cyclotomic polynomials are now presented
in trigonometric form.
FriCAS 1.3.7
The FRICASsys binary will use its parent directory when FRICAS environment variable is not
set.
Polynomial rings are now of FreeModuleCategory.
Fixed tests for bad reduction during polynomial factrization and GCD.
FriCAS 1.3.6
Main FriCAS environment variable is now called FRICAS and main executable is called FRIC-
ASsys.
FriCAS 1.3.5
FriCAS 1.3.4
Added ’extendedLLL’.
Removed FreeAbelianGroup.
FriCAS 1.3.3
FriCAS 1.3.2
FriCAS 1.3.1
Categories with associative multiplication are now subcategories of categories with nonassociative
multiplication.
Inlining optimization in now effective also in command line (interpreter) compiler.
Added conversions between finitely presented groups and permutation groups (Todd-Coxeter
algorithm) and back.
Whole interpreter is now included in executable (no need to load parts before use).
Plots sometimes used single precision. Now they should always use double precision.
FriCAS 1.3.0
Several domains and categories are more general, in particular matrices, indexed products and
direct product.
’)show’ now evaluates predicates.
Improved integrator, handles few more ’erf’ cases and more algebraic functions. Result should
be simpler.
Simpler, more predictable equality for algebraic numbers (no longer uses ’trueEqual’).
FriCAS 1.2.7
FriCAS 1.2.6
FriCAS 1.2.5
Extended GCD in Ore algebras can now return coefficients of both GCD and LCM.
Continuation lines which begins like commands are no longer treated as commands.
Printing of series now respect ’showall’ setting, cyclic series are detected.
FriCAS 1.2.4
Added double precision versions of several special functions (needed for plotting).
FriCAS 1.2.3
In Spad error did only minimal checking of its argument. Now argument to error must be a
String or OutputForm or a literal list of OutputForm-s.
Types like ”failed” now consistently use string quotes in output form.
FriCAS 1.2.2
Improvements to ’integrate’: better handling of algebraic integrals, new routine which handles
some integrals containing ’lambertW’.
Improvements to ’limit’, now Gruntz algorithm knows about a few tractable functions.
Pile/nopile mode is now restored after ’)read’ or ’)compile’. Piling rules now accept some forms
of multiline lists.
Eliminated version checking in generated code. Note: this change means that Spad code compiled
by earlier FriCAS versions will not run in FriCAS 1.2.2.
Updated Aldor interface to work with free Aldor.
FriCAS 1.2.1
Improvements to ’integrate’: a new routine for integration in terms of Ei, better handling of
algebraic integrals.
Implemented ’erfi’.
Derivatives of ’asec’, ’asech’, ’acsc’ and ’acsch’ use different formula so that numeric evaluation
of derivative will take correct branch on real axis.
Linear dependence package is changed to be consistent with linear solvers.
15.1. RELEASE NOTES 717
FriCAS 1.2.0
FriCAS has now true 2-dimensional arrays (previously they were emulated using vectors of vec-
tors).
Speedups in some matrix operations and in arithmetic with algebraic expressions.
Changed Spad parser, it now uses common scanner with interpreter. Spad language is now
closer to interpreter language and Aldor. ’leave’ is removed, ’free’, ’generate’ and ’goto’ are now
keywords. Pile rules changed slightly, they should be more intuitive now. Error messages from
Spad parser should be slightly better.
’nthRootIfCan’ removes leading zeros from generalized series (this avoids problems with power
series expanders).
Fixed corruption of formal derivatives.
FriCAS 1.1.8
Improvements of pattern matching integrator, it can now integrate in terms of Fresnel integrals
and better handles integrals in terms of Si and Ci.
Better integration of symbolic derivatives.
Better normalization of Liouvillian functions.
New package for computing limits using Gruntz algorithm.
Faster removal of roots from denominators.
New domains for multivariate Ore algebras and partial differential operators.
New package for noncommutative Groebner bases.
New domain for univariate power series with arbitrary exponents.
New special functions: Shi and Chi.
Several aggregates (in particular tables) allow more general parameter types.
New domain for hash tables using equality from underlying domain.
FriCAS 1.1.7
FriCAS 1.1.6
FriCAS 1.1.5
Spad compiler can now handle single => at top level of a function.
FriCAS 1.1.4
Attempt to print error message about invalid type no longer crash (SF 2977357).
HyperDoc now should find all function descriptions (previously it missed several).
FriCAS 1.1.3
Added ”jet bundle” framework by Werner Seiler and Joachim Schue, which includes completion
procedure and symmetry analysis for PDE.
Better splitting of group representations (added Holt-Rees improvement to meatAxe).
Added numeric versions of some elliptic integrals and few more elliptic functions.
New experimental flag (off by default, set via setSimplifyDenomsFlag) which if on causes removal
of irrationalities from denominators. Usually it causes slowdown, but on some examples gives
huge speedup. It may go away in future (when no longer needed).
Added experimental framework for theory of computations.
15.1. RELEASE NOTES 721
Numerical solutions of polynomial systems have now required accuracy (SF 2418832).
Fixed problem with crashes during tracing.
Fixed a problem with nested iteration (SF 3016806).
Eliminated stack overflow when concatenating long lists.
FriCAS 1.1.2
Fixed few cases where elementary integrals were returned unevaluated or produced wrong results.
Unwanted numerical evaluation should be no longer a problem (FriCAS interpreter now very
strongly prefers symbolic evaluation over numerical evaluation).
Fixed a truncation bug in guessing package which caused loss of some correct solutions.
TeX and MathML format should correctly put parentheses around and inside sums and products.
Fixed few problems with handling of Unicode.
FriCAS 1.1.1
FriCAS 1.1.0
Speed improvements: several polynomial operations are faster, faster multiplication in Ore alge-
bras, faster computation of strong generating set for permutation groups, faster coercions.
Several improvements to the guessing package (in particular new option Somos for restricting
attention to Somos-like sequences
FriCAS can now compute multiplicative inverse of a power series with constant term not equal
to 1.
Fixed a problem with passing interpreter functions to algebra.
Plotting fixes.
FriCAS 1.0.9
Types in interpreter are now of type ’Type’ (instead of ’Domain’) and categories in interpreter
are of type ’Category’ (instead of ’Subdomain(Domain)’).
Interpreter functions can now return ’Type’.
New function for files: ’flush’.
Spad compiler: return in nested functions and nested functions returning functions.
FriCAS 1.0.8
Improved version of guessing package. It can now handle much larger problems than before.
Added ability to guess functional substitution equations.
Experimental support for build using CMU CL
Various speed improvements including faster indexing for two dimensional arrays
By default FriCAS build tries to use sbcl.
Building no longer require patch.
FriCAS 1.0.7
Comparisons between elements of the Expression domain are undefined. Earlier versions gave
confusing results for expressions like %e < %pi – now FriCAS will complain about < being unde-
fined.
A domain for general quaternions was added.
Equality in Any is now more reasonable – it uses equality from underlying domain if available.
724 CHAPTER 15. WHAT’S NEW IN FRICAS
In Spad code a single quote now means that the following token is a symbol.
Reorganization of algebra sources, in particular several types have changed (this may affect users
Spad code).
Categories with default package can be used just after definition (fixes 1.0.6 regression).
FriCAS 1.0.6
some undesirable simplification are no longer done by default, for example now asin(sin(3)) is
left unevaluated
support lambda expressions using “+->” syntax and nested functions in Spad
faster bootstrap, also parallel (this does not affect speed of release build)
fixed a regression introduced in 1.0.4 which caused equality for nested products to sometimes
give wrong result
corrected fixed output of floating point numbers,
FriCAS 1.0.5
improvement to normalize function, it performs now much stronger simplifications than before
better integration: due to improved normalize FriCAS can now integrate many functions that it
previously considered unintegrable
improvement to Martin Rubey guessing package, for example it can now guess differential equa-
tion for the generating function of integer partitions
FriCAS 1.0.4
new optional Emacs mode and efricas script to run FriCAS inside emacs
better unparse
removed support for attributes (replaced by empty categories) and use of colon for type conver-
sions in Spad code
a few bug fixes
FriCAS 1.0.3
added new categories for semiring and ordered semigroup, direct product of monoids is now a
monoid
internal cleanups and restructurings
FriCAS 1.0.2
FriCAS 1.0.1
FriCAS 1.0.0
The 1.0 release is the first release of FriCAS. Below we list main differences compared to AXIOM
September 2006.
Numerous bug fixes (in particular HyperDoc is now fully functional on Unix systems).
FriCAS includes guessing package written by Martin Rubey. This package provides unique ability to
guess formulas for sequences of numbers or polynomials.
Some computation, in particular involving Expression domain, should be much faster. FriCAS goes
through its testsuite in only half of the time needed by AXIOM September 2006.
Spad compilation is faster (in some cases 2 times faster).
FriCAS is much more portable than AXIOM September 2006. It can be built on Linux, many Unix
systems (for example Mac OS X and Solaris 10) and Windows. It can be built on top of gcl, sbcl, clisp
or openmcl (gcl and sbcl based FriCAS is fully functional, clisp or openmcl based one lacks graphic
support).
Many unused or non-working parts are removed from FriCAS. In particular FriCAS does not contain
support for NAG numerical library.
FriCAS can be built from sources using only a few pre-generated Lisp files for bootstrap – only to
bootstrap Shoe translator. This means that modifying FriCAS algebra is now much easier.
15.2. CHANGES TO SPAD LANGUAGE 727
http://fricas.github.io – The official documentation of FriCAS including the API of the FriCAS
library.
https://github.com/fricas/fricas – The official git repository.
http://wiki.fricas.org – A wiki site related to FriCAS.
http://fricas.sourceforge.net – The old homepage of FriCAS.
http://sourceforge.net/p/fricas/code/HEAD/tree/ – The old source code repository.
The leave keyword has been replaced by the break keyword for compatibility with the new AXIOM
extension language. See section Section 5.4.3 on page 132 for more information.
Curly braces are no longer used to create sets. Instead, use set followed by a bracketed expression. For
example,
set [1 ,2 ,3 ,4]
{1, 2, 3, 4} (1)
15.4. OLD NEWS ABOUT AXIOM VERSION 2.X 729
Set( PositiveInteger )
Curly braces are now used to enclose a block (see section Section 5.2 on page 126 for more information).
For compatibility, a block can still be enclosed by parentheses as well.
New coercions to and from type Expression have been added. For example, it is now possible to map
a polynomial represented as an expression to an appropriate polynomial type.
Various messages have been added or rewritten for clarity.
15.4.3 Library
The FullPartialFractionExpansion domain has been added. This domain computes factor-free full
partial fraction expansions. See section ‘FullPartialFractionExpansion’ on page 429 for examples.
We have implemented the Bertrand/Cantor algorithm for integrals of hyperelliptic functions. This
brings a major speedup for some classes of algebraic integrals.
We have implemented a new (direct) algorithm for integrating trigonometric functions. This brings a
speedup and an improvement in the answer quality.
The SmallFloat domain has been renamed DoubleFloat and SmallInteger has been renamed Single-
Integer. The new abbreviations as DFLOAT and SINT, respectively. We have defined the macro
SF, the old abbreviation for SmallFloat, to expand to DoubleFloat and modified the documentation
and input file examples to use the new names and abbreviations. You should do the same in any
private FriCAS files you have.
We have made improvements to the differential equation solvers and there is a new facility for solving
systems of first-order linear differential equations. In particular, an important fix was made to the solver
for inhomogeneous linear ordinary differential equations that corrected the calculation of particular
solutions. We also made improvements to the polynomial and transcendental equation solvers including
the ability to solve some classes of systems of transcendental equations.
The efficiency of power series have been improved and left and right expansions of tan(f(x)) at x =
a pole of f(x) can now be computed. A number of power series bugs were fixed and the GeneralU-
nivariatePowerSeries domain was added. The power series variable can appear in the coefficients
and when this happens, you cannot differentiate or integrate the series. Differentiation and integration
with respect to other variables is supported.
A domain was added for representing asymptotic expansions of a function at an exponential singularity.
For limits, the main new feature is the exponential expansion domain used to treat certain exponential
singularities. Previously, such singularities were treated in an ad hoc way and only a few cases were
covered. Now AXIOM can do things like
in a systematic way. It only does one level of nesting, though. In other words, if f is a function with
a pole, we can handle exp(f), but not exp(exp(f)).
The computation of integral bases has been improved through careful use of Hermite row reduction. A
P-adic algorithm for function fields of algebraic curves in finite characteristic has also been developed.
Miscellaneous: There is improved conversion of definite and indefinite integrals to InputForm; bi-
nomial coefficients are displayed in a new way; some new simplifications of radicals have been imple-
730 CHAPTER 15. WHAT’S NEW IN FRICAS
mented; the operation complexForm for converting to rectangular coordinates has been added; sym-
metric product operations have been added to LinearOrdinaryDifferentialOperator.
15.4.4 HyperDoc
The buttons on the titlebar and scrollbar have been replaced with ones which have a 3D effect. You
can change the foreground and background colors of these “controls” by including and modifying the
following lines in your .Xdefaults file.
Axiom.hyperdoc.ControlBackground: White
Axiom.hyperdoc.ControlForeground: Black
For various reasons, HyperDoc sometimes displays a secondary window. You can control the size and
placement of this window by including and modifying the following line in your .Xdefaults file.
Axiom.hyperdoc.FormGeometry: =950x450+100+0
This setting is a standard X Window System geometry specification: you are requesting a window 950
pixels wide by 450 deep and placed in the upper left corner.
Some key definitions have been changed to conform more closely with the CUA guidelines. Press F9
to see the current definitions.
Input boxes (for example, in the Browser) now accept paste-ins from the X Window System. Use the
second button to paste in something you have previously copied or cut. An example of how you can
use this is that you can paste the type from an FriCAS computation into the main Browser input box.
15.4.5 Documentation
We describe here a few additions to the on-line version of the AXIOM book which you can read with
HyperDoc.
A section has been added to the graphics chapter, describing how to build two-dimensional graphs from
lists of points. An example is given showing how to read the points from a file. See section Section
7.1.9 on page 211 for details.
A further section has been added to that same chapter, describing how to add a two-dimensional graph
to a viewport which already contains other graphs. See section Section 7.1.10 on page 219 for details.
Chapter 3 and the on-line HyperDoc help have been unified.
An explanation of operation names ending in “?” and “!” has been added to the first chapter. See the
end of the section Section 1.3.6 on page 28 for details.
An expanded explanation of using predicates has been added to the sixth chapter. See the example
involving evenRule in the middle of the section Section 6.21 on page 187 for details.
Documentation for the )compile, )library and )load commands has been greatly changed. This
reflects the ability of the )compile to now invoke the AXIOM-XL compiler, the impending deletion of
the )load command and the new )library command. The )library command replaces )load and
is compatible with the compiled output from both the old and new compilers.
15.4. OLD NEWS ABOUT AXIOM VERSION 2.X 731
Univariate polynomial factorization over the integers has been enhanced by updates to the Galois-
GroupFactorizer type and friends from Frederic Lehobey ([email protected], University of
Lille I, France).
The package constructor PseudoRemainderSequence provides efficient algorithms by Lionel Ducos
([email protected], University of Poitiers, France) for computing sub-resultants.
This leads to a speed up in many places in FriCAS where sub-resultants are computed (polynomial
system solving, algebraic factorization, integration).
Based on this package, the domain constructor NewSparseUnivariatePolynomial extends the con-
structor SparseUnivariatePolynomial. In a similar way, the NewSparseMultivariatePolyno-
mial extends the constructor SparseUnivariatePolynomial; it also provides some additional oper-
ations related to polynomial system solving by means of triangular sets.
Several domain constructors implement regular triangular sets (or regular chains). Among them Reg-
ularTriangularSet and SquareFreeRegularTriangularSet. They also implement an algorithm by
Marc Moreno Maza ([email protected], NAG) for computing triangular decompositions of polynomial
systems. This method is refined in the package LazardSetSolvingPackage in order to produce de-
compositions by means of Lazard triangular sets. For the case of polynomial systems with finitely
many solutions, these decompositions can also be computed by the package LexTriangularPackage.
The domain constructor RealClosure by Renaud Rioboo ([email protected], University of Paris
6, France) provides the real closure of an ordered field. The implementation is based on interval
arithmetic. Moreover, the design of this constructor and its related packages allows an easy use of
other codings for real algebraic numbers.
Based on triangular decompositions and the RealClosure constructor, the package ZeroDimen-
sionalSolvePackage provides operations for computing symbolically the real or complex roots of
polynomial systems with finitely many solutions.
Polynomial arithmetic with non-commutative variables has been improved too by a contribution of
Michel Petitot ([email protected], University of Lille I, France). The domain constructors XRecur-
sivePolynomial and XDistributedPolynomial provide recursive and distributed representations
for these polynomials. They are the non-commutative equivalents for the SparseMultivariatePoly-
nomial and DistributedMultivariatePolynomial constructors. The constructor LiePolynomial
implement Lie polynomials in the Lyndon basis. The constructor XPBWPolynomial manage poly-
nomials with non-commutative variables in the Poincaré-Birkhoff-Witt basis from the Lyndon basis.
This allows to compute in the Lie Group associated with a free nilpotent Lie algebra by using the
LieExponentials domain constructor.
From this version of AXIOM onwards, the pixmap format used to save graphics images in color
and to display them in HyperDoc has been changed to the industry-standard XPM format. See
ftp://koala.inria.fr/pub/xpm.
732 CHAPTER 15. WHAT’S NEW IN FRICAS
Content removed - no longer relevant since FriCAS runs on different Lisp systems.
Appendix A
This chapter describes system commands, the command-line facilities used to control the FriCAS
environment. The first section is an introduction and discusses the common syntax of the commands
available.
A.1 Introduction
System commands are used to perform FriCAS environment management. Among the commands are
those that display what has been defined or computed, set up multiple logical FriCAS environments
(frames), clear definitions, read files of expressions and commands, show what functions are available,
and terminate FriCAS.
Some commands are restricted: the commands
set the user-access level to the three possible choices. All commands are available at development
level and the fewest are available at interpreter level. The default user-level is interpreter. In
addition to the )set command (discussed in Section A.21 on page 753) you can use the HyperDoc
settings facility to change the user-level.
Each command listing begins with one or more syntax pattern descriptions plus examples of related
commands. The syntax descriptions are intended to be easy to read and do not necessarily represent the
most compact way of specifying all possible arguments and options; the descriptions may occasionally
be redundant.
All system commands begin with a right parenthesis which should be in the first available column of
the input line (that is, immediately after the input prompt, if any). System commands may be issued
directly to FriCAS or be included in .input files.
A system command argument is a word that directly follows the command name and is not followed
or preceded by a right parenthesis. A system command option follows the system command and is
733
734 APPENDIX A. FRICAS SYSTEM COMMANDS
directly preceded by a right parenthesis. Options may have arguments: they directly follow the option.
This example may make it easier to remember what is an option and what is an argument:
In the system command descriptions, optional arguments and options are enclosed in brackets (“[”
and “]”). If an argument or option name is in italics, it is meant to be a variable and must have
some actual value substituted for it when the system command call is made. For example, the syntax
pattern description
)read fileName [)quietly]
would imply that you must provide an actual file name for fileName but need not use the )quietly
option. Thus
)read matrix.input
)s Integer
is not a valid abbreviation for the )set command, because both )set and )show begin with the letter
“s”. Typically, two or three letters are sufficient for disambiguating names. In our descriptions of the
commands, we have used no abbreviations for either command names or options.
In some syntax descriptions we use a vertical line “|” to indicate that you must specify one of the
listed choices. For example, in
only on and off are acceptable words for following boot. We also sometimes use “...” to indicate that
additional arguments or options of the listed form are allowed. Finally, in the syntax descriptions we
may also list the syntax of related commands.
A.2 )abbreviation
User Level Required: compiler
Command Syntax:
)abbreviation query [nameOrAbbrev]
)abbreviation category abbrev fullname [)quiet]
)abbreviation domain abbrev fullname [)quiet]
)abbreviation package abbrev fullname [)quiet]
A.3. )BOOT 735
The following shows the constructor name corresponding to the abbreviation NNI:
)abbreviation query
To add an abbreviation for a constructor, use this command with category, domain or package. The
following add abbreviations to the system for a category, domain and package, respectively:
If the )quiet option is used, no output is displayed from this command. You would normally only
define an abbreviation in a library source file. If this command is issued for a constructor that has
already been loaded, the constructor will be reloaded next time it is referenced. In particular, you can
use this command to force the automatic reloading of constructors.
To remove an abbreviation, the remove argument is used. This is usually only used to correct a
previous command that set an abbreviation for a constructor name. If, in fact, the abbreviation does
exist, you are prompted for confirmation of the removal request. Either of the following commands will
remove the abbreviation VECTOR2 and the constructor name VectorFunctions2 from the system:
A.3 )boot
User Level Required: development
736 APPENDIX A. FRICAS SYSTEM COMMANDS
Command Syntax:
)boot bootExpression
Command Description:
This command is used by FriCAS system developers to execute expressions written in the BOOT
language. For example,
creates and compiles the Common LISP function “times3” obtained by translating the BOOT code.
Also See: ‘)fin’ in Section A.10 on page 745, ‘)lisp’ in Section A.15 on page 750, ‘)set’ in Section
A.21 on page 753, and ‘)system’ in Section A.25 on page 756.
A.4 )cd
User Level Required: interpreter
Command Syntax:
)cd directory
Command Description:
This command sets the FriCAS working current directory. The current directory is used for looking
for input files (for )read), FriCAS library source files (for )compile), saved history environment files
(for )history )restore), compiled FriCAS library files (for )library), and files to edit (for )edit).
It is also used for writing spool files (via )spool), writing history input files (via )history )write)
and history environment files (via )history )save),and compiled FriCAS library files (via )compile).
If issued with no argument, this command sets the FriCAS current directory to your home directory.
If an argument is used, it must be a valid directory name. Except for the “)” at the beginning of the
command, this has the same syntax as the operating system cd command.
Also See: ‘)compile’ in Section A.7 on page 738, ‘)edit’ in Section A.9 on page 744, ‘)history’ in
Section A.13 on page 747, ‘)library’ in Section A.14 on page 749, ‘)read’ in Section A.20 on page
752, and ‘)spool’ in Section A.23 on page 754.
A.5 )close
User Level Required: interpreter
Command Syntax:
)close
)close )quietly
Command Description:
This command is used to close down interpreter client processes. Such processes are started by Hyper-
Doc to run FriCAS examples when you click on their text. When you have finished examining or
A.6. )CLEAR 737
modifying the example and you do not want the extra window around anymore, issue
)close
Type ”y” (followed by the Return key) if this is what you had in mind. Type ”n” (followed by the
Return key) to cancel the command.
You can use the )quietly option to force FriCAS to close down the interpreter client process without
closing down the entire FriCAS session.
Also See: ‘)quit’ in Section A.19 on page 751 and ‘)pquit’ in Section A.18 on page 751.
A.6 )clear
User Level Required: interpreter
Command Syntax:
)clear all
)clear completely
)clear properties all
)clear properties obj1 [obj2 ...]
)clear value all
)clear value obj1 [obj2 ...]
)clear mode all
)clear mode obj1 [obj2 ...]
Command Description:
This command is used to remove function and variable declarations, definitions and values from the
workspace. To empty the entire workspace and reset the step counter to 1, issue
)clear all
To remove everything in the workspace but not reset the step counter, issue
)clear properties x
)clear properties x y f
)clear p all
)clear p x
)clear p x y f
This retains whatever declarations the objects had. To remove definitions and values for the specific
objects x, y and f, issue
)clear value x y f
)clear v x y f
To remove the declarations of everything while leaving the definitions and values, issue
)clear mode x y f
)clear m x y f
The )display names and )display properties commands may be used to see what is currently in
the workspace.
The command
)clear completely
does everything that )clear all does, and also clears the internal system function and constructor
caches.
Also See: ‘)display’ in Section A.8 on page 743, ‘)history’ in Section A.13 on page 747, and ‘)undo’
in Section A.27 on page 760.
A.7 )compile
User Level Required: compiler
Command Syntax:
)compile
A.7. )COMPILE 739
)compile fileName
)compile fileName.as
)compile directory/fileName.as
)compile fileName.ao
)compile directory/fileName.ao
)compile fileName.al
)compile directory/fileName.al
)compile fileName.lsp
)compile directory/fileName.lsp
)compile fileName.spad
)compile directory/fileName.spad
)compile fileName )new
)compile fileName )old
)compile fileName )quiet
)compile fileName )noquiet
)compile fileName )moreargs
)compile fileName )onlyargs
)compile fileName )break
)compile fileName )nobreak
)compile fileName )library
)compile fileName )nolibrary
)compile fileName )vartrace
)compile fileName )constructor nameOrAbbrev
Command Description:
You use this command to invoke the Aldor library compiler or the FriCAS system compiler. The
)compile system command is actually a combination of FriCAS processing and a call to the Aldor
compiler. It is performing double-duty, acting as a front-end to both the Aldor compiler and the
FriCAS system compiler. (The FriCAS system compiler is written in Boot and is an integral part of
the FriCAS environment. The Aldor compiler is written in C and executed by the operating system
when called from within FriCAS.)
The command compiles files with file extensions .as, .ao and .al with the Aldor compiler and files with
file extension .spad with the FriCAS system compiler. It also can compile files with file extension .lsp.
These are assumed to be Lisp files generated by the Aldor compiler. If you omit the file extension,
the command looks to see if you have specified the )new or )old option. If you have given one of
these options, the corresponding compiler is used. Otherwise, the command first looks in the standard
system directories for files with extension .as, .ao and .al and then files with extension .spad. The first
file found has the appropriate compiler invoked on it. If the command cannot find a matching file, an
error message is displayed and the command terminates.
We now describe the options for the Aldor compiler.
The first thing )compile does is look for a source code filename among its arguments. Thus
)compile mycode.as
)compile /u/jones/as/mycode.as
)compile mycode
740 APPENDIX A. FRICAS SYSTEM COMMANDS
all invoke )compiler on the file /u/jones/as/mycode.as if the current FriCAS working directory is
/u/jones/as. (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 FriCAS.)
This is frequently all you need to compile your file. This simple command:
3. uses the )library command to tell FriCAS about the contents of your compiled file and arrange
to have those contents loaded on demand.
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 the Aldor documentation. The default
options used by the )compile command can be viewed and set using the )set compiler args FriCAS
system command. The current defaults are
-Mno-ALDOR W WillObsolete: do not display messages about older generated files becoming
obsolete, and
-DFriCAS: define the global assertion FriCAS so that the Aldor libraries for generating stand-alone
code are not accidentally used with FriCAS.
To supplement these default arguments, use the )moreargs option on )compile. For example,
uses the default arguments and appends the -v (verbose) argument flag. The additional argument
specification must be enclosed in double quotes.
To completely replace these default arguments for a particular use of )compile, use the )onlyargs
option. For example,
A.7. )COMPILE 741
only uses the -v (verbose) and -O (optimize) arguments. The argument specification must be en-
closed in double quotes. In this example, Lisp code is not produced and so the compilation output
will not be available to FriCAS.
To completely replace the default arguments for all calls to )compile within your FriCAS session, use
)set compiler args. For example, to use the above arguments for all compilations, issue
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.
By default, the )library system command exposes all domains and categories it processes. This means
that the FriCAS interpreter 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,
You must give an explicit directory after )dir, even if you want all compiled code in the current
working directory processed, e.g.
)library )dir .
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 onto 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
)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.
742 APPENDIX A. FRICAS SYSTEM COMMANDS
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 present a .asy generated from the same source file.
The following are descriptions of options for the FriCAS system compiler.
You can compile category, domain, and package constructors contained in files with file extension .spad.
You can compile individual constructors or every constructor in a file.
The full filename is remembered between invocations of this command and )edit commands. The
sequence of commands
)compile matrix.spad
)edit
)compile
will call the compiler, edit, and then call the compiler again on the file matrix.spad. If you do not
specify a directory, the working current directory (see Section A.4 on page 736) is searched for the file.
If the file is not found, the standard system directories are searched.
If you do not give any options, all constructors within a file are compiled. Each constructor should
have an )abbreviation command in the file in which it is defined. We suggest that you place the
)abbreviation commands at the top of the file in the order in which the constructors are defined.
The list of commands serves as a table of contents for the file.
The )library option causes directories containing the compiled code for each constructor to be created
in the working current directory. The name of such a directory consists of the constructor abbreviation
and the .NRLIB file extension. For example, the directory containing the compiled code for the
MATRIX constructor is called MATRIX.NRLIB. The )nolibrary option says that such files
should not be created. The default is )library. Note that the semantics of )library and )nolibrary
for the Aldor compiler and for the FriCAS system compiler are completely different.
The )vartrace option causes the compiler to generate extra code for the constructor to support
conditional tracing of variable assignments. (see Section A.26 on page 756). Without this option, this
code is suppressed and one cannot use the )vars option for the trace command.
The )constructor option is used to specify a particular constructor to compile. All other constructors
in the file are ignored. The constructor name or abbreviation follows )constructor. Thus either
or
A.8 )display
User Level Required: interpreter
Command Syntax:
)display all
)display properties
)display properties all
)display properties [obj1 [obj2 ...]]
)display value all
)display value [obj1 [obj2 ...]]
)display mode all
)display mode [obj1 [obj2 ...]]
)display names
)display operations opName
Command Description:
This command is used to display the contents of the workspace and signatures of functions with a
given name.1
The command
)display names
lists the names of all user-defined objects in the workspace. This is useful if you do not wish to see
everything about the objects and need only be reminded of their names.
The commands
)display all
)display properties
)display properties all
all do the same thing: show the values and types and declared modes of all variables in the workspace.
If you have defined functions, their signatures and definitions will also be displayed.
To show all information about a particular variable or user functions, for example, something named
d, issue
)display properties d
)display value d
)display mode d
All modemaps for a given operation may be displayed by using )display operations. A modemap is
a collection of information about a particular reference to an operation. This includes the types of the
arguments and the return value, the location of the implementation and any conditions on the types.
The modemap may contain patterns. The following displays the modemaps for the operation complex:
)d op complex
Also See: ‘)clear’ in Section A.6 on page 737, ‘)history’ in Section A.13 on page 747, ‘)set’ in
Section A.21 on page 753, ‘)show’ in Section A.22 on page 753, and ‘)what’ in Section A.28 on page
761.
A.9 )edit
User Level Required: interpreter
Command Syntax:
)edit [filename]
Command Description:
This command is used to edit files. It works in conjunction with the )read and )compile commands
to remember the name of the file on which you are working. By specifying the name fully, you can edit
any file you wish. Thus
)edit /u/julius/matrix.input
will place you in an editor looking at the file /u/julius/matrix.input. By default, the editor is
less just for viewing purpose, but if you have a shell environment variable FRICASEDITOR defined,
that editor will be used. When FriCAS is running under the X Window System, it will try to open a
separate xterm running your editor if it thinks one is necessary. For example, under the Bash shell, if
you issue
export FRICASEDITOR=emacs
A.10 )fin
User Level Required: development
Command Syntax:
)fin
Command Description:
This command is used by FriCAS developers to leave the FriCAS system and return to the underlying
Common LISP system. To return to FriCAS, issue the “(|spad|)” function call to Common LISP.
Also See: ‘)pquit’ in Section A.18 on page 751 and ‘)quit’ in Section A.19 on page 751.
A.11 )frame
User Level Required: interpreter
Command Syntax:
)frame new frameName
)frame drop [frameName]
)frame next
)frame last
)frame names
)frame import frameName [objectName1 [objectName2 ...]]
)set message frame on | off
)set message prompt frame
Command Description:
A frame can be thought of as a logical session within the physical session that you get when you start
the system. You can have as many frames as you want, within the limits of your computer’s storage,
paging space, and so on. Each frame has its own step number, environment and history. You can have
a variable named a in one frame and it will have nothing to do with anything that might be called a
in any other frame.
Some frames are created by the HyperDoc program and these can have pretty strange names, since
they are generated automatically. To find out the names of all frames, issue
)frame names
The history facility can be turned on by issuing either )set history on or )history )on. If the
history facility is on and you are saving history information in a file rather than in the FriCAS envi-
ronment then a history file with filename quark.axh will be created as you enter commands. If you
wish to go back to what you were doing in the “initial” frame, use
746 APPENDIX A. FRICAS SYSTEM COMMANDS
)frame next
or
)frame last
will print more messages about frames when it is set on. By default, it is off.
when you start up. In this case, the frame name and step make up the prompt.
Also See: ‘)history’ in Section A.13 on page 747 and ‘)set’ in Section A.21 on page 753.
A.12 )help
User Level Required: interpreter
Command Syntax:
A.13. )HISTORY 747
)help
)help commandName
)help syntax
Command Description:
This command displays help information about system commands. If you issue
)help help
then this very text will be shown. You can also give the name of a system command to display
information about it. For example,
)help clear
)help syntax
A.13 )history
User Level Required: interpreter
Command Syntax:
)history )on
)history )off
)history )write historyInputFileName
)history )show [n] [both]
)history )save savedHistoryName
)history )restore [savedHistoryName]
)history )reset
)history )change n
)history )memory
)history )file
%
%%(n)
)set history on | off
Command Description:
The history facility within FriCAS allows you to restore your environment to that of another session
and recall previous computational results. Additional commands allow you to review previous input
lines and to create an .input file of the lines typed to FriCAS.
748 APPENDIX A. FRICAS SYSTEM COMMANDS
FriCAS saves your input and output if the history facility is turned on (which is the default). This
information is saved if either of
)set history on
)history )on
)change n will set the number of steps that are saved in memory to n. This option only has effect
when the history data is maintained in a file. If you have issued )history )memory (or not
changed the default) there is no need to use )history )change.
)on will start the recording of information. If the workspace is not empty, you will be asked to confirm
this request. If you do so, the workspace will be cleared and history data will begin being saved.
You can also turn the facility on by issuing )set history on.
)off will stop the recording of information. The )history )show command will not work after issuing
this command. Note that this command may be issued to save time, as there is some performance
penalty paid for saving the environment data. You can also turn the facility off by issuing )set
history off.
)file indicates that history data should be saved in an external file on disk.
)memory indicates that all history data should be kept in memory rather than saved in a file. Note
that if you are computing with very large objects it may not be practical to kept this data in
memory.
)reset will flush the internal list of the most recent workspace calculations so that the data structures
may be garbage collected by the underlying Common LISP system. Like )history )change,
this option only has real effect when history data is being saved in a file.
A.14. )LIBRARY 749
)restore [savedHistoryName] completely clears the environment and restores it to a saved session, if
possible. The )save option below allows you to save a session to a file with a given name. If you
had issued )history )save jacobi the command )history )restore jacobi would clear the
current workspace and load the contents of the named saved session. If no saved session name is
specified, the system looks for a file called last.axh.
)save savedHistoryName is used to save a snapshot of the environment in a file. This file is placed
in the current working directory (see Section A.4 on page 736). Use )history )restore to
restore the environment to the state preserved in the file. This option also creates an input file
containing all the lines of input since you created the workspace frame (for example, by starting
your FriCAS session) or last did a )clear all or )clear completely.
)show [n] [both] can show previous input lines and output results. )show will display up to twenty
of the last input lines (fewer if you haven’t typed in twenty lines). )show n will display up to
n of the last input lines. )show both will display up to five of the last input lines and output
results. )show n both will display up to n of the last input lines and output results.
)write historyInputFile creates an .input file with the input lines typed since the start of the ses-
sion/frame or the last )clear all or )clear completely. If historyInputFileName does not
contain a period (“.”) in the filename, .input is appended to it. For example, )history )write
chaos and )history )write chaos.input both write the input lines to a file called chaos.input
in your current working directory. If you issued one or more )undo commands, )history )write
eliminates all input lines backtracked over as a result of )undo. You can edit this file and then
use )read to have FriCAS process the contents.
Also See: ‘)frame’ in Section A.11 on page 745, ‘)read’ in Section A.20 on page 752, ‘)set’ in Section
A.21 on page 753, and ‘)undo’ in Section A.27 on page 760.
A.14 )library
User Level Required: interpreter
Command Syntax:
)library libName1 [libName2 ...]
)library )dir dirName
)library )only objName1 [objlib2 ...]
)library )noexpose
Command Description:
This command replaces the )load system command. The )library command makes available to
FriCAS the compiled objects in the libraries listed.
For example, if you )compile dopler.as in your home directory, issue )library dopler to have
FriCAS look at the library, determine the category and domain constructors present, update the
internal database with various properties of the constructors, and arrange for the constructors to be
automatically loaded when needed. If the )noexpose option has not been given, the constructors will
be exposed (that is, available) in the current frame.
If you compiled a file with the FriCAS system compiler, you will have an NRLIB present, for example,
750 APPENDIX A. FRICAS SYSTEM COMMANDS
DOPLER.NRLIB, where DOPLER is a constructor abbreviation. The command )library DOPLER will
then do the analysis and database updates as above.
To tell the system about all libraries in a directory, use )library )dir dirName where dirName is an
explicit directory. You may specify “.” as the directory, which means the current directory from which
you started the system or the one you set via the )cd command. The directory name is required.
You may only want to tell the system about particular constructors within a library. In this case, use
the )only option. The command )library dopler )only Test1 will only cause the Test1 constructor
to be analyzed, autoloaded, etc..
Finally, each constructor in a library are usually automatically exposed when the )library command
is used. Use the )noexpose option if you do not want them exposed. At a later time you can use )set
expose add constructor to expose any hidden constructors.
Also See: ‘)cd’ in Section A.4 on page 736, ‘)compile’ in Section A.7 on page 738, ‘)frame’ in Section
A.11 on page 745, and ‘)set’ in Section A.21 on page 753.
A.15 )lisp
User Level Required: development
Command Syntax:
)lisp [lispExpression]
Command Description:
This command is used by FriCAS system developers to have single expressions evaluated by the Com-
mon LISP system on which FriCAS is built. The lispExpression is read by the Common LISP reader
and evaluated. If this expression is not complete (unbalanced parentheses, say), the reader will wait
until a complete expression is entered.
Since this command is only useful for evaluating single expressions, the )fin command may be used
to drop out of FriCAS into Common LISP.
Also See: ‘)system’ in Section A.25 on page 756, ‘)boot’ in Section A.3 on page 735, and ‘)fin’ in
Section A.10 on page 745.
A.16 )load
User Level Required: interpreter
Command Description:
This command is obsolete. Use )library instead.
A.17 )ltrace
User Level Required: development
A.18. )PQUIT 751
Command Syntax:
This command has the same arguments as options as the )trace command.
Command Description:
This command is used by FriCAS system developers to trace Common LISP or BOOT functions. It is
not supported for general use.
Also See: ‘)boot’ in Section A.3 on page 735, ‘)lisp’ in Section A.15 on page 750, and ‘)trace’ in
Section A.26 on page 756.
A.18 )pquit
User Level Required: interpreter
Command Syntax:
)pquit
Command Description:
This command is used to terminate FriCAS and return to the operating system. Other than by redoing
all your computations or by using the )history )restore command to try to restore your working
environment, you cannot return to FriCAS in the same state.
)pquit differs from the )quit in that it always asks for confirmation that you want to terminate
FriCAS (the “p” is for “protected”). When you enter the )pquit command, FriCAS responds
and FriCAS will terminate and return you to the operating system (or the environment from which
you invoked the system). If you responded with something other than y or yes, then the message
A.19 )quit
User Level Required: interpreter
Command Syntax:
752 APPENDIX A. FRICAS SYSTEM COMMANDS
)quit
)set quit protected | unprotected
Command Description:
This command is used to terminate FriCAS and return to the operating system. Other than by redoing
all your computations or by using the )history )restore command to try to restore your working
environment, you cannot return to FriCAS in the same state.
)quit differs from the )pquit in that it asks for confirmation only if the command
has been issued. Otherwise, )quit will make FriCAS terminate and return you to the operating system
(or the environment from which you invoked the system).
The default setting is )set quit unprotected. We suggest that you do not (somehow) assign )quit
to be executed when you press, say, a function key.
Also See: ‘)fin’ in Section A.10 on page 745, ‘)history’ in Section A.13 on page 747, ‘)close’ in
Section A.5 on page 736, ‘)pquit’ in Section A.18 on page 751, and ‘)system’ in Section A.25 on page
756.
A.20 )read
User Level Required: interpreter
Command Syntax:
)read [fileName]
)read [fileName] [)quiet] [)ifthere]
Command Description:
This command is used to read .input files into FriCAS. The command
)read matrix.input
will read the contents of the file matrix.input into FriCAS. The “.input” file extension is optional.
See Section 4.1 on page 105 for more information about .input files.
This command remembers the previous file you edited, read or compiled. If you do not specify a file
name, the previous file will be read.
The )ifthere option checks to see whether the .input file exists. If it does not, the )read command
does nothing. If you do not use this option and the file does not exist, you are asked to give the name
of an existing .input file.
The )quiet option suppresses output while the file is being read.
Also See: ‘)compile’ in Section A.7 on page 738, ‘)edit’ in Section A.9 on page 744, and ‘)history’
in Section A.13 on page 747.
A.21. )SET 753
A.21 )set
User Level Required: interpreter
Command Syntax:
)set
)set label1 [... labelN]
)set label1 [... labelN] newValue
Command Description:
The )set command is used to view or set system variables that control what messages are displayed,
the type of output desired, the status of the history facility, the way FriCAS user functions are cached,
and so on. Since this collection is very large, we will not discuss them here. Rather, we will show how
the facility is used. We urge you to explore the )set options to familiarize yourself with how you can
modify your FriCAS working environment. There is a HyperDoc version of this same facility available
from the main HyperDoc menu.
The )set command is command-driven with a menu display. It is tree-structured. To see all top-level
nodes, issue )set by itself.
)set
Variables with values have them displayed near the right margin. Subtrees of selections have “...”
displayed in the value field. For example, there are many kinds of messages, so issue )set message to
see the choices.
)set message
The current setting for the variable that displays whether computation times are displayed is visible
in the menu displayed by the last command. To see more information, issue
As noted above, not all settings have so many qualifiers. For example, to change the )quit command
to being unprotected (that is, you will not be prompted for verification), you need only issue
A.22 )show
User Level Required: interpreter
Command Syntax:
754 APPENDIX A. FRICAS SYSTEM COMMANDS
)show nameOrAbbrev
)show nameOrAbbrev )operations
Command Description: This command displays information about FriCAS domain, package and
category constructors. If no options are given, the )operations option is assumed. For example,
)show POLY
)show POLY )operations
)show Polynomial
)show Polynomial )operations
each display basic information about the Polynomial domain constructor and then provide a listing
of operations. Since Polynomial requires a Ring (for example, Integer) as argument, the above
commands all refer to a unspecified ring R. In the list of operations, “$” means Polynomial(R).
The basic information displayed includes the signature of the constructor (the name and arguments),
the constructor abbreviation, the exposure status of the constructor, and the name of the library source
file for the constructor.
If operation information about a specific domain is wanted, the full or abbreviated domain name may
be used. For example,
are among the combinations that will display the operations exported by the domain Polynomial(Integer)
(as opposed to the general domain constructor Polynomial).
Also See: ‘)display’ in Section A.8 on page 743, ‘)set’ in Section A.21 on page 753, and ‘)what’ in
Section A.28 on page 761.
A.23 )spool
User Level Required: interpreter
Command Syntax:
)spool [fileName]
)spool
Command Description:
This command is used to save (spool) all FriCAS input and output into a file, called a spool file. You
can only have one spool file active at a time. To start spool, issue this command with a filename. For
example,
)spool integrate.out
If the filename is qualified with a directory, then the output will be placed in that directory. If no
directory information is given, the spool file will be placed in the current directory. The current
directory is the directory from which you started FriCAS or is the directory you specified using the
)cd command.
Also See: ‘)cd’ in Section A.4 on page 736.
A.24 )synonym
User Level Required: interpreter
Command Syntax:
)synonym
)synonym synonym fullCommand
)what synonyms
Command Description:
This command is used to create short synonyms for system command expressions. For example, the
following synonyms might simplify commands you often use.
Once defined, synonyms can be used in place of the longer command expressions. Thus
)fortran on
)synonyms
)what synonyms
To list, say, all synonyms that contain the substring “ap”, issue
)what synonyms ap
Also See: ‘)set’ in Section A.21 on page 753 and ‘)what’ in Section A.28 on page 761.
756 APPENDIX A. FRICAS SYSTEM COMMANDS
A.25 )system
User Level Required: interpreter
Command Syntax:
)system cmdExpression
Command Description:
This command may be used to issue commands to the operating system while remaining in FriCAS.
The cmdExpression is passed to the operating system for execution.
To get an operating system shell, issue, for example, )system sh. When you enter the key combination,
Ctrl – D (pressing and holding the Ctrl key and then pressing the D key) the shell will terminate
and you will return to FriCAS. We do not recommend this way of creating a shell because Common
LISP may field some interrupts instead of the shell. If possible, use a shell running in another window.
If you execute programs that misbehave you may not be able to return to FriCAS. If this happens, you
may have no other choice than to restart FriCAS and restore the environment via )history )restore,
if possible.
Also See: ‘)boot’ in Section A.3 on page 735, ‘)fin’ in Section A.10 on page 745, ‘)lisp’ in Section
A.15 on page 750, ‘)pquit’ in Section A.18 on page 751, and ‘)quit’ in Section A.19 on page 751.
A.26 )trace
User Level Required: interpreter
Command Syntax:
)trace
)trace )off
)trace function [options]
)trace constructor [options]
)trace domainOrPackage [options]
where options can be one or more of
)after S-expression
)before S-expression
)break after
)break before
)cond S-expression
)count
)count n
)depth n
)local op1 [... opN]
)nonquietly
)nt
A.26. )TRACE 757
)off
)only listOfDataToDisplay
)ops
)ops op1 [... opN ]
)restore
)stats
)stats reset
)timer
)varbreak
)varbreak var1 [... varN ]
)vars
)vars var1 [... varN ]
)within executingFunction
Command Description:
This command is used to trace the execution of functions that make up the FriCAS system, functions
defined by users, and functions from the system library. Almost all options are available for each type
of function but exceptions will be noted below.
To list all functions, constructors, domains and packages that are traced, simply issue
)trace
)trace )off
When a function is traced, the default system action is to display the arguments to the function and
the return value when the function is exited. Note that if a function is left via an action such as a
THROW, no return value will be displayed. Also, optimization of tail recursion may decrease the number
of times a function is actually invoked and so may cause less trace information to be displayed. Other
information can be displayed or collected when a function is traced and this is controlled by the various
options. Most options will be of interest only to FriCAS system developers. If a domain or package is
traced, the default action is to trace all functions exported.
Individual interpreter, lisp or boot functions can be traced by listing their names after )trace. Any
options that are present must follow the functions to be traced.
)trace f
)trace f )off
Note that if a function name contains a special character, it will be necessary to escape the character
with an underscore
)trace _/D_,1
758 APPENDIX A. FRICAS SYSTEM COMMANDS
To trace all domains or packages that are or will be created from a particular constructor, give the
constructor name or abbreviation after )trace.
)trace MATRIX
)trace List Integer
The first command traces all domains currently instantiated with Matrix. If additional domains are in-
stantiated with this constructor (for example, if you have used Matrix(Integer) and Matrix(Float)),
they will be automatically traced. The second command traces List(Integer). It is possible to trace
individual functions in a domain or package. See the )ops option below.
The following are the general options for the )trace command.
)break after causes a Common LISP break loop to be entered after exiting the traced function.
)break before causes a Common LISP break loop to be entered before entering the traced function.
)break is the same as )break before.
)count causes the system to keep a count of the number of times the traced function is entered. The
total can be displayed with )trace )stats and cleared with )trace )stats reset.
)count n causes information about the traced function to be displayed for the first n executions. After
the n th execution, the function is untraced.
)depth n causes trace information to be shown for only n levels of recursion of the traced function.
The command
will cause the display of only 10 levels of trace information for the recursive execution of a user
function fib.
)math causes the function arguments and return value to be displayed in the FriCAS monospace two-
dimensional math format.
)nonquietly causes the display of additional messages when a function is traced.
)nt This suppresses all normal trace information. This option is useful if the )count or )timer options
are used and you are interested in the statistics but not the function calling information.
)off causes untracing of all or specific functions. Without an argument, all functions, constructors,
domains and packages are untraced. Otherwise, the given functions and other objects are un-
traced. To immediately retrace the untraced functions, issue )trace )restore.
)only listOfDataToDisplay causes only specific trace information to be shown. The items are listed
by using the following abbreviations:
a display all arguments
v display return value
1 display first argument
2 display second argument
A.26. )TRACE 759
)restore causes the last untraced functions to be retraced. If additional options are present, they are
added to those previously in effect.
)stats causes the display of statistics collected by the use of the )count and )timer options.
)stats reset resets to 0 the statistics collected by the use of the )count and )timer options.
)timer causes the system to keep a count of execution times for the traced function. The total can
be displayed with )trace )stats and cleared with )trace )stats reset.
)varbreak var1 [... varN] causes a Common LISP break loop to be entered after the assignment to
any of the listed variables in the traced function.
)vars causes the display of the value of any variable after it is assigned in the traced function. Note
that library code must have been compiled (see Section A.7 on page 738) using the )vartrace
option in order to support this option.
)vars var1 [... varN] causes the display of the value of any of the specified variables after they are
assigned in the traced function. Note that library code must have been compiled (see Section
A.7 on page 738) using the )vartrace option in order to support this option.
)within executingFunction causes the display of trace information only if the traced function is called
when the given executingFunction is running.
The following are the options for tracing constructors, domains and packages.
)local [op1 [... opN]] causes local functions of the constructor to be traced. Note that to untrace
an individual local function, you must use the fully qualified internal name, using the escape
character “_” before the semicolon.
)ops op1 [... opN] By default, all operations from a domain or package are traced when the domain
or package is traced. This option allows you to specify that only particular operations should be
traced. The command
traces four operations from the domain Integer. Since + and - are special characters, it is
necessary to escape them with an underscore.
Also See: ‘)boot’ in Section A.3 on page 735, ‘)lisp’ in Section A.15 on page 750, and ‘)ltrace’ in
Section A.17 on page 750.
760 APPENDIX A. FRICAS SYSTEM COMMANDS
A.27 )undo
User Level Required: interpreter
Command Syntax:
)undo
)undo integer
)undo integer [option]
)undo )redo
where option is one of
)after
)before
Command Description:
This command is used to restore the state of the user environment to an earlier point in the interactive
session. The argument of an )undo is an integer which must designate some step number in the
interactive session.
)undo n
)undo n )after
These commands return the state of the interactive environment to that immediately after step n. If
n is a positive number, then n refers to step number n. If n is a negative number, it refers to the nth
previous command (that is, undoes the effects of the last −n commands).
A )clear all resets the )undo facility. Otherwise, an )undo undoes the effect of )clear with options
properties, value, and mode, and that of a previous undo. If any such system commands are given
between steps n and n + 1 (n > 0), their effect is undone for )undo m for any 0 < m ≤ n.
The command )undo is equivalent to )undo -1 (it undoes the effect of the previous user expression).
The command )undo 0 undoes any of the above system commands issued since the last user expression.
)undo n )before
This command returns the state of the interactive environment to that immediately before step n. Any
)undo or )clear system commands given before step n will not be undone.
)undo )redo
This command reads the file redo.input. created by the last )undo command. This file consists of
all user input lines, excluding those backtracked over due to a previous )undo.
The command )history )write will eliminate the “undone” command lines of your program.
Also See: ‘)history’ in Section A.13 on page 747.
A.28. )WHAT 761
A.28 )what
User Level Required: interpreter
Command Syntax:
)what categories pattern1 [pattern2 ...]
)what commands pattern1 [pattern2 ...]
)what domains pattern1 [pattern2 ...]
)what operations pattern1 [pattern2 ...]
)what packages pattern1 [pattern2 ...]
)what synonym pattern1 [pattern2 ...]
)what things pattern1 [pattern2 ...]
)apropos pattern1 [pattern2 ...]
Command Description:
This command is used to display lists of things in the system. The patterns are all strings and, if
present, restrict the contents of the lists. Only those items that contain one or more of the strings as
substrings are displayed. For example,
)what synonym
displays all command synonyms containing the substring “ver” or the substring “pr”. Output similar
to the following will be displayed
Also See: ‘)display’ in Section A.8 on page 743, ‘)set’ in Section A.21 on page 753, and ‘)show’ in
Section A.22 on page 753.
Appendix B
This appendix contains the FriCAS programs used to generate the images in the FriCAS Images color
insert of this book. All these input files are included with the FriCAS system. To produce the images
on page 6 of the FriCAS Images insert, for example, issue the command:
)read images6
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 FriCAS-generated PostScript output. The images were reproduced from slides
made on an Agfa ChromaScript PostScript interpreter with a Matrix Instruments QCR camera.
B.1 images1.input
1 ) read tknot -- Read torus knot program.
2
3 torusKnot (15 ,17 , 0.1 , 6 , 700) -- A (15,17) torus knot.
763
764 APPENDIX B. PROGRAMS FOR FRICAS IMAGES
B.2 images2.input
These images illustrate how Newton’s method converges when computing the 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.
1 ) read newton -- Read the programs from
2 ) read vectors -- Chapter 10.
3 f := newtonStep ( x ^3 - 2) -- Create a Newton’s iteration
4 -- function for x3 = 2.
B.3 images3.input
1 ) r tknot
2 for i in 0..4 repeat torusKnot (2 , 2 + i /4 , 0.5 , 25 , 250)
B.4 images5.input
The parameterization of the Etruscan Venus is due to George Frances.
1 venus (a ,r , steps ) ==
2 surf := ( u : DFLOAT , v : DFLOAT ): Point DFLOAT + - >
3 cv := cos ( v )
4 sv := sin ( v )
5 cu := cos ( u )
6 su := sin ( u )
7 x := r * cos (2* u ) * cv + sv * cu
8 y := r * sin (2* u ) * cv - sv * su
9 z := a * cv
10 point [x ,y , z ]
11 draw ( surf , 0..% pi , -% pi ..% pi , var1Steps == steps ,
12 var2Steps == steps , title == " Etruscan Venus ")
13
14 venus (5/2 , 13/10 , 50) -- The Etruscan Venus
The Figure-8 Klein Bottle parameterization is from “Differential Geometry and Computer Graphics”
by Thomas Banchoff, in Perspectives in Mathematics, Anniversary of Oberwolfasch 1984, Birkhäuser-
Verlag, Basel, pp. 43-60.
15 klein (x , y ) ==
16 cx := cos ( x )
17 cy := cos ( y )
18 sx := sin ( x )
19 sy := sin ( y )
20 sx2 := sin ( x /2)
21 cx2 := cos ( x /2)
22 sq2 := sqrt (2.0 @DFLOAT )
B.5. IMAGES6.INPUT 765
B.5 images6.input
1 gam (x , y ) == -- The height and color are the
2 g := Gamma complex (x , y ) -- real and argument parts
3 point [x ,y , max ( min ( real g , 4) , -4) , argument g ] -- of the Gamma function,
4 -- respectively.
5
6 draw ( gam , -% pi ..% pi , -% pi ..% pi , -- The Gamma Function
7 title == " Gamma ( x + % i * y )" , _
8 var1Steps == 100 , var2Steps == 100)
9
10 b (x , y ) == Beta (x , y )
11
12 draw (b , -3.1..3 , -3.1 .. 3 , title == " Beta (x , y )") -- The Beta Function
13
14 atf (x , y ) ==
15 a := atan complex (x , y )
16 point [x ,y , real a , argument a ]
17
18 draw ( atf , -3.0..% pi , -3.0..% pi ) -- The Arctangent function
766 APPENDIX B. PROGRAMS FOR FRICAS IMAGES
B.6 images7.input
First we look at the conformal map z 7→ z + 1/z.
1 ) read conformal -- Read program for drawing
2 -- conformal maps.
3
4 f z == z -- The coordinate grid for the
5 -- complex plane.
6 conformalDraw (f , -2..2 , -2..2 , 9 , 9 , " cartesian ") -- Mapping 1: Source
7
8 f z == z + 1/ z -- The map z 7→ z + 1/z
9
10 conformalDraw (f , -2..2 , -2..2 , 9 , 9 , " cartesian ") -- Mapping 1: Target
The map z 7→ −(z + 1)/(z − 1) maps the unit disk to the right half-plane, as shown on the Riemann
sphere.
11 f z == z -- The unit disk.
12
13 r i e m a n n C o n f o r m a l D r a w (f ,0.1..0.99 ,0..2*% pi ,7 ,11 ," polar ") -- Mapping 2: Source
14
15 f z == -( z +1)/( z -1) -- The map x 7→ −(z + 1)/(z − 1).
16 r i e m a n n C o n f o r m a l D r a w (f ,0.1..0.99 ,0..2*% pi ,7 ,11 ," polar ") -- Mapping 2: Target
17
18 r i e m a n n S p h er e D r a w ( -4..4 , -4..4 , 7 , 7 , " cartesian ") -- Riemann Sphere Mapping
B.7 images8.input
1 ) read dhtri
2 ) read tetra
3 drawPyramid 4 -- Sierpinsky’s Tetrahedron
4
5 \ index { Sierpinsky ’ s Tetrahedron }
6 ) read antoine
7 drawRings 2 -- Antoine’s Necklace
8
9 \ index { Antoine ’ s Necklace }
10 ) read scherk
11 drawScherk (3 ,3) -- Scherk’s Minimal Surface
12
13 \ index { Scherk ’ s minimal surface }
14 ) read ribbonsNew
15 drawRibbons ([ x ^ i for i in 1..5] , x = -1..1 , y =0..2) -- Ribbon Plot
B.8 conformal.input
The functions in this section draw conformal maps both on the plane and on the Riemann sphere.
1 C := Complex DoubleFloat -- Complex Numbers
2 S := Segment DoubleFloat -- Draw ranges
3 R3 := Point DFLOAT -- Points in 3-space
conformalDraw(f, rRange, tRange, rSteps, tSteps, coord) draws the image of the coordinate grid
under f in the complex plane. The grid may be given in either polar or Cartesian coordinates. Argument
f is the function to draw; rRange is the range of the radius (in polar) or real (in Cartesian); tRange is
B.8. CONFORMAL.INPUT 767
the range of θ (in polar) or imaginary (in Cartesian); tSteps, rSteps, are the number of intervals in the
r and θ directions; and coord is the coordinate system to use (either "polar" or "cartesian").
5 conformalDraw : ( C -> C , S , S , PI , PI , String ) -> VIEW3D
6 conformalDraw (f , rRange , tRange , rSteps , tSteps , coord ) ==
7 transformC := -- Function for changing an (x, y)
8 coord = " polar " = > polar2Complex -- pair into a complex number.
9 c a r t e s ia n 2 C o m p l e x
10 cm := m a k e C o n f o r m a l M a p (f , transformC )
11 sp := c r e a t e T h r e e S p a c e () -- Create a fresh space.
12 adaptGrid ( sp , cm , rRange , tRange , rSteps , tSteps ) -- Plot the coordinate lines.
13 makeV iewport 3D ( sp , " Conformal Map ") -- Draw the image.
riemannConformalDraw(f, rRange, tRange, rSteps, tSteps, coord) draws the image of the coordinate
grid under f on the Riemann sphere. The grid may be given in either polar or Cartesian coordinates.
Its arguments are the same as those for conformalDraw.
14 r i e m a n n C o n f o r m a l D r a w :( C - >C ,S ,S , PI , PI , String ) - > VIEW3D
15 r i e m a n n C o n f o r m a l D r a w (f , rRange , tRange ,
16 rSteps , tSteps , coord ) ==
17 transformC := -- Function for changing an (x, y)
18 coord = " polar " = > polar2Complex -- pair into a complex number.
19 c a r t e s ia n 2 C o m p l e x
20 sp := c r e a t e T h r e e S p a c e () -- Create a fresh space.
21 cm := m a k e R i e m a n n C o n f o r m a l M a p (f , transformC )
22 adaptGrid ( sp , cm , rRange , tRange , rSteps , tSteps ) -- Plot the coordinate lines.
23 curve ( sp ,[ point [0 ,0 ,2.0 @DFLOAT ,0] , point [0 ,0 ,2.0 @DFLOAT ,0]]) -- Add an invisible point at
24 makeV iewport 3D ( sp ," Map on the Riemann Sphere ") -- the north pole for scaling.
25
26 adaptGrid ( sp , f , uRange , vRange , uSteps , vSteps ) == -- Plot the coordinate grid
27 delU := ( high ( uRange ) - low ( uRange ))/ uSteps -- using adaptive plotting for
28 delV := ( high ( vRange ) - low ( vRange ))/ vSteps -- coordinate lines, and draw
29 uSteps := uSteps + 1; vSteps := vSteps + 1 -- tubes around the lines.
30 u := low uRange
31 for i in 1.. uSteps repeat -- Draw coordinate lines in the v
32 c := curryLeft (f , u ) -- direction; curve c fixes the
33 cf := ( t : DFLOAT ): DFLOAT + - > 0 -- current value of u.
34 makeObject (c , vRange :: SEG Float , colorFunction == cf , -- Draw the v coordinate line.
35 space == sp , tubeRadius == .02 , tubePoints == 6)
36 u := u + delU
37 v := low vRange
38 for i in 1.. vSteps repeat -- Draw coordinate lines in the u
39 c := curryRight (f , v ) -- direction; curve c fixes the
40 cf := ( t : DFLOAT ): DFLOAT + - > 1 -- current value of v.
41 makeObject (c , uRange :: SEG Float , colorFunction == cf , -- Draw the u coordinate line.
42 space == sp , tubeRadius == .02 , tubePoints == 6)
43 v := v + delV
44 void ()
45
46 r i e m a n n T r a ns f o rm ( z ) == -- Map a point in the complex
47 r := sqrt norm z -- plane to the Riemann sphere.
48 cosTheta := ( real z )/ r
49 sinTheta := ( imag z )/ r
50 cp := 4* r /(4+ r ^2)
51 sp := sqrt (1 - cp * cp )
52 if r >2 then sp := - sp
53 point [ cosTheta * cp , sinTheta * cp , - sp + 1]
54
55 c a r t e s i a n 2 Co m p l e x ( r : DFLOAT , i : DFLOAT ): C == -- Convert Cartesian coordinates to
56 complex (r , i ) -- complex Cartesian form.
57
58 polar2Complex ( r : DFLOAT , th : DFLOAT ): C == -- Convert polar coordinates to
768 APPENDIX B. PROGRAMS FOR FRICAS IMAGES
B.9 tknot.input
Create a (p, q) torus-knot with radius r around the curve. The formula was derived by Larry Lambe.
1 ) read ntube
2 torusKnot : ( DFLOAT , DFLOAT , DFLOAT , PI , PI ) -> VIEW3D
3 torusKnot (p , q ,r , uSteps , tSteps ) ==
4 knot := ( t : DFLOAT ): Point DFLOAT + - > -- Function for the torus knot.
5 fac := 4/(2.2 @DFLOAT - sin ( q * t ))
6 fac * point [ cos ( p * t ) , sin ( p * t ) , cos ( q * t )]
7 circle := ( u : DFLOAT , t : DFLOAT ): Point DFLOAT + - > -- The cross section.
8 r * point [ cos u , sin u ]
9 ntubeDrawOpt ( knot , circle , 0..2*% pi , 0..2*% pi , -- Draw the circle around the knot.
10 var1Steps == uSteps , var2Steps == tSteps )
B.10 ntube.input
The functions in this file create generalized tubes (also known as generalized cylinders). These functions
draw a 2-d curve in the normal planes around a 3-d curve.
1 R3 := Point DFLOAT -- Points in 3-Space
2 R2 := Point DFLOAT -- Points in 2-Space
3 S := Segment Float -- Draw ranges
4 -- Introduce types for functions for:
5 ThreeCurve := DFLOAT -> R3 -- —the space curve function
6 TwoCurve := ( DFLOAT , DFLOAT ) -> R2 -- —the plane curve function
7 Surface := ( DFLOAT , DFLOAT ) -> R3 -- —the surface function
8 -- Frenet frames define a
9 FrenetFrame := -- coordinate system around a
10 Record ( value : R3 , tangent : R3 , normal : R3 , binormal : R3 ) -- point on a space curve.
11 frame : FrenetFrame -- The current Frenet frame
12 -- for a point on a curve.
ntubeDraw(spaceCurve, planeCurve, u0 ..u1 , t0 ..t1 ) draws planeCurve in the normal planes of space-
Curve. The parameter u0 ..u1 specifies the parameter range for planeCurve and t0 ..t1 specifies the
parameter range for spaceCurve. Additionally, the plane curve function takes a second parameter: the
current parameter of spaceCurve. This allows the plane curve to change shape as it goes around the
space curve. See Section B.4 on page 764 for an example of this.
13 ntubeDraw : ( ThreeCurve , TwoCurve ,S , S ) -> VIEW3D
14 ntubeDraw ( spaceCurve , planeCurve , uRange , tRange ) ==
15 ntubeDrawOpt ( spaceCurve , planeCurve , uRange , _
16 tRange , [] $ List DROPT )
17
18 ntubeDrawOpt : ( ThreeCurve , TwoCurve ,S ,S , List DROPT )
19 -> VIEW3D
20 ntubeDrawOpt ( spaceCurve , planeCurve , uRange , tRange , l ) == -- This function is similar
21 -- to ntubeDraw, but takes
22 delT : DFLOAT := ( high ( tRange ) - low ( tRange ))/10000 -- optional parameters that it
23 oldT : DFLOAT := low ( tRange ) - 1 -- passes to the draw command.
24 fun := ngeneralTube ( spaceCurve , planeCurve , delT , oldT )
25 draw ( fun , uRange , tRange , l )
nfrenetFrame(c, t, delT) numerically computes the Frenet frame about the curve c at t. Parameter
delT is a small number used to compute derivatives.
27 nfrenetFrame (c , t , delT ) ==
770 APPENDIX B. PROGRAMS FOR FRICAS IMAGES
28 f0 := c ( t )
29 f1 := c ( t + delT )
30 t0 := f1 - f0 -- The tangent.
31 n0 := f1 + f0
32 b := cross ( t0 , n0 ) -- The binormal.
33 n := cross (b , t0 ) -- The normal.
34 ln := length n
35 lb := length b
36 ln = 0 or lb = 0 = >
37 error " Frenet Frame not well defined "
38 n := (1/ ln )* n -- Make into unit length vectors.
39 b := (1/ lb )* b
40 [ f0 , t0 , n , b ] $ FrenetFrame
ngeneralTube(spaceCurve, planeCurve,delT, oltT) creates a function that can be passed to the system
draw command. The function is a parameterized surface for the general tube around spaceCurve. delT
is a small number used to compute derivatives. oldT is used to hold the current value of the t parameter
for spaceCurve. This is an efficiency measure to ensure that frames are only computed once for each
value of t.
41 ngeneralTube : ( ThreeCurve , TwoCurve , DFLOAT , DFLOAT ) -> Surface
42 ngeneralTube ( spaceCurve , planeCurve , delT , oldT ) ==
43 free frame -- Indicate that frame is global.
44 ( v : DFLOAT , t : DFLOAT ): R3 + - >
45 if ( t ~= oldT ) then -- If not already computed,
46 frame := nfrenetFrame ( spaceCurve , t , delT ) -- compute new frame.
47 oldT := t
48 p := planeCurve (v , t )
49 frame . value + p .1* frame . normal + p .2* frame . binormal -- Project p into the normal plane.
B.11 dhtri.input
Create affine transformations (DH matrices) that transform a given triangle into another.
1 tri2tri : ( List Point DFLOAT , List Point DFLOAT ) -> DHMATRIX ( DFLOAT )
2 -- Compute a DHMATRIX that
3 tri2tri ( t1 , t2 ) == -- transforms t1 to t2, where
4 n1 := tri angleNor mal ( t1 ) -- t1 and t2 are the vertices
5 n2 := tri angleNor mal ( t2 ) -- of two triangles in 3-space.
6 tet2tet ( concat ( t1 , n1 ) , concat ( t2 , n2 ))
7
8 tet2tet : ( List Point DFLOAT , List Point DFLOAT ) -> DHMATRIX ( DFLOAT )
9 -- Compute a DHMATRIX that
10 tet2tet ( t1 , t2 ) == -- transforms t1 to t2,
11 m1 := m a k e C o l u m n M a t r i x t1 -- where t1 and t2 are the
12 m2 := m a k e C o l u m n M a t r i x t2 -- vertices of two tetrahedrons
13 m2 * inverse ( m1 ) -- in 3-space.
14
15 m a k e C o l u m n Ma t r ix ( t ) == -- Put the vertices of a tetra-
16 m := new (4 ,4 ,0) $ DHMATRIX ( DFLOAT ) -- hedron into matrix form.
17 for x in t for i in 1.. repeat
18 for j in 1..3 repeat
19 m (j , i ) := x . j
20 m (4 , i ) := 1
21 m
22
23 tria ngleNorm al ( t ) == -- Compute a vector normal to
24 a := triangleArea t -- the given triangle, whose
B.12. TETRA.INPUT 771
B.12 tetra.input
1 ) set expose add con D e n a v i t H a r t e n b e r g M a t r i x -- Bring DH matrices into the
2 -- environment.
3 x1 : DFLOAT := sqrt (2.0 @DFLOAT /3.0 @DFLOAT ) -- Set up the coordinates of the
4 x2 : DFLOAT := sqrt (3.0 @DFLOAT )/6 -- corners of the tetrahedron.
5
6 z := 0.0 @DFLOAT
7 h := 0.5 @DFLOAT
8
9 p1 := point [ -h , -x2 , z ] -- Some needed points.
10 p2 := point [h , -x2 , z ]
11 p3 := point [z , 2* x2 , z ]
12 p4 := point [z , z , x1 ]
13
14 baseTriangle := [ p2 , p1 , p3 ] -- The base of the tetrahedron.
15
16 mt := [ h *( p2 + p1 ) , h *( p1 + p3 ) , h *( p3 + p2 )] -- The “middle triangle” inscribed
17 -- in the base of the tetrahedron.
18 bt1 := [ mt .1 , p1 , mt .2] -- The bases of the triangles of
19 bt2 := [ p2 , mt .1 , mt .3] -- the subdivided tetrahedron.
20 bt3 := [ mt .2 , p3 , mt .3]
21 bt4 := [ h *( p2 + p4 ) , h *( p1 + p4 ) , h *( p3 + p4 )]
22
23 tt1 := tri2tri ( baseTriangle , bt1 ) -- Create the transformations
24 tt2 := tri2tri ( baseTriangle , bt2 ) -- that bring the base of the
25 tt3 := tri2tri ( baseTriangle , bt3 ) -- tetrahedron to the bases of
26 tt4 := tri2tri ( baseTriangle , bt4 ) -- the subdivided tetrahedron.
27
28 drawPyramid ( n ) == -- Draw a Sierpinsky tetrahedron
29 s := c r e a t e T h r e e S p a c e () -- with n levels of recursive
30 dh := rotatex (0.0 @DFLOAT ) -- subdivision.
31 d r a w P y r a mi d I n n e r (s , n , dh )
32 makeV iewport 3D (s , " Sierpinsky Tetrahedron ")
33
34 d r a w P y r a m i dI n n er (s , n , dh ) == -- Recursively draw a Sierpinsky
35 n = 0 = > ma ke Te t ra he dr o n (s , dh , n ) -- tetrahedron.
36 d r a w P y r a mi d I n n e r (s , n -1 , dh * tt1 ) -- Draw the 4 recursive pyramids.
37 d r a w P y r a mi d I n n e r (s , n -1 , dh * tt2 )
38 d r a w P y r a mi d I n n e r (s , n -1 , dh * tt3 )
39 d r a w P y r a mi d I n n e r (s , n -1 , dh * tt4 )
40
41 m ak eT et r ah ed ro n ( sp , dh , color ) == -- Draw a tetrahedron into the
42 w1 := dh * p1 -- given space with the given
772 APPENDIX B. PROGRAMS FOR FRICAS IMAGES
43 w2 := dh * p2 -- color, transforming it by
44 w3 := dh * p3 -- the given DH matrix.
45 w4 := dh * p4
46 polygon ( sp , [ w1 , w2 , w4 ])
47 polygon ( sp , [ w1 , w3 , w4 ])
48 polygon ( sp , [ w2 , w3 , w4 ])
49 void ()
B.13 antoine.input
Draw Antoine’s Necklace. Thank you to Matthew Grayson at IBM’s T.J Watson Research Center for
the idea.
1 ) set expose add con D e n a v i t H a r t e n b e r g M a t r i x -- Bring DH matrices into
2 -- the environment.
3 torusRot : DHMATRIX ( DFLOAT ) -- The current transformation for
4 -- drawing a sub ring.
5
6 drawRings ( n ) == -- Draw Antoine’s Necklace with n
7 s := c r e at e T h r e e S p a c e () -- levels of recursive subdivision.
8 dh : DHMATRIX ( DFLOAT ) := identity () -- The number of subrings is 10n .
9 drawR ingsInn er (s , n , dh ) -- Do the real work.
10 makeV iewport 3D (s , " Antoine ’ s Necklace ")
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
DHMATRIX operations are used to build up the proper matrix composing all these transformations.
12 F == > DFLOAT
13 draw RingsInn er (s , n , dh ) == -- Recursively draw Antoine’s
14 n = 0 => -- Necklace.
15 drawRing (s , dh )
16 void ()
17 t := 0.0 @F -- Angle around ring.
18 p := 0.0 @F -- Angle of subring from plane.
19 tr := 1.0 @F -- Amount to translate subring.
20 inc := 0.1 @F -- The translation increment.
21 for i in 1..10 repeat -- Subdivide into 10 linked rings.
22 tr := tr + inc
23 inc := - inc
24 dh ’ := dh * rotatez ( t )* translate ( tr ,0.0 @F ,0.0 @F )* -- Transform ring in center
25 rotatey ( p )* scale (0.35 @F , 0.48 @F , 0.4 @F ) -- to a link.
26 drawR ingsInn er (s , n -1 , dh ’)
27 t := t + 36.0 @F
28 p := p + 90.0 @F
29 void ()
30
31 drawRing (s , dh ) == -- Draw a single ring into
32 free torusRot -- the given subspace,
33 torusRot := dh -- transformed by the given
34 makeObject ( torus , 0..2*% pi , 0..2*% pi , var1Steps == 6 , -- DHMATRIX.
35 space == s , var2Steps == 15)
36
37 torus ( u ,v ) == -- Parameterization of a torus,
38 cu := cos ( u )/6 -- transformed by the
39 torusRot * point [(1+ cu )* cos ( v ) ,(1+ cu )* sin ( v ) ,( sin u )/6] -- DHMATRIX in torusRot.
B.14. SCHERK.INPUT 773
B.14 scherk.input
Scherk’s minimal surface, defined by: ez cos(x) = cos(y). See: A Comprehensive Introduction to
Differential Geometry, Vol. 3, by Michael Spivak, Publish Or Perish, Berkeley, 1979, pp. 249-252.
1 ( xOffset , yOffset ): DFLOAT -- Offsets for a single piece
2 -- of Scherk’s minimal surface.
3
4 drawScherk (m , n ) == -- Draw Scherk’s minimal surface
5 free xOffset , yOffset -- on an m by n patch.
6 space := c r e a t e T h r e e S p ac e ()
7 for i in 0.. m -1 repeat
8 xOffset := i *% pi
9 for j in 0 .. n -1 repeat
10 rem ( i +j , 2) = 0 = > ’ iter -- Draw only odd patches.
11 yOffset := j *% pi
12 drawOneScherk ( space ) -- Draw a patch.
13 makeV iewport 3D ( space , " Scherk ’ s Minimal Surface ")
14
15 scherk1 (u , v ) == -- The first patch that makes
16 x := cos ( u )/ exp ( v ) -- up a single piece of
17 point [ xOffset + acos ( x ) , yOffset + u , v , abs ( v )] -- Scherk’s minimal surface.
18
19 scherk2 (u , v ) == -- The second patch.
20 x := cos ( u )/ exp ( v )
21 point [ xOffset - acos ( x ) , yOffset + u , v , abs ( v )]
22
23 scherk3 (u , v ) == -- The third patch.
24 x := exp ( v ) * cos ( u )
25 point [ xOffset + u , yOffset + acos ( x ) , v , abs ( v )]
26
27 scherk4 (u , v ) == -- The fourth patch.
28 x := exp ( v ) * cos ( u )
29 point [ xOffset + u , yOffset - acos ( x ) , v , abs ( v )]
30
31 drawOneScherk ( s ) == -- Draw the surface by
32 makeObject ( scherk1 , -% pi /2..% pi /2 ,0..% pi /2 , space == s , -- breaking it into four
33 var1Steps == 28 , var2Steps == 28) -- patches and then drawing
34 makeObject ( scherk2 , -% pi /2..% pi /2 ,0..% pi /2 , space == s , -- the patches.
35 var1Steps == 28 , var2Steps == 28)
36 makeObject ( scherk3 , -% pi /2..% pi /2 , -% pi /2..0 , space == s ,
37 var1Steps == 28 , var2Steps == 28)
38 makeObject ( scherk4 , -% pi /2..% pi /2 , -% pi /2..0 , space == s ,
39 var1Steps == 28 , var2Steps == 28)
40 void ()
Index
774
INDEX 775
undo, 62
Union, 79
Union, 43
union, 79
difference from record, 82
selector, 82
user-level, 704, 705, 733, 761
weight, 205
where , 651, 671
while , 133, 136
wild card, 690
window, 21
with , 651, 662, 670