This notebook is licenced under CC BY-SA 4.0.

# FriCAS Tutorial (First Steps)¶

## Ralf Hemmecke <ralf@hemmecke.org>¶

Sources at Github.

In [1]:
)set message type off
)set output algebra off
setFormat!(FormatMathJax)$JFriCASSupport )set message type on  In [2]: )version  Value = "FriCAS a9422d32eb6f6b03d98ac6adfc9bf05ec0f5e8bd compiled at Sa 03 Apr 2021 00:29:13 CEST"  ## General remarks¶ FriCAS is a typed computer algebra system. In this notebook we evaluate certain expressions. Each expression is evaluated and yields a value that belongs to a certain type. This type is shown at the right hand side after the value. Note that this type is a hyperlink that leads to its description. By convention, types in FriCAS begin with a capital letter. Functions and variables are usually start with a small letter. ## FriCAS as a Pocket Calculator¶ Type an expression into a cell and press SHIFT-ENTER. In [2]: 1+1  Out[2]: $2$ In [3]: 1-1  Out[3]: $0$ In [4]: -1  Out[4]: $-1$ Everything in FriCAS has a type. The FriCAS interpreter guesses the most appropriate type. For simple things types do not matter much. Apart from the above integer domains, there are rational numbers and floating point numbers, complex integers, complex floats, etc. In [5]: 2/3  Out[5]: $\frac{2}{3}$ In [6]: 3/6  Out[6]: $\frac{1}{2}$ In [7]: 2/3 + 1/5 * (- 2/11)  Out[7]: $\frac{104}{165}$ In [8]: 2^10  Out[8]: $1024$ FriCAS can compute with arbitrarily big numerical values. Only memory and time set the limits. In [9]: factorial(100)  Out[9]: $93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000$ By default 20 digits are used for floating point computation. In [10]: 2/3 + 1.0  Out[10]: $1.6666666666666666667$ By using the digits function, one can query and set the number of digits that are used during the computation. By default, a fraction is expressed in the most appropriate domain, which would be Fraction(Integer). Coercion into the appropriate type is done via the :: operator. In [14]: digits 40 22/7 :: Float digits(20) 22/7 :: Float  Out[14]: $20$ Out[14]: $3.142857142857142857142857142857142857143$ Out[14]: $40$ Out[14]: $3.1428571428571428571$ A number that contains a dot, is automatically a member of the floating point domain. So the following fraction is computed within the respective domain, namely, Float. In [15]: 22/7.0  Out[15]: $3.1428571428571428571$ In [16]: sqrt(2.0)  Out[16]: $1.4142135623730950488$ For integer arguments, it is not clear what the user actually wants. So the expression remains unevaluated. Note that we get AlgebraicNumber as yet another number type. In [17]: sqrt(3)  Out[17]: $\sqrt{3}$ In fact, AlgebraicNumber is a step into the direction of computing with symbols rather than just numbers. In [18]: sqrt(2)+sqrt(3)  Out[18]: $\sqrt{3}+\sqrt{2}$ FriCAS can also deal with complex numbers. The symbol %i denotes the imaginary unit. Here we have Gaussian integers. In [19]: 2+3*%i  Out[19]: $2+3\, i$ As with integers, the resulting type is appropriately chosen, i.e. "complex rational numbers". In [20]: (2 + 3*%i) / (3 + 5*%i)  Out[20]: $\frac{21}{34}-\frac{1}{34}\, i$ As with real numbers where Float is the corresponding domain in FriCAS, complex numbers can only be modelled approximately on a computer. In [21]: sqrt(2.0) * (1 + 2.0*%i)  Out[21]: $1.4142135623730950488+2.8284271247461900976\, i$ Not everything can be done with floating point numbers. FriCAS does not automatically extend the number domain from real numbers to complex numbers. It rather considers Float as a domain with partial operations, i.e. operations that might fail on certain input. In [22]: sqrt(5.0)  Out[22]: $2.2360679774997896964$ In [21]: sqrt(-5.0)   >> Error detected within library code: sqrt: negative argument: -5.0  But we can convert an algebraic number into a complex floating point number. In [24]: sqrt(-5) sqrt(-5) :: Complex(Float)  Out[24]: $\sqrt{-5}$ Out[24]: $2.2360679774997896964\, i$ There are a lot of functions that can be used with floating point numbers. Note that in the following list % is an abbreviation of "this domain", i.e. Float in our case. The question mark is just used as a placeholder for an argument. In [23]: )show Float   Float is a domain constructor. Abbreviation for Float is FLOAT This constructor is exposed in this frame. 127 Names for 171 Operations in this Domain. ------------------------------- Operations -------------------------------- ?*? : (Integer, %) -> % ?*? : (PositiveInteger, %) -> % ?*? : (%, %) -> % ?+? : (%, %) -> % ?-? : (%, %) -> % -? : % -> % ?/? : (%, Integer) -> % ?/? : (%, %) -> % ?<? : (%, %) -> Boolean ?<=? : (%, %) -> Boolean ?=? : (%, %) -> Boolean ?>? : (%, %) -> Boolean ?>=? : (%, %) -> Boolean D : (%, NonNegativeInteger) -> % D : % -> % OMwrite : (%, Boolean) -> String OMwrite : % -> String 1 : () -> % 0 : () -> % ?^? : (%, Integer) -> % ?^? : (%, PositiveInteger) -> % ?^? : (%, %) -> % abs : % -> % acos : % -> % acosh : % -> % acot : % -> % acoth : % -> % acsc : % -> % acsch : % -> % annihilate? : (%, %) -> Boolean antiCommutator : (%, %) -> % asec : % -> % asech : % -> % asin : % -> % asinh : % -> % associates? : (%, %) -> Boolean associator : (%, %, %) -> % atan : (%, %) -> % atan : % -> % atanh : % -> % base : () -> PositiveInteger bits : () -> PositiveInteger ceiling : % -> % coerce : % -> DoubleFloat coerce : % -> OutputForm coerce : Fraction(Integer) -> % coerce : Integer -> % coerce : % -> % commutator : (%, %) -> % convert : % -> DoubleFloat convert : % -> Float convert : % -> InputForm convert : % -> Pattern(Float) convert : % -> String convert : DoubleFloat -> % cos : % -> % cosh : % -> % cot : % -> % coth : % -> % csc : % -> % csch : % -> % differentiate : % -> % digits : () -> PositiveInteger exp : % -> % exp1 : () -> % exponent : % -> Integer factor : % -> Factored(%) float : (Integer, Integer) -> % floor : % -> % fractionPart : % -> % gcd : List(%) -> % gcd : (%, %) -> % hash : % -> SingleInteger inv : % -> % latex : % -> String lcm : List(%) -> % lcm : (%, %) -> % log : % -> % log10 : % -> % log10 : () -> % log2 : % -> % log2 : () -> % mantissa : % -> Integer max : (%, %) -> % min : (%, %) -> % negative? : % -> Boolean norm : % -> % normalize : % -> % nthRoot : (%, Integer) -> % one? : % -> Boolean opposite? : (%, %) -> Boolean order : % -> Integer outputFixed : () -> Void outputFloating : () -> Void outputGeneral : () -> Void pi : () -> % positive? : % -> Boolean precision : () -> PositiveInteger prime? : % -> Boolean ?quo? : (%, %) -> % recip : % -> Union(%,"failed") relerror : (%, %) -> % ?rem? : (%, %) -> % retract : % -> Fraction(Integer) retract : % -> Integer round : % -> % sample : () -> % sec : % -> % sech : % -> % shift : (%, Integer) -> % sign : % -> Integer sin : % -> % sinh : % -> % sizeLess? : (%, %) -> Boolean smaller? : (%, %) -> Boolean sqrt : % -> % squareFree : % -> Factored(%) squareFreePart : % -> % tan : % -> % tanh : % -> % toString : % -> String truncate : % -> % unit? : % -> Boolean unitCanonical : % -> % wholePart : % -> Integer zero? : % -> Boolean ?~=? : (%, %) -> Boolean ?*? : (Fraction(Integer), %) -> % ?*? : (NonNegativeInteger, %) -> % ?*? : (%, Fraction(Integer)) -> % OMwrite : (OpenMathDevice, %, Boolean) -> Void OMwrite : (OpenMathDevice, %) -> Void ?^? : (%, Fraction(Integer)) -> % ?^? : (%, NonNegativeInteger) -> % bits : PositiveInteger -> PositiveInteger characteristic : () -> NonNegativeInteger decreasePrecision : Integer -> PositiveInteger differentiate : (%, NonNegativeInteger) -> % digits : PositiveInteger -> PositiveInteger divide : (%, %) -> Record(quotient: %,remainder: %) euclideanSize : % -> NonNegativeInteger expressIdealMember : (List(%), %) -> Union(List(%),"failed") exquo : (%, %) -> Union(%,"failed") extendedEuclidean : (%, %) -> Record(coef1: %,coef2: %,generator: %) extendedEuclidean : (%, %, %) -> Union(Record(coef1: %,coef2: %),"failed") float : (Integer, Integer, PositiveInteger) -> % gcdPolynomial : (SparseUnivariatePolynomial(%), SparseUnivariatePolynomial(%)) -> SparseUnivariatePolynomial(%) hashUpdate! : (HashState, %) -> HashState increasePrecision : Integer -> PositiveInteger lcmCoef : (%, %) -> Record(llcm_res: %,coeff1: %,coeff2: %) leftPower : (%, NonNegativeInteger) -> % leftPower : (%, PositiveInteger) -> % leftRecip : % -> Union(%,"failed") multiEuclidean : (List(%), %) -> Union(List(%),"failed") outputFixed : NonNegativeInteger -> Void outputFloating : NonNegativeInteger -> Void outputGeneral : NonNegativeInteger -> Void outputSpacing : NonNegativeInteger -> Void patternMatch : (%, Pattern(Float), PatternMatchResult(Float,%)) -> PatternMatchResult(Float,%) precision : PositiveInteger -> PositiveInteger principalIdeal : List(%) -> Record(coef: List(%),generator: %) rationalApproximation : (%, NonNegativeInteger, NonNegativeInteger) -> Fraction(Integer) rationalApproximation : (%, NonNegativeInteger) -> Fraction(Integer) retractIfCan : % -> Union(Fraction(Integer),"failed") retractIfCan : % -> Union(Integer,"failed") rightPower : (%, NonNegativeInteger) -> % rightPower : (%, PositiveInteger) -> % rightRecip : % -> Union(%,"failed") subtractIfCan : (%, %) -> Union(%,"failed") toString : (%, NonNegativeInteger) -> String unitNormal : % -> Record(unit: %,canonical: %,associate: %)  FriCAS can be used as a numerical engine. In [25]: tan(sin(1.0)*exp(3.5))  Out[25]: $-0.43301751741640407036$ In [26]: log(abs(-3.0*sin(2*3.1415)))  Out[26]: $-7.4948833967339587459$ ## Computation with symbols¶ Entering variables is as easy as in most other CAS. In [27]: p:=4*x^2+4*x+1  Out[27]: $4\, {x}^{2}+4\, x+1$ Note that the resulting domain of the factor operation is not Polynomial(Integer). In [28]: factor(p)  Out[28]: ${\left(2\, x+1\right)}^{2}$ The domain Factored(X) keeps its elements in a factored form as long as possible. In [29]: f:=factor(x^2-1)  Out[29]: $\left(x-1\right)\, \left(x+1\right)$ In [30]: g:=f*(x-1)  Out[30]: ${\left(x-1\right)}^{2}\, \left(x+1\right)$ In [31]: h:=g+1  Out[31]: ${x}^{3}-{x}^{2}-x+2$ In [32]: h-1  Out[32]: ${\left(x-1\right)}^{2}\, \left(x+1\right)$ Since in a rational function field any element is a unit, the concept of factorization does not do anything. But there is a function factorFraction that factors the numerator and denominator separately. In [34]: r := (x^2+2*x+1)/(x^2-9) factor r  Out[34]: $\frac{{x}^{2}+2\, x+1}{{x}^{2}-9}$ Out[34]: $\frac{{x}^{2}+2\, x+1}{{x}^{2}-9}$ In [35]: factorFraction r  Out[35]: $\frac{{\left(x+1\right)}^{2}}{\left(x-3\right)\, \left(x+3\right)}$ FriCAS knows about the standard mathematical functions and can do computations with them. In [36]: sin(x)*exp(x)  Out[36]: ${e}^{x}\, \sin\left(x\right)$ Some mathematical constants and their properties are built-in. In [37]: %e  Out[37]: $e$ In [38]: %pi  Out[38]: $\pi$ In [39]: %e^(%pi * %i)  Out[39]: $-1$ ## Expressions vs. specific types¶ Eagerness of evaluation of an expression depends on its type. In fact, each type defines a certain normal form and the expression is simply stored in this form. In [40]: (x^100 + 1)*(x^100-1)  Out[40]: ${x}^{200}-1$ In [41]: (x^50-1)/(x-1)  Out[41]: ${x}^{49}+{x}^{48}+{x}^{47}+{x}^{46}+{x}^{45}+{x}^{44}+{x}^{43}+{x}^{42}+{x}^{41}+{x}^{40}+{x}^{39}+{x}^{38}+{x}^{37}+{x}^{36}+{x}^{35}+{x}^{34}+{x}^{33}+{x}^{32}+{x}^{31}+{x}^{30}+{x}^{29}+{x}^{28}+{x}^{27}+{x}^{26}+{x}^{25}+{x}^{24}+{x}^{23}+{x}^{22}+{x}^{21}+{x}^{20}+{x}^{19}+{x}^{18}+{x}^{17}+{x}^{16}+{x}^{15}+{x}^{14}+{x}^{13}+{x}^{12}+{x}^{11}+{x}^{10}+{x}^{9}+{x}^{8}+{x}^{7}+{x}^{6}+{x}^{5}+{x}^{4}+{x}^{3}+{x}^{2}+x+1$ The domain Expression(Integer) is similar to the way expressions are stored in other computer algebra systems. If FriCAS does not find a more appropriate interpretation for an expresssion, the expression often ends up in being of type Expression(Integer). In [42]: sin(%pi/3)  Out[42]: $\frac{\sqrt{3}}{2}$ In [43]: e := sin(x)^2 + cos(x)^2  Out[43]: ${\left(\sin\left(x\right)\right)}^{2}+{\left(\cos\left(x\right)\right)}^{2}$ Some expressions are not automatically simplified. In [44]: simplify(e)  Out[44]: $1$ In some cases, it is simply not clear what a "simpler expression" actually means. In [45]: simplify(sin(2*x))  Out[45]: $\sin\left(2\, x\right)$ In [46]: simplify(2*sin(x)*cos(x))  Out[46]: $2\, \cos\left(x\right)\, \sin\left(x\right)$ ## Variables, Assignments, Equations, Declarations¶ In addition to accessing previoiusly computed values via the %%(n) mechanism, intermediate results can also be stored in variables. In [47]: a := 1/3 + 22/7  Out[47]: $\frac{73}{21}$ In [48]: a  Out[48]: $\frac{73}{21}$ Assignment is done via :=. A simple = sign just creates an equation. In [49]: eq := A = 1/3 + 22/7  Out[49]: $A=\frac{73}{21}$ FriCAS is case-sensitive. In [50]: A  Out[50]: $A$ In [51]: A = lhs(eq)  Out[51]: $A=A$ In order to see whether an equation is true or false, we must turn it into a boolean. In [52]: (A=lhs(eq))::Boolean  Out[52]: $\texttt{true}$ In [53]: (A=10)::Boolean  Out[53]: $\texttt{false}$ The type of a variable can be declared in advance. Its type is then fixed for the whole session. In [54]: v: PositiveInteger  Out[54]: If a variable has been declared, it is no longer automatically converted to an indeterminate that can be used in an expression. In [53]: 5*v   v is declared as being in PositiveInteger but has not been given a value.  One would have to prepend an apostroph to refer to a symbol of that name. In [55]: 5 * 'v  Out[55]: $5\, v$ Only values that belong to the respective type can be assigned to the variable. In [55]: v := -1  Compiling function G843 with type Integer -> Boolean Cannot convert right-hand side of assignment - 1 to an object of the type PositiveInteger of the left-hand side.  In [56]: v := 1  Out[56]: $1$ ## Functions¶ Functions, are first class objects, they can be assigned to variables and can be used as arguments of functions. The operator +-> is used to created anonymous functions, i.e. lambda expressions. In [57]: f := x +-> sin(x)*exp(x)  Out[57]: $x\mapsto \sin\left(x\right)\, \operatorname{exp}\left(x\right)$ In [58]: f(%pi/3)  Out[58]: $\frac{\sqrt{3}\, {e}^{\frac{\pi }{3}}}{2}$ Simply using an expression in a functional way makes no sense. In [59]: g := sin(x)*exp(x)  Out[59]: ${e}^{x}\, \sin\left(x\right)$ In [60]: g(%pi/2)  There are no library operations named g Use HyperDoc Browse or issue )what op g to learn if there is any operation containing " g " in its name. Cannot find a definition or applicable library operation named g with argument type(s) Pi Perhaps you should use "@" to indicate the required return type, or "$" to
specify which version of the function you need.

In [60]:
eval(g, x=%pi/2)

Out[60]:
${e}^{\frac{\pi }{2}}$

Declaring the type of a function explicitly, restricts the way the function can be used.

In [61]:
f1: Integer -> Integer

Out[61]:
In [62]:
f1 := x +-> gcd(x,x+6)

Out[62]:
$\operatorname{theMap}(anonymousFunction)$
In [63]:
f1(18)

Out[63]:
$6$

Since the functions has been declared for integer arguments, it cannot be used with floating point arguments.

In [65]:
f1(2.3)

There are no library operations named f1
Use HyperDoc Browse or issue
)what op f1
to learn if there is any operation containing " f1 " in its name.
Cannot find a definition or applicable library operation named f1 with
argument type(s)
Float

Perhaps you should use "@" to indicate the required return type, or "\$" to
specify which version of the function you need.


Functions can also be defined via the "delayed assignment" using ==.

In [64]:
f2(x: Integer): String == reverse(string(x))

Function declaration f2 : Integer -> String has been added to workspace.

Out[64]:

Functions will automatically be compiled to machine code, the first time they are used.

In [65]:
f2(123453)

Compiling function f2 with type Integer -> String

Out[65]:
$\texttt{"354321"}$

The function cannot be applied to strings, because that would require the string to be converted into an integer.

In [68]:
f2("FriCAS")

Conversion failed in the compiled user function f2 .
Cannot convert the value from type String to Integer .


Multivariate function definitions are no problem.

In [66]:
f3(x,y,z) == (x+2*y)*z

Out[66]:
In [67]:
f3(3,4,2)

Compiling function f3 with type (PositiveInteger, PositiveInteger,
PositiveInteger) -> PositiveInteger

Out[67]:
$22$
In [68]:
f3(3.2,4.1,2)

Compiling function f3 with type (Float, Float, PositiveInteger) -> Float

Out[68]:
$22.8$

Note that by not specifying the types in the definition of f3 above, FriCAS will use the definition as a pattern to define functions with appropriate types when the function is first called. These functions have the same name, but due to different input/output type are, in fact, different. Not so different here, because the follow the same pattern. However, in the programming language SPAD that comes with FriCAS, it is, allowed and common to have functions with the same name/identifier that have different input/output types. That is known as function overloading.