How do I add infix operators?

7 views
Skip to first unread message

Martin Baker

unread,
Nov 14, 2009, 11:08:56 AM11/14/09
to FriCAS - computer algebra system
I am modifying the CliffordAlgebra domain and I would like to add /\,
\/ and _| operators to represent exterior,inner and contraction inner
products (in addition to the existing * Clifford product).

Is it possible to add these as infix operators from within the spad
domain code and define their precedence?

From searching this forum I get the impression that this involves a
command like:
)Lisp (push _/_\)
Although I can't find any instructions about how to do it, how to set
the precedence and so on?

Also is this generally encouraged or discouraged?
Are there examples in the codebase where I could see how to do this?
Vectors don't seem to do this for cross and dot products?

I could just provide this as functions like:
z := /\(x,y)
but this would be much less readable, especially for complicated
equations with mixed operations.

What do you think would be the best way to do this (keeping in mind
that I am a beginner with FriCAS)

Martin

Waldek Hebisch

unread,
Nov 14, 2009, 1:03:53 PM11/14/09
to fricas...@googlegroups.com
Martin Baker wrote:
> I am modifying the CliffordAlgebra domain and I would like to add /\,
> \/ and _| operators to represent exterior,inner and contraction inner
> products (in addition to the existing * Clifford product).
>
> Is it possible to add these as infix operators from within the spad
> domain code and define their precedence?
>

Actually currently '/\' and '\/' are operators, however due to a bug
they do not work in the compiler. I attach a small file which
fixes the problem. To use it save it in file 'ops.lisp', then
at FriCAS command line type:

)lisp (load (compile-file "ops.lisp"))

Note: you can put it in a .input script or even at start of your
.spad file. The fix has only effect during current session,
if you want permanent effect you need to modify FriCAS sources
and recompile.

Concerning '_|', FriCAS treats is the almost the same as '|' which
is an operator. This is because '_' is used as an "escape"
character. In particular putting it into name means that
FriCAS will treat the name as equal to name _without_ underscores,
but disable special syntatic meaning of that name. In particular
FriCAS will no longer treat the name as an operator.

In other words it is not possible to have '_' inside operator
name.


> >From searching this forum I get the impression that this involves a
> command like:
> )Lisp (push _/_\)
> Although I can't find any instructions about how to do it, how to set
> the precedence and so on?
>
> Also is this generally encouraged or discouraged?
> Are there examples in the codebase where I could see how to do this?
> Vectors don't seem to do this for cross and dot products?
>

Capability to add operators at runtime is currently unused. In
general if the operator name is not a Spad identifer one has to
properly modify "gliph-table" (the attached code is doing this).
If operator name is a Spad identifier one has to add it to
the list of keywords, like:

)lisp (push '|newop| Keywords)

Then one has to assign it correct priority, like:

)lisp (put '|newop| '|Led| '(|newop| |newop| 650 651))

It is hard to say what you should do: since to ability to add
operators is unused the is no experiece. One thing is probably
worth mentioning: currently priorities are global, so if you
change priority of some operators in other places priority
may be different than the one you expect. Releated to this
you may be surprised by priorities if '/\' and '\/': in the
compiler they were intended for logical operators, so in
compiler they bind less tightly than addition. I have put
qualification "in the compiler" because both operators
are also present in the interpreter, apparently with different
priority.



--
Waldek Hebisch
heb...@math.uni.wroc.pl
ops.lisp

Bill Page

unread,
Nov 14, 2009, 10:52:38 PM11/14/09
to fricas...@googlegroups.com
Martin,

Perhaps I do not understand your question but I do not see any problem
defining /\ and \/ as operators. They are treated as infix operators
by default in the interpreter even though you define them using a
standard prefix notation. For example see the page:

http://axiom-wiki.newsynthesis.org/SandBoxTensorProductPolynomial

On Sat, Nov 14, 2009 at 11:08 AM, Martin Baker wrote:
> I am modifying the CliffordAlgebra domain and I would like to add /\,
> \/ and _| operators to represent exterior,inner and contraction inner
> products (in addition to the existing * Clifford product).
>
> Is it possible to add these as infix operators from within the spad
> domain code and define their precedence?
>
> From searching this forum I get the impression that this involves a
> command like:
> )Lisp (push _/_\)
> Although I can't find any instructions about how to do it, how to set
> the precedence and so on?
>

Changing precedence might not be so easy. The code in the example
above does not attempt to change that. This involves at least
temporary changes to the Axiom interpreter as Waldek's email suggests.

> Also is this generally encouraged or discouraged?
> Are there examples in the codebase where I could see how to do this?
> Vectors don't seem to do this for cross and dot products?
>
> I could just provide this as functions like:
> z := /\(x,y)
> but this would be much less readable, especially for complicated
> equations with mixed operations.
>
> What do you think would be the best way to do this (keeping in mind
> that I am a beginner with FriCAS)
>

I think you bring up a good point that this should be made easier to do.

Regards,
Bill Page

Martin Baker

unread,
Nov 15, 2009, 3:53:10 AM11/15/09
to FriCAS - computer algebra system
I guess I can see why the precedence of an infix operator has to be
global. Presumably the program does not bind to a specific domain
until after the operation has been chosen according to its precedence?

In view of the limited number of symbols available and the links
between Grassman algebra, logic, vector algebra and tensors it seems
to make sense that they all use /\ and \/ but I get the impression
that we might want them to have a different precedence with + and *,
for instance:

In Grassman Algebra we might expect to see the exterior product /\
bind more tightly than the Clifford product (CliffordAlgebra currently
uses * as inherited from ring - perhaps Grassman Algebra shouldn't?)

In vector algebra we might expect scalar multiplication * to bind more
tightly than cross product (why not use /\ for that?).

Anyway, this is not an urgent issue for me, I can work on the
functionality by using function calls instead of the infix operator.
I'll put this on the list of implementation issues and hope that those
wiser than me come up with a solution.

Martin

Martin Baker

unread,
Nov 15, 2009, 10:10:20 AM11/15/09
to FriCAS - computer algebra system
Please ignore my last message, I'm not sure what I was trying to say
about vectors and scalar products, but it didn't make much sense!

I guess all I have to do is check both the compiler and the
interpreter to make sure that all products bind more tightly than +,
and that /\ and \/ bind more tightly than *. I think that would be
good enough for my purpose.

Then all I have to do is find a suitable symbol for the contraction
product.

Martin

Bertfried Fauser

unread,
Nov 15, 2009, 10:56:49 AM11/15/09
to fricas...@googlegroups.com
Dear Martin,

sorry fro being quiet, but I have currently other errands with higher priority.
Furthermorer I am not a FriCAS expert (at all or) on things like precedence.

> Then all I have to do is find a suitable symbol for the contraction
> product.

I can possibly help on that one. In differential geometry the canonical name for
a contraction by an element 'a' is i_{a} (subscript, with script 'i).
Note that the
contraction _always_ depends on the choice (!) of a dual isomorphism which
cannot be done uniquely. Most people though use the identification V=V* by
defining the canonical dual basis {e*_i}_i wrt to the canonical
basis {e_i}_i of V
such that e*_i(e_j) = \delta_{i,j} (Kronnecker \delta}. In that case
the dependence
of the 'bilinear form' (that is dual isomorphism followed by
evaluation) is usually
suppressed. However, this choice has geometric implications [in
projective geometry]
which one might or not might want to make.

If you want to have the choice of such a dual isomorphism to be free, then your
action (contraction, this is not a product, its not monoidal) become
parametrized by
a bilinear (symmetric) form. You will need this for dealing with
Clifford algebras in
arbitrary bases, when the quadratic form is not necessarily diagonalized by the
generators of the algebra [as in your very first example with the
rotated basis].
The contraction i(B)_{a}(v) would therefore have the signature:

i(B) : /\V x /\V --> /\V
i : /\V x /\V x B --> /\V where B : V x V ---> k is the bilinear
(polar) form of the quadratic
form.

In maple you can pass such parameters as indices to functions, in
FriCAS you might possibly want to have a function which sets locally
in the domain the bilinear form.
[Ralf I know this is wrong, but.....]

Note:
* The wedge product is associative
* the meet product is associative
* the Clifford product is associative
* the left/right contractions are not associative, but derivations
(a in V , u,v in /\V, Chevalley eq ii) of one of my previous mails)
i_a (u/\v) = i_a(u)/\v + (-1)^|u| u/\(i_a(v)) [left contraction]
(u/\v) j_a = u/\((v) j_a) + (-1)^|v| ((u) j_a)/\v [right contraction]

Rafal and I have used 'L' and 'J' as symbols for left and right contractions
when nothing other was available, its pretty close to typing in ascii _| |_
and has the advantage to be schort [Ralf I know that upper case letters should
not be used in FriCAS as names for function...]

For the reasons described above, I do not see a necessity to have an infix form
for the left/right contraction, since it does not really make sense, so I would
propose you use:
lc for left contraction (or even leftContrac) and
rc (or even rightContract) for the right contraction.

What I really would like to have (and that's not your problem at all)
is a graded
super module, generated by an ordered graded super set of 'letters' (elements),
that is the module would be spanned by generators 'a_i which have additional
information:
* Z_2 grade (even or odd)
* Z degree
like

OGSS := Record(s: OrderedSet, z2: FiniteField(2), z: Integer)
and the Grassmann algebra would be over ordered such sequences
GRMOD := Vector OGSS as basis monoms

(Note that the case all letters are even, and of degree 1 gives a
polynomial algebra,
while the case all letters are even and one has one letter in each
degree would
lead to the ring of symmetric functions, while the case all letters
are odd of
degree one leads to the Grassmann algebra...., such a thing
available would allow
to write code for all this objects in a single domain ;-))

So just go ahead to implement a plain Grassmann algebra, and I surely can help
with the code for a contraction.

Ciao
BF.

--
% PD Dr Bertfried Fauser
% Research Fellow, School of Computer Science, Univ. of Birmingham
% Honorary Associate, University of Tasmania
% Privat Docent: University of Konstanz, Physics Dept
<http://www.uni-konstanz.de>
% contact |-> URL : http://clifford.physik.uni-konstanz.de/~fauser/
% Phone : +49 1520 9874517

Martin Baker

unread,
Nov 15, 2009, 1:38:40 PM11/15/09
to FriCAS - computer algebra system
Bertfried,

Thanks, lots to think about as always, do you think these are all the
binary and unary operators that are needed (or have I combined
separate concepts?):

binary operators:

_/_\: (%, %) -> % -- exterior,Grassman,wedge,join
_\_/: (%, %) -> % -- regressive inner,meet
*: (%, %) -> % -- Clifford, geometric
lc: (%, %) -> % -- left contraction
rc: (%, %) -> % -- right contraction
-- + and - are inherited from ring

unary operators:

recip(x: %): Union(%, "failed") -- Clifford inverse where possible,
reverse
*: (%) -> % -- complement,canonical dual basis,multiply by
pseudoscalar

Waldek, bill,

Is it alright to use '*' as both infix and prefix operator?

Thanks,

Martin

Bertfried Fauser

unread,
Nov 15, 2009, 2:11:51 PM11/15/09
to fricas...@googlegroups.com
Hi Martin,

your list looks pretty complete to me. I assume that % is the graded
vector space
/\V over a space V over a base field (ring) k

> binary operators:
>
> _/_\: (%, %) -> % -- exterior,Grassman,wedge,join
[fine]
> _\_/: (%, %) -> % -- regressive inner,meet
[note that the regressive product might need to know about the total
dimension of the
space, while the wedge don't need this information, a move I like
very much, also for
geometric reasons.]
> *: (%, %) -> % -- Clifford, geometric
[fine, as long as you can somehow teach * to be dependent on a quadratic or even
general bilinear form]
> lc: (%, %) -> % -- left contraction
> rc: (%, %) -> % -- right contraction
[same comment as for *]
> -- + and - are inherited from ring
[are inherited from % as a (graded) module/abelian group]

> unary operators:
>
> recip(x: %): Union(%, "failed") -- Clifford inverse where possible,
[fine]

> reverse
> *: (%) -> % -- complement,canonical dual basis,multiply by pseudoscalar
[the reverse is usually denoted by a tilde ~, not by a *, though this
has some right
to be called * (if seen as a Hodge duality). Since the signature of
your stars differ, *:(%,%)->% and *:(%)->% FriCAS should be fine with
two such operationsm but
I would prefer the tilde ~ (or even 'reversion') anyhow.

Note1: IFF the bilinear form B attached to the quadratic form Q used
to build the clifford algebra is _not diagonal_ in the chosen
generators, then the reversion depends
nontrivially on B, even worse if B is not a symmetric matrix (one can
still build a
Clifford algebra over such B's), there are some commutative diagrams in a joint
paper of mine with Rafal Ablamowicz on our Bigebra package, if you really
want to know I can send it.

Note2: You should be aware that there are (at least) two types of
reversions (families of reversions depending on the choice of
generators). One is the reversion of the
Grassmann basis, one is the reversion of the Clifford basis, they are different
concepts!

Example:
Def: e12:=e1/\e2 e(12):=e(1)*e(2) etc, ~=reversion wrt the chosen basis

first ~= Grassmann reversion:
~(e12) = e21 = -e12
~(e(12)) = ~(e(1)*e(2)) = ~(e12 +B(e1,e2)) = -e12+B(e1,e2) =
-e(1)*e(2) + 2B(e1,e2)
now ~=Clifford reversion:
~(e(12)) = e(21) = e(2)*e(1) = e21+B(e2,e1)= -e12+B(e2,e1) = -e(12)
+B(e1,e2)+B(e2,e1)
now if B=B^t then we get
= -e(12)+2B(e1,e2)
if B=g+A with g=g^t and A=-A^t we get
= -e(12) +2g(e1,e2)
~(e12) = ~(e(12) - B(e1,e2)) = -e(12) +2B(e1,e2)-B(e1,e2) (sym B)
= -e(12) + B(e1,e2)
[the nonsymmetric case is more complicated, shows however up in the
normal ordering
process of functional equations in quantum field theory, thats why I
developed the Clifford
theory for arbitrary bilinear forms B, for geometry you can _almost_
allways do with symmetric B though, so dont bother too much.]

Lesson: ~ also depends on the chosen bilinear form! (or phrased
differently on the
chosen set of generators.
]

> pseudoscalar:()->%
[fine]

You might also want to add: (R base ring)

scalarpart:(%) -> R
wedgeB:(%,%) -> R (the extended bilinear form B : VxV -> R to B^ : /\Vx/\V ->R)
unit:(r:R)->% [embedding of the scalars, note that unit(1) is the
identity of the algebra(s)]

======================================================
At a later stage you might want to add matrix representations of
Clifford numbers,
but that is not yet our/your concern I guess. If you have code, please
let me know...
Reply all
Reply to author
Forward
0 new messages