Symbolic Integers
A simple form of symbolic computation using just Variable and Integer.
fricas
(1) -> a:Union(Variable a,Integer)
Type: Void
fricas
b:Union(Variable b,Integer)
Type: Void
fricas
c:=a*3-b*2
Type: Polynomial(Integer)
fricas
p:UP(x,Integer):=x*2-7
Type: UnivariatePolynomial
?(x,
Integer)
fricas
pc := p c
Type: Fraction(Polynomial(Integer))
fricas
f(x)==x^3-x^2+1
Type: Void
fricas
fb := f b
fricas
Compiling function f with type Variable(b) -> Polynomial(Integer)
Type: Polynomial(Integer)
fricas
a:=1
Type: Union(Integer,...)
fricas
b:=-3
Type: Union(Integer,...)
fricas
c
Type: Polynomial(Integer)
fricas
eval(pc,['a=a,'b=b])
Type: Fraction(Polynomial(Integer))
fricas
eval(c,['a=a,'b=b])
Type: Polynomial(Integer)
fricas
eval(fb,['a=a,'b=b])
Type: Polynomial(Integer)
fricas
a:=3.14 -- not permitted!
Cannot convert right-hand side of assignment
3.14
to an object of the type Union(Variable(a),Integer) of the
left-hand side.
For more complex cases it is necessary to define a new domain of "indeterminants". These are symbols and unevaluated expressions that can be evaluated at a later time. This domain is modeled after InputForm? which provides all of the basic functionality.
spad
)abbrev domain INDET Indeterminant
++ Description:
++ Based on InputForm
Indeterminant():
Join(SExpressionCategory(String,Symbol,Integer,DoubleFloat,OutputForm),
ConvertibleTo SExpression) with
eval: % -> Any
++ eval(f) passes f to the interpreter.
binary : (%, List %) -> %
++ \spad{binary(op, [a1,...,an])} returns the input form
++ corresponding to \spad{a1 op a2 op ... op an}.
function : (%, List Symbol, Symbol) -> %
++ \spad{function(code, [x1,...,xn], f)} returns the input form
++ corresponding to \spad{f(x1,...,xn) == code}.
lambda : (%, List Symbol) -> %
++ \spad{lambda(code, [x1,...,xn])} returns the input form
++ corresponding to \spad{(x1,...,xn) +-> code} if \spad{n > 1},
++ or to \spad{x1 +-> code} if \spad{n = 1}.
"+" : (%, %) -> %
++ \spad{a + b} returns the input form corresponding to \spad{a + b}.
"-" : (%, %) -> %
++ \spad{a - b} returns the input form corresponding to \spad{a - b}.
"-" : % -> %
++ \spad{-a} returns the input form corresponding to \spad{-a}.
"*" : (%, %) -> %
++ \spad{a * b} returns the input form corresponding to \spad{a * b}.
"/" : (%, %) -> %
++ \spad{a / b} returns the input form corresponding to \spad{a / b}.
"**" : (%, NonNegativeInteger) -> %
++ \spad{a ** b} returns the input form corresponding to \spad{a ** b}.
"**" : (%, Integer) -> %
++ \spad{a ** b} returns the input form corresponding to \spad{a ** b}.
unparse : % -> String
++ unparse(f) returns a string s such that the parser
++ would transform s to f.
++ Error: if f is not the parsed form of a string.
declare : List % -> Symbol
++ declare(t) returns a name f such that f has been
++ declared to the interpreter to be of type t, but has
++ not been assigned a value yet.
++ Note: t should be created as \spad{devaluate(T)$Lisp} where T is the
++ actual type of f (this hack is required for the case where
++ T is a mapping type).
compile : (Symbol, List %) -> Symbol
++ \spad{compile(f, [t1,...,tn])} forces the interpreter to compile
++ the function f with signature \spad{(t1,...,tn) -> ?}.
++ returns the symbol f if successful.
++ Error: if f was not defined beforehand in the interpreter,
++ or if the ti's are not valid types, or if the compiler fails.
coerce : Integer -> %
== SExpression add
Rep := SExpression
mkProperOp: Symbol -> %
strsym : % -> String
tuplify : List Symbol -> %
coerce(x:Integer):% == convert(x)
coerce(x:%):OutputForm == expr x
convert(x:%):SExpression == x pretend SExpression
conv(ll : List %): % ==
convert(ll pretend List SExpression)$SExpression pretend %
lambda(f,l) == conv([convert("+->"::Symbol),tuplify l,f]$List(%))
eval x ==
v := interpret(x)$Lisp
mkObj(unwrap(objVal(v)$Lisp)$Lisp, objMode(v)$Lisp)$Lisp
convert(x:DoubleFloat):% ==
convert(x)$Rep
strsym s ==
string? s => string s
symbol? s => string symbol s
error "strsym: form is neither a string or symbol"
unparse x ==
atom?(s:% := form2String(x)$Lisp) => strsym s
concat [strsym a for a in destruct s]
declare signature ==
declare(name := new()$Symbol, signature)$Lisp
name
compile(name, types) ==
symbol car cdr car
selectLocalMms(mkProperOp name, convert(name)@%,
types, nil$List(%))$Lisp
mkProperOp name ==
op := mkAtree(nme := convert(name)@%)$Lisp
transferPropsToNode(nme, op)$Lisp
convert op
binary(op, args) ==
(n := #args) < 2 => error "Need at least 2 arguments"
n = 2 => convert([op, first args, last args]$List(%))
convert([op, first args, binary(op, rest args)]$List(%))
tuplify l ==
empty? rest l => convert first l
conv
concat(convert("Tuple"::Symbol), [convert x for x in l]$List(%))
function(f, l, name) ==
nn := convert(new(1 + #l, convert(nil()$List(%)))$List(%))@%
conv([convert("DEF"::Symbol), conv(cons(convert(name)@%,
[convert(x)@% for x in l])), nn, nn, f]$List(%))
s1 + s2 ==
conv [convert("+"::Symbol), s1, s2]$List(%)
s1 - s2 ==
conv [convert("-"::Symbol), s1, s2]$List(%)
_-(s1) ==
conv [convert("-"::Symbol), s1]$List(%)
s1 * s2 ==
conv [convert("*"::Symbol), s1, s2]$List(%)
s1:% ** n:Integer ==
conv [convert("**"::Symbol), s1, convert n]$List(%)
s1:% ** n:NonNegativeInteger == s1 ** (n::Integer)
s1 / s2 ==
conv [convert("/"::Symbol), s1, s2]$List(%)
spad
Compiling FriCAS source code from file
/var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/7483143363411555740-25px002.spad
using system compiler.
INDET abbreviates domain Indeterminant
------------------------------------------------------------------------
initializing NRLIB INDET for Indeterminant
compiling into NRLIB INDET
>> System error:
invalid number of arguments: 5
Symbolic Matrices
fricas
)clear all
All user variables and function definitions have been cleared.
fricas
m:Union(Indeterminant,Matrix Integer)
You cannot now use Indeterminant in the context you have it.
In the Union(Variable a,Integer) way,
fricas
)clear all
All user variables and function definitions have been cleared.
fricas
d: Union(Variable d, Float)
Type: Void
fricas
d*2
Type: Polynomial(Integer)
will be problematic, and the assignment between symbolic integers is not allowed.
fricas
a: Union(Variable a, Integer)
Type: Void
fricas
b: Union(Variable b, Integer)
Type: Void
fricas
b:=a
a is declared as being in Union(Variable(a),Integer) but has not
been given a value.
I agree that the type
Union(Variable d,Integer) alone is not
sufficient for symbolic computation. But although it might look
strange, in fact a result of
Polynomial Integer for
2*d is
not really a problem. Remember that the use of
Integer in
Polynomial Integer does not mean that evaluation of the
polynomial yields an
Integer - it means only that the domain
of the coefficients of the polynomial are integers (i.e. that
2 is an integer), it says nothing about 'd':
fricas
p:=2*d
Type: Polynomial(Integer)
fricas
eval(p,d=3.14)
Type: Polynomial(Float)
But there is still a problem since I can write:
fricas
a:Union(Variable a,Integer)
Type: Void
fricas
a:=3.14
Cannot convert right-hand side of assignment
3.14
to an object of the type Union(Variable(a),Integer) of the
left-hand side.
and Axiom does not complain about the eval request because
as far as Polynomial Integer is concerned d is just a
Symbol.
In the case of the example Indeterminant domain, evaluation
of symbolic expressions is always delayed so an appropriate
eval operation could be defined that properly respects the
type.