1
2% Redistribution and use in source and binary forms, with or without
3% modification, are permitted provided that the following conditions are met:
4%
5%    * Redistributions of source code must retain the relevant copyright
6%      notice, this list of conditions and the following disclaimer.
7%    * Redistributions in binary form must reproduce the above copyright
8%      notice, this list of conditions and the following disclaimer in the
9%      documentation and/or other materials provided with the distribution.
10%
11% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
13% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14% PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR
15% CONTRIBUTORS
16% BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22% POSSIBILITY OF SUCH DAMAGE.
23%
24
25COMMENT
26
27  The following routines can handle scalar expressions that are composed out
28  of 3-vectors in three different notations:
29
30  - the extended vector form: ABCD... stands for (A , B x (C x (D x ...)))
31    where ',' stands for the vector product and 'x' stands for the
32    skew symmetric product,
33  - the standard vector form involving only AB = (A , B) and
34    ABC = (A , B x C),
35  - the component form involving only the components a1,a2,a3,b1,...
36
37  In all 3 notations the vector is represented by a single letter only.
38  Any extra (non-vectorial) constant or parameter has to start with the
39  characters !&.
40
41  ROUTINES:
42  ---------
43  e2s : extended vector form into standard vector form, also conversion of a
44        standard vector form into standard vector form, but where factors
45        in calar products and triple products are sorted lexicographically,
46        This is necessary in order to work with this package on expressions
47        that have been generated outside this package.
48  v2c : any vector form (extended or standard) into component form
49  c2s : component form into standard vector form
50  c2sl: like c2s, only the resulting vector expression is returned partitioned
51        as a list which simplifies choosing arbitrary parameters arbcomplex(i)
52        such that the vector expression is as short as possible
53  s2s : generates and uses vector identities to length reduce a standard
54        vector form expression
55  s2e : like s2s but also uses identities involving n-products and thus
56        transforms standard vector form into extended vector form
57  genpro: generation of all scalar and spate products for a given vector list
58  genpro_wg: generation of all scalar and spate products with weight lists
59             for a given vector weight list
60  poisson_c: computation of the poisson bracket of two arbitrary
61             expressions, needs anything what struc_cons needs
62             in component form, e.g. kap:=-a1**2-a2**2-a3**2
63  poisson_v: computes the Poisson bracket for two vector expressions uses
64             global variables v_, gbase_ and initially the procedure
65             poisson_c (to compute the Poisson bracket between scalar and
66             spate products), so poisson_v needs all that poisson_c needs,
67             currently restricted to vectors A,B,U,V through gbase_ .
68  %  arb2zero: sets all arbcomplex(1)..arbcomplex(!!arbint):=0 and !!arbint:=0
69  gfi: generates a vector expression with unknown coefficients, where
70       each term of the generated polynomial has a total weight list
71       as required by the first argument to gfi. The weight list of each
72       vector is given through the second argument to gfi. The third argument
73       is a list of vector expressions to the effect that no term of
74       the generated polynomial is purely a product of powers of these vector
75       exressions. gfi returns a list with the generated polynomial as first
76       element followed by a list of undetermined constants.
77  vinit: generates all polynomial identities for all scalar and triple
78         products from the (currently) 4 vectors in the input list
79
80  GLOBAL VARIABLES:
81  -----------------
82  algebraic:  all variables in struc_cons, like U1,U2,U3,V1,V2,V3,kap
83              v_, gbase_, heads_ % for poisson_v
84              !&c1, !&c2, ...    % from c2s
85  operator:   poi_               % stores the Poisson brackets
86  lisp:       fino_, wgths_      % from file gengen.red
87              !&r1, !&r2, ...    % from gfi
88              tr_vec
89
90  INITIALIZATION:
91  ---------------
92  This file contains all initializations (of v_,gbase_,heads_,struc_cons)
93  needed for computations with the 2 constant vectors A,B and 2 dynamical
94  vectors U,V. If other vectors or constant vectors with conditions,
95  like AB=0 should be used  then
96  - run:  vinit(list_of_vectors)
97$
98
99lisp <<terpri()$
100 write"********************************************************************"$
101 terpri()$
102 write"* Please note the following conventions to use these routines:     *"$
103 terpri()$
104 write"* - Vectors are denoted by a single character and products         *"$
105 terpri()$
106 write"*   (A,Bx(Cx(Dx...))) by single identifiers ABCD... . For example, *"$
107 terpri()$
108 write"*   scalar products (A,B) by AB, triple products (A,BxC) by ABC,   *"$
109 terpri()$
110 write"*   (A,Bx(CxD)) by ABCD and so on. For scalar and triple products  *"$
111 terpri()$
112 write"*   only those versions are used for which letters are sorted      *"$
113 terpri()$
114 write"*   alphabetically, for example, AB, ABU but not BA, AUB or BUA.   *"$
115 terpri()$
116 write"* - Any non-vectorial variable starts with the two characters !&.  *"$
117 terpri()$
118 write"* - For further comments see the beginning of this file and the    *"$
119 terpri()$
120 write"*   files v3tools.tex and v3tools.tst.                             *"$
121 terpri()$
122 write"********************************************************************"$
123 terpri()
124>>$
125
126lisp(if getd 'set_bndstk_size then set_bndstk_size(50000))$
127load_package  'groebner$
128load_package 'crack$
129setcrackflags()$
130symbolic fluid '(print_more record_hist max_gc_short size_watch max_gc_fac
131                 print_ old_history tr_short tr_vec)$
132tr_vec:=nil$
133
134%----------------------------------------------------
135
136algebraic operator poi_$
137
138%----------------------------------------------------
139symbolic fluid '(wgths_ fino_ nfct_)$
140
141symbolic procedure gen(all)$
142% The global variable wgths_ specifies the weights of the generated terms
143% which are put into the global list fino_.
144% 'all' is the list of variables and their weights to be used.
145% Before calling gen externally, set the global variable fino_ to nil.
146if null all then {cons(nil,for each h in wgths_ collect 0)}
147                   % {{{'bu},0,1,1}}    % i.e. if bu is an overall factor
148                   % but then reductions are wrong
149            else begin
150  scalar h,v,vw,oldli,newli,vwcp,wgcp,found_less,found_more,b,c,d$
151
152  h:=car all$  all:=cdr all$
153  v:=car h; vw:=cdr h$    % the next factor to be multiplied + its weight-list
154
155  oldli:=gen(all)$
156  % old has the form {e1,e2,e3,..} where
157  % ei = {{v1,v2,v3,..}, weights} represents a monomial
158  % vi are factors of the monomial,
159  % for all i: weights(i)<=wgths_(i) and not all relations are equalities.
160
161  while oldli do <<
162    h:=car oldli; oldli:=cdr oldli$
163    newli:=cons(h,newli);
164    repeat <<
165      vwcp:=vw;
166      wgcp:=wgths_$
167      found_less:=nil$
168      found_more:=nil$
169      h:=cons(cons(v,car h),
170              for each b in cdr h collect
171              <<d:=b+<<c:=car vwcp;vwcp:=cdr vwcp;c>>;
172                if d<car wgcp then found_less:=t else
173                if d>car wgcp then found_more:=t$
174                wgcp:=cdr wgcp$
175                d
176              >>
177             )$
178    >> until if found_more then t else
179             if found_less=nil then
180             <<fino_:=cons(if cdar h then cons('times,car h)
181                                     else caar h            ,fino_)$ t>>
182             else <<newli:=cons(h,newli); nil>>
183  >>$
184
185  return newli
186end$
187%----------------------------------------------------
188
189algebraic procedure is_reduceable(trm,hs)$
190begin
191 while hs neq {} and (den(trm/first hs) neq 1) do hs:=rest hs;
192 return if hs neq {} then t
193                     else nil
194end$
195
196%----------------------------------------------------
197
198symbolic procedure l2s(li)$
199% The program converts a list {a,b,c,d,..} which represents
200% (a,(bx(cx(dx..)))) where ',' stands for the scalar product and x
201% stands for the skew product into a polynomial of scalar products and
202% spate products.
203% The argument li must be a lisp list with at least 2 elements
204
205if length(li)=2 then if ordp(car li,cadr li) then mkid(car  li,cadr li)
206                                             else mkid(cadr li,car  li)
207                else
208if length(li)=3 then if (car  li=cadr  li) or
209                        (car  li=caddr li) or
210                        (cadr li=caddr li) then 0
211                                           else
212if ordp(car   li,cadr  li) and
213   ordp(cadr  li,caddr li) then mkid(car li,mkid(cadr li,caddr li)) else
214if ordp(cadr  li,caddr li) and
215   ordp(caddr li,car   li) then mkid(cadr li,mkid(caddr li,car li)) else
216if ordp(caddr li,car   li) and
217   ordp(car   li,cadr  li) then mkid(caddr li,mkid(car li,cadr li)) else
218if ordp(car   li,caddr li) and
219   ordp(caddr li,cadr  li) then{'minus,mkid(car li,mkid(caddr li,cadr li))}else
220if ordp(cadr  li,car   li) and
221   ordp(car   li,caddr li) then{'minus,mkid(cadr li,mkid(car li,caddr li))}else
222if ordp(caddr li,cadr  li) and
223   ordp(cadr  li,car   li) then{'minus,mkid(caddr li,mkid(cadr li,car li))}else
224write"error in ord!"
225                else
226{'difference,{'times,if ordp(car  li,caddr li) then
227                       mkid(car   li,caddr li) else
228                       mkid(caddr li,car   li),l2s(cons(cadr li,cdddr li))},
229             {'times,if ordp(cadr li,caddr li) then
230                       mkid(cadr  li,caddr li) else
231                       mkid(caddr li,cadr  li),l2s(cons(car  li,cdddr li))} }$
232%----------------------------------------------------
233
234%% symbolic procedure permu_repi(li)$
235%% % generates a list of permutations of the elements of li without multiple
236%% % permutations but where li can have multiple elements
237%% begin scalar p,perm,red_perm$
238%%  perm:=
239%%  if 1=length li then list(li)
240%%                 else for each x in li join
241%%                      for each y in permu_repi(delete(x,li)) collect cons(x,y)$
242%%
243%%  if perm and length car perm = 3 then <<
244%%   for each p in perm do
245%%   if cadr p neq caddr p then red_perm:=cons(p,red_perm)$
246%%   perm:=red_perm;
247%%   red_perm:=nil$
248%%  >>$
249%%
250%%  % deleting multiple lists
251%%  for each p in perm do
252%%  if not member(p,red_perm) then red_perm:=cons(p,red_perm)$
253%%
254%%  return red_perm
255%% end$
256
257% FJW, May 2019: The following version of permu_repi caches function
258% values and generates only unique permutations.  This makes it very
259% significantly more efficient when there are many repeated elements
260% in the list being permuted, as is the case when it is called in
261% v3tools.tst.  Assuming this represents the normal use case then it
262% should be a worthwhile improvement.  However, when there are no
263% repeats it will be slower and generate a lot of irrelevant
264% intermediate data.  If this is an issue then it could be
265% conditionalized to pick the best strategy, so I have preserved the
266% original version above as a comment.
267
268fluid '(permu_repi_cache)$
269
270symbolic procedure permu_repi(li)$
271% generates a list of permutations of the elements of li without multiple
272% permutations but where li can have multiple elements
273begin scalar permu_repi_cache$
274 % permu_repi_cache is used to avoid recursively recomputing
275 % the same sub-permutations within this call of permu_repi.
276 return permu_repi_1(li)
277end$
278
279symbolic procedure permu_repi_1(li)$
280begin scalar r,p,perm,red_perm, lix, xlix, perms_seen$
281 % perms_seen is used to ignore duplicate permutations at this level.
282 if r:=assoc(li,permu_repi_cache) then return cdr r$
283 perm:=
284 if 1=length li then list(li)
285                else for each x in li join <<
286                     lix := delete(x,li)$  xlix := x . lix$
287                     if not (xlix member perms_seen) then <<
288                            perms_seen := xlix . perms_seen$
289                            for each y in permu_repi_1 lix collect cons(x,y) >>
290                >>$
291
292 if perm and length car perm = 3 then <<
293  for each p in perm do
294  if cadr p neq caddr p then red_perm:=cons(p,red_perm)$
295  perm:=red_perm;
296 >>$
297
298 % This line is here only to preserve the ordering returned by the
299 % original version of this procedure:
300 perm:=reversip perm$
301
302 permu_repi_cache:=(li.perm).permu_repi_cache$
303 return perm
304end$
305%----------------------------------------------------
306
307symbolic procedure genid(vli,wgli)$
308% This procedure generates a list of all n-vector products for given
309% vli : the list of vector variables and their weights
310%       eg {{A,1,0},{B,1,0},{U,0,1},{V,1,1}}
311% wgli: the list of total weights of each term of the polynomial
312%       eg {2,3}
313begin scalar h,hm,p,perm,allperm,idli,idlicp$
314
315 fino_:=nil$
316 wgths_:=wgli$
317 gen(vli);
318
319 % now generation of all permutations
320 for each h in fino_ do <<
321  % Each h is of the form {TIMES a a b b b u v v v ...}
322  write"Generating specific permutations of products of the vectors ",
323       compress cdr h,"."$
324  terpri()$
325  allperm:=permu_repi(cdr h)$
326  write length allperm," permutations generated."$terpri()$
327
328  % deleting multiple lists with identical first two elements
329  for each p in allperm do
330  if car p neq cadr p then perm:=cons(p,perm)$
331  allperm:=nil$
332  write"Applying another filter, ",length perm," are left."$terpri()$
333
334  idli:=nil$
335  for each p in perm do <<
336
337   h:=reval l2s p$
338   if not zerop h then <<
339    hm:=reval {'minus,h}$
340    idlicp:=idli$
341    while idlicp and
342          caar idlicp neq h and
343          caar idlicp neq hm do idlicp:=cdr idlicp$
344
345    if null idlicp then idli:=cons((h . intern compress p),idli)
346   >>$
347  >>$
348  write "At a first look ",length idli," seem to be non-equivalent."$terpri()$
349% for each h in idli do mathprint {'EQUAL,cdr h,car h}$
350 >>$
351 fino_:=nil;
352 return for each h in idli collect {'difference,car h, cdr h}
353end$
354%----------------------------------------------------
355
356symbolic fluid '(algebraic_reduce_functions)$
357lisp (algebraic_reduce_functions:=
358'(plus minus difference times quotient expt arbcomplex list))$
359
360symbolic procedure expro(a)$
361% procedure to extract all identifiers
362% the parameter a has to be in prefix form
363
364% WINFRIED: also, ich nehme immer die Funktion  groebnervars
365% oder auch gvarlis wenn man sowieso das groebnerpackage
366% geladen hat. Eventuell groebnervars reval ...
367
368if null a then nil else
369if atom a then
370  if numberp a or
371     member(a,algebraic_reduce_functions) then nil
372                                          else {a}
373          else union(expro(car a),expro(cdr a))$
374%----------------------------------------------------
375
376symbolic procedure extract_prod(a)$
377% extracts all identifiers from 'a' which do not start with &,!&,!!
378begin scalar ep,epl,h,ret$
379 ep:=expro reval a$
380 for each h in ep do <<
381  epl:=explode h$
382  if car epl neq '&  and
383     car epl neq '!& and
384     car epl neq '!! then ret:=cons(h,ret)
385 >>$
386 return ret
387end$
388%----------------------------------------------------
389
390symbolic operator e2s$
391symbolic procedure e2s(a)$
392% converts extended vector form to standard vector form
393% also useful to convert e.g. BA to AB if a vector expression has been
394% generated outside of this program
395begin scalar p,pl,px$
396 pl:=extract_prod a$
397 for each p in pl do <<
398  px:=l2s explode p$
399  if p neq px then a:=subst(px,p,a)
400 >>$
401 return a
402end$
403%----------------------------------------------------
404
405symbolic procedure vc(v)$
406% generates a lisp list of the 3 components for a given vector
407{mkid(v,1),mkid(v,2),mkid(v,3)}$
408%----------------------------------------------------
409
410symbolic procedure dot(f,g)$
411% returns the scalar product of two vectors represented
412% by lisp lists of components
413reval {'plus,{'times,car   f,car   g},
414             {'times,cadr  f,cadr  g},
415             {'times,caddr f,caddr g} }$
416%----------------------------------------------------
417
418symbolic procedure cross(f,g)$
419% returns the skew product of two vectors represented
420% by lisp lists of components
421{{'difference,{'times,cadr  f,caddr g},{'times,caddr f,cadr  g}},
422 {'difference,{'times,caddr f,car   g},{'times,car   f,caddr g}},
423 {'difference,{'times,car   f,cadr  g},{'times,cadr  f,car   g}} }$
424%----------------------------------------------------
425
426symbolic procedure spat(f,g,h)$
427% returns the spate (triple) product of three vectors
428dot(f,cross(g,h))$
429%----------------------------------------------------
430
431symbolic operator v2c$
432% converts any vector form into component form
433symbolic procedure v2c(a)$
434begin scalar p,pl,px$
435 if tr_vec then <<write"v2c start"$terpri()>>$
436 a:=e2s a$
437 pl:=extract_prod a$
438 for each p in pl do <<
439  px:=explode p$
440  a:=subst(if length px = 2 then dot (vc car px,vc cadr px)
441                            else spat(vc car px,vc cadr px,vc caddr px),p,a)
442 >>$
443  if tr_vec then <<write"v2c end"$terpri()>>$
444 return reval a
445end$
446%----------------------------------------------------
447
448symbolic procedure addvec(v,vl)$
449% vl is an assoc list ((a . na) (b . nb) ...) of vectors a,b,... and the
450% number of their occurences na, nb, ...
451% An occurence of the vector v is added.
452begin scalar ve$
453 ve:=assoc(v,vl)$
454 return
455 if null ve then cons((v . 1),vl)
456            else cons((v . add1 cdr ve),delete(ve,vl))
457end$
458%----------------------------------------------------
459
460symbolic procedure letters_of(a)$
461% explodes an identifier and returns list of letters
462% if 'a' is a vector identifier and nil if 'a' is a parameter
463% (ie if 'a' starts with & or !& or !! )
464begin scalar l,h,ea;
465 ea:=explode a$
466 if car ea neq '& and
467    car ea neq '!& and
468    car ea neq '!! then
469 for each h in ea do
470 if freeof('(!0 !1 !2 !3 !4 !5 !6 !7 !8 !9),h) then l:=cons(h,l)$
471 return l
472end$
473%----------------------------------------------------
474
475symbolic procedure get_vlist_of_term(at)$
476% returns a sorted association list of vectors and their degree
477% appearing in the single term 'at'
478begin scalar f1,v,vl,vlc,h$
479 if pairp at and car at = 'quotient then at:=cadr at;
480 if pairp at and car at = 'minus then <<
481  at:=cadr at;
482  if pairp at and car at = 'quotient then at:=cadr at
483 >>$
484 if pairp at and ((car at = 'times) or
485                  (car at = 'list ) or
486                  (car at = 'equal)    ) then at:=cdr at
487                                         else at:={at}$
488 while at do <<
489  f1:=car at;  at:=cdr at;
490  if not ((numberp f1               ) or
491          ((pairp f1) and
492           (car f1 = 'quotient) and
493           (numberp cadr f1) and
494           (numberp caddr f1)       )    ) then
495  if atom f1 then for each v in letters_of f1 do vl:=addvec(v,vl) else
496  if car f1 neq 'arbcomplex then
497  if car f1 neq 'expt then write"****** car not EXPT ******" else
498  for each v in letters_of cadr f1 do
499  for h:=1:(caddr f1) do vl:=addvec(v,vl)
500 >>;
501
502 % at first sorting vl to generate later always the same vector
503 % products, like ab instead of ba
504 while vl do <<
505  v:=car vl;
506  for each u in vl do if ordp(car v,car u) then v:=u;
507  vlc:=cons(v,vlc);
508  vl:=delete(v,vl);
509 >>$
510 return vlc
511end$
512%----------------------------------------------------
513
514symbolic procedure filter_hom(a,at)$
515% From the polynomial vector expression 'a' in component form return
516% 1) that part for which each term has the same number of occurences of the
517%    same vector components as in the term 'at'
518% 2) the list of vectors and their number of occurences ((a.2) (b.1) ...)
519begin scalar vl,v,h,gs;
520 if tr_vec then <<write"filter_hom start"$terpri()>>$
521
522 vl:=get_vlist_of_term(at)$
523 gs:=gensym()$
524 for each v in vl do <<
525  % replace each component_of_car_v by gs**(component_of_car_v)
526  for each h in vc car v do a:=subst({'times,h,gs},h,a)$
527  a:=reval a$
528  a:=coeffn(a,gs,cdr v)
529 >>$
530
531 if tr_vec then <<write"filter_hom end"$terpri()>>$
532 return cons(a,vl)
533end$
534%----------------------------------------------------
535
536symbolic procedure t1(a)$
537% 'a' is an expression in prefix form
538% t1 returns the first term of its numerator
539if null a then 0 else
540if atom a then a else
541if (car a='quotient) then reval {'quotient,t1 cadr a,caddr a} else
542if (car a='plus) or (car a='difference) then cadr a
543                                        else a$
544%----------------------------------------------------
545
546symbolic operator genpro_wg$
547% converting algebraic input list to symbolic and result back to algebraic
548symbolic procedure genpro_wg(vl)$
549cons('list,for each g in genpro_wg_l(for each h in cdr vl collect cdr h)
550           collect cons('list,g))$
551%----------------------------------------------------
552
553symbolic procedure addvectowg(wg,v)$
554% adds vector v of weights to the vector wg
555for j:=1:(length wg) collect reval {'plus,nth(wg,j),nth(v,j)}$
556%----------------------------------------------------
557
558symbolic procedure genpro_wg_l(vl)$
559% input: symbolic list of variables with weights, e.g.
560%        vl={{A,1,0,0},{B,0,1,0},{U,0,0,1},{V,1,0,1}}$
561% output: list of scalar/spate products + weights {{AA,2,0,0},..}
562if null vl then {'list} else
563begin scalar n,j,k,l,p2,p3,wg;
564
565 wg:=for j:=1:((length cdar vl)) collect 0$
566 n:=length vl;
567 % then generation of the scalar products
568 p2:=for j:=1:n join
569     for k:=j:n collect
570     cons(mkid(car nth(vl,j),car nth(vl,k)),
571          addvectowg(addvectowg(wg,cdr nth(vl,j)),cdr nth(vl,k)))$
572
573 % then generation of the spate products
574 p3:=for j:=  1  :(n-2) join
575     for k:=(j+1):(n-1) join
576     for l:=(k+1):  n   collect
577     cons(mkid(car nth(vl,j),mkid(car nth(vl,k),car nth(vl,l))),
578          addvectowg(addvectowg(addvectowg(wg,cdr nth(vl,j)),
579                                cdr nth(vl,k)),cdr nth(vl,l)))$
580
581 return append(p2,p3)
582end$
583%----------------------------------------------------
584
585symbolic procedure std_wg(vl)$
586% lisp input : {a,b,u,v}
587% lisp output: {{a,1,0,0,0},{b,0,1,0,0},{u,0,0,1,0},{v,0,0,0,1}}
588for h:=1:(length vl) collect cons(nth(vl,h),
589for k:=1:(length vl) collect if h=k then 1 else 0)$
590%----------------------------------------------------
591
592symbolic operator genpro$  % moved up
593symbolic procedure genpro(vl)$
594% input: algebraic list of vectors, e.g. {a,b,u,v}
595% output: algebraic list of scalar and spate products
596cons('list,for each h in genpro_wg_l(std_wg cdr vl) collect car h)$
597%----------------------------------------------------
598
599symbolic procedure hc2s(ahc)$
600% generates a vector expression (if possible) for the homogeneaous
601% component expression car ahc
602% ahc={hom_expression_in_component_form,{('u.2),('v.1),..}}
603% where 2 is the degree of u,...
604begin scalar v,vl,nf,f,fl,zro,h,sol,ansatz$ %,oldorder$
605 if tr_vec then <<write"hc2s start"$terpri()>>$
606
607 % generation of all vector products with correct weight
608 fino_:=nil$
609 wgths_:=for each v in cdr ahc collect cdr v$
610 if tr_vec then << write"gen start"$terpri()>>$
611 gen genpro_wg_l std_wg for each v in cdr ahc collect car v$
612 if tr_vec then <<write"gen end"$terpri()>>$
613
614 % generating a vector ansatz with unknown coefficients
615 nf:=1;
616 ansatz:=for each v in fino_ collect <<
617  f:=mkid('!&c,nf);
618  nf:=add1 nf$
619  fl:=cons(f,fl);
620  {'times,f,v}
621 >>$
622 fino_:=nil;
623 if tr_vec then <<
624  write"The vector ansatz has ",length fl," unknown coefficients."$terpri()
625 >>$
626 if null cdr ansatz then ansatz:=reval car ansatz
627                    else ansatz:=reval cons('plus,ansatz)$
628
629 % generate a list vl of all components of all vectors
630 vl:=for each v in cdr ahc join vc car v$
631
632% oldorder:=setkorder vl;
633
634 zro:={'list,reval {'difference,car ahc,v2c ansatz}}$
635
636 % splitting zro:
637
638 for each v in vl do <<
639  if tr_vec then <<write"splitting wrt ",v$terpri()>>$
640  sol:=cdr algebraic(for each h in lisp(zro) join coeff(lisp h,lisp v));
641  % deleting zeros
642  zro:=nil$
643  while sol do <<
644   if car sol neq 0 then zro:=cons(car sol,zro);
645   sol:=cdr sol$
646  >>$
647  if tr_vec then <<write"zro has ",length zro," conditions."$terpri()>>$
648  zro:=cons('list,zro)
649 >>$
650 if tr_vec then <<
651  write (length zro) - 1," conditions for ",length fl," unknowns."$terpri()
652 >>$
653
654 % solution of the condition:
655 !!arbint:=0$
656 if tr_vec then <<write"solveeval start"$terpri()>>$
657 sol:=solveeval list(zro,cons('list,fl));
658 if tr_vec then <<write"solveeval end"$terpri()>>$
659
660 return
661 if null cdr sol then nil
662                 else algebraic <<
663
664  ansatz:=sub(first lisp sol,lisp ansatz)$
665
666  zro:=0$
667  sol:=for h:=1:lisp !!arbint collect <<
668   v:=coeffn(ansatz,arbcomplex(h),1)$
669   zro:=zro+arbcomplex(h)*v$
670   num v
671  >>$
672  ansatz:=ansatz-zro$
673
674  % Call of CRACK to shorten the identities
675  if t then <<
676   off batch_mode$
677   lisp <<
678    print_more:=nil;
679    record_hist:=t;
680    max_gc_short:=15; % 25;
681    size_watch:=t;
682    max_gc_fac:=4;
683    print_:=nil$
684    old_history:='(l 11 !; q 0)$
685   >>$
686   sol:=crack(sol,{},lisp cons('list,extract_prod(sol)),{});
687  >>$
688
689  lisp(if tr_vec then <<write"hc2s end"$terpri()>>)$
690  cons(ansatz,first first sol)
691 >>
692end$
693%----------------------------------------------------
694
695algebraic procedure c2s(a)$
696begin scalar n$
697 return <<
698  n:=0;
699  for each h in c2sl(a) sum
700  first h + for each g in rest h sum <<
701   n:=n+1;
702   (lisp mkid('!&c,reval algebraic n))*g
703  >>
704 >>
705end$
706%----------------------------------------------------
707
708symbolic operator c2sl$
709symbolic procedure c2sl(a)$
710% converts a possibly inhom. vector expression 'a' into standard vector form
711begin scalar av,ahv,ahc,at1,tr_vec$
712 if tr_vec then <<write"c2sl start"$terpri()>>$
713 tr_vec:=nil$
714 a:=reval a$
715 av:={}$ ahv:=1$
716 while (a neq 0) and ahv do <<
717
718  % pick the first term
719  at1:=t1 a$
720  if tr_vec then <<write length a," terms to vectorize."$terpri()>>$
721
722  % extract all terms of type at1
723  ahc:=filter_hom(a,at1)$ % includes assoc list of vectors + degree
724
725  ahv:=hc2s ahc$
726  if ahv then <<av:=cons(ahv,av); a:=reval {'difference,a,car ahc}>>
727         else <<write"All the terms with the same homogeneity as the"$
728                terpri()$
729                write"following terms can not be vectorized: "$
730                mathprint at1>>
731 >>$
732
733 return
734 if null ahv then nil
735             else <<
736  if tr_vec then <<
737   terpri()$
738   write"The input expression in component form has been partitioned. Each of"$
739   terpri()$
740   write"the partitions Pi has been converted into vector form and comes with"$
741   terpri()$
742   write"identities Iij of the same homogeneity type to be used to shorten Pi."$
743   terpri()$
744   write"Everything is returned in the form {{P1,I11,I12,..},{P2,I21,..},..}."$
745   terpri()
746  >>$
747  if tr_vec then <<write"c2sl stop"$terpri()>>$
748  reval cons('list,av)
749 >>$
750
751end$
752%----------------------------------------------------
753
754symbolic procedure add_hom_term(v,at,pl)$
755% pl is an assoc list ((vl1 . terms1) (vl2 . terms2) ...) where
756% vli are assoc lists of vectors and their appearance and terms1 the sum of all
757% terms with these vectors
758% In this procedure an occurence of the pair (v . at) is added.
759begin scalar plc$
760 while pl and (caar pl neq v) do <<plc:=cons(car pl,plc);pl:=cdr pl>>$
761 if null pl then plc:=cons((v . at),plc)
762            else <<
763  plc:=cons((v . {'plus,cdar pl,at}),plc);
764  pl:=cdr pl;
765  while pl do <<plc:=cons(car pl,plc);pl:=cdr pl>>
766 >>$
767 return plc
768end$
769%----------------------------------------------------
770
771symbolic procedure shortvex(a,d)$
772% generates and uses vector identities to length reduce standard vector
773% form expressions
774% if d<>nil then it also uses identities involving n-products and thus
775% transforms the standard vector form expression 'a' into extended vector form
776begin scalar at1,pl,sh,n,wg,j,k,vli,wli,vlc,idty,gs$
777
778 % partition 'a' into parts where within each all terms have the same
779 % number of the same vectors
780 a:=reval a$
781 while a neq 0 do <<
782
783  % pick the first term
784  at1:=t1 a$
785
786  % add at1 to the right partition
787  pl:=add_hom_term(get_vlist_of_term(at1),at1,pl)$
788
789  a:=reval {'difference,a,at1}
790 >>$
791
792 % optimize the formulation in terms of n-products for each single partition
793 while pl do <<
794  vlc:=caar pl; sh:=cdar pl; pl:=cdr pl;
795  if d then <<
796   n:=length vlc;
797   k:=0;
798   vli:=nil; wli:=nil;
799   while vlc do <<
800    k:=add1 k;
801    wg:=append(for j:=1:(k-1) collect 0,cons(1,for j:=(k+1):n collect 0))$
802    vli:=cons(cons(caar vlc,wg),vli);
803    wli:=cons(cdar vlc,wli);
804    vlc:=cdr vlc
805   >>$
806  >>$
807
808  algebraic write"=========================================================="$
809  algebraic write"One partition of input: ",lisp sh$
810
811  % sh contains a specific combination of vectors encoded in vli and wli.
812  % For this combination of vectors all identities are generated next:
813  algebraic (% write"a) identities: ",
814  idty:=rest first c2sl v2c lisp t1 sh);
815
816  % now identities are generated that contain each one n-vector product
817  % expressed in terms of scalar and triple products:
818  gs:=gensym()$
819  idty:=cons('list,
820             cons(reval {'difference,sh,gs},
821                  if d then append(cdr idty,genid(reverse vli,reverse wli))
822                       else        cdr idty
823            ))$
824
825%write"idty="$prettyprint idty$
826  algebraic off batch_mode$
827  print_more:=nil;
828  record_hist:=t;
829  max_gc_short:=15; % 25;
830  size_watch:=t;
831  max_gc_fac:=4;
832  print_:=nil$
833%print_:=100000$
834  tr_short:=t$
835  old_history:='(67 e_1 nil q 0)$
836%old_history:=nil$
837  idty:=algebraic(crack(idty,{},lisp cons('list,extract_prod(idty)),{}));
838  if idty={'list} then <<write"ERROR 1 in CRACK!"$terpri()>>
839                  else <<
840   idty:=cadr cadr idty; % the remaining equations from the first solution
841   while idty and freeof(car idty,gs) do idty:=cdr idty;
842   if null idty then <<write"ERROR 2 in CRACK!"$terpri()>>
843                else <<
844    idty:=solveeval list(car idty,{'list,gs});
845    if null idty or (idty={'list}) then <<write"ERROR 3 in SOLVE!"$terpri()>>
846                                   else <<
847     idty:=caddr cadr idty$
848     if 0=reval reval {'difference,sh,idty} then
849     write"Partition is unchanged."         else <<
850      write"shortened expression:";
851      mathprint idty    % rhs of first solution
852     >>
853    >>
854   >>
855  >>$
856
857  a:=algebraic(a+idty)$
858
859  % to save memory (for now):
860  idty:=nil
861
862 >>$
863 return a
864end$
865%----------------------------------------------------
866
867symbolic operator s2s$
868symbolic procedure s2s(a)$
869shortvex(a,nil)$
870%----------------------------------------------------
871
872symbolic operator s2e$
873symbolic procedure s2e(a)$
874shortvex(a,t)$
875%----------------------------------------------------
876
877% not anymore used:
878%symbolic operator arb2zero$
879%symbolic procedure arb2zero(a)$
880%begin scalar h$
881% for h:=1:!!arbint do a:=algebraic(sub(arbcomplex(h)=0,a))$
882% !!arbint:=0$
883% return a
884%end$
885%----------------------------------------------------
886
887algebraic procedure poisson_c(f,g,poi_struc_mat)$
888% computes Poisson bracket for arbitrary expressions F,G
889% using the Poisson structure matrix poi_struc_mat
890for each h in poi_struc_mat sum (df(f,first h)*df(g,second h)-
891                                 df(g,first h)*df(f,second h) )*(third h)$
892%----------------------------------------------------
893
894algebraic procedure poisson_v(f,g,poi_struc_mat)$
895% computes the numerator of the Poisson bracket for vector expressions F,G
896% using the Poisson structure matrix poi_struc_mat.
897% It uses the global variables v_ (algebraic list of vectors) and gbase_ (an
898% algebraic Groebner basis of the identities between vectors v_).
899% If the poisson bracket for the dynamical variables (the operator poi_) is
900% not yet computed then they are initially computed in component form and for
901% that this procedure needs all relations between identifiers in the structure
902% matrix (like in the default settings kap) assigned in component form,
903% e.g. kap:=-a1**2-a2**2-a3**2$
904begin scalar h,r,s,alle$
905 alle:=reverse genpro(v_)$
906 torder(alle,lex)$
907 lisp(!!arbint:=0)$
908 h:=for each r in alle sum for each s in alle sum
909    if r=s then <<poi_(r,s):=0;0>>
910           else <<if (arglength poi_(r,s) = 2) and
911                     (part(poi_(r,s),0) = poi_) then
912                  poi_(r,s):=for each h in c2sl poisson_c(v2c r,v2c s,
913                                                          poi_struc_mat)
914                             sum first h$
915                  poi_(r,s)*df(f,r)*df(g,s)>>$
916
917 r:=preduce(num h,gbase_);
918 return
919 r
920 % The following was commented out as computing the quotient r/s
921 % can take too much memory, much more than needed for solving r=0 later
922 %
923 % if den h neq 1 then <<
924 %  s:=preduce(den h,gbase_);
925 %  if s=0 then write"Error: Poisson bracket has zero denominator!"
926 %         else r/s
927 % >>             else r
928end$
929
930% Typical use:
931%
932% hh:={poisson_v(F,G,
933%                {{U1,U2, U3}, {U2,U3, U1}, {U3,U1, U2},
934%                 {U1,V2, V3}, {U2,V3, V1}, {U3,V1, V2},
935%                 {U1,V3,-V2}, {U2,V1,-V3}, {U3,V2,-V1},
936%                 {V1,V2, kap*U3}, {V2,V3, kap*U1}, {V3,V1, kap*U2}})};
937% for each g in genpro {a,b,u,v} do
938% hh:=for each h in hh join coeff(h,g)$
939%----------------------------------------------------
940
941symbolic procedure symaddweights(vwghts,exl)$
942% vweights is an algebraic list like {{a,1,0,0},{b,0,1,0},{u,0,0,1},{v,1,0,1}}
943% exl is a list of homogeneous standard vector expressions
944% The procedure returns a lisp list of lisp lists like vweights,
945% only with the exl-expressions instead of vectors as first elements of
946% the sub-lists.
947
948begin scalar h,g,k,wg,p,v,n$
949 return
950 for each h in cdr exl collect <<
951  h:=reval h;
952  g:=t1 h$
953  k:=get_vlist_of_term g$ % k is an assoc list of all vectors with
954                          % their multiplicity
955  wg:=for each p in cddadr vwghts collect 0$
956  while k do <<
957   p:=car k; k:=cdr k;
958   v:=cdr vwghts;
959   while v and cadar v neq car p do v:=cdr v;
960   v:=cddar v;     % v is the weight list of car p
961   for n:=1:cdr p do wg:=addvectowg(wg,v)
962  >>$
963
964  cons(h,wg)
965 >>
966end$
967%----------------------------------------------------
968
969symbolic operator addweights$
970symbolic procedure addweights(vwghts,exl)$
971% The same as symaddweights, only returning an algebraic list of alg. lists
972cons('list,for each h in symaddweights(vwghts,exl) collect cons('list,h))$
973%----------------------------------------------------
974
975lisp(nfct_:=1)$  % defined in crack
976
977symbolic operator gfi$
978symbolic procedure gfi(wgcp,alle,fdep,heads)$
979begin scalar k,g,h,p,rtn,dropped1,dropped2,f,fl,gt1$
980  % - If one wants a specific factor then this factor has to be multiplied
981  %   afterwards and gfi has to be given appropriate lowered weights
982  % - dropped1 is the number of terms dropped as they can be replaced
983  %   using products of powers of Casimirs, Hamiltonians and known
984  %   first integrals.
985  % - dropped2 is the number of terms dropped due to general relationships
986  %   of 3-component vectors.
987
988  % At first we generate all possible terms with proper multi-weight
989  wgths_:=cdr wgcp$
990  fino_:=nil$
991  gen(for each h in cdr reval algebraic genpro_wg alle collect cdr h);
992
993  % Then we drop all terms that are reducible due to identities
994  dropped2:=0;
995  while fino_ do <<
996   h:=reval car fino_; fino_:=cdr fino_;
997   if algebraic is_reduceable(lisp h,heads) then dropped2:=add1 dropped2
998                                            else rtn:=cons(h,rtn)
999  >>$
1000
1001  % Now we drop all terms that could be killed through expressions
1002  % functionally dependent on expressions in fdep
1003
1004  % 1. finding and adding the weight lists producing a lisp list of lisp lists
1005  fdep:=symaddweights(alle,fdep)$
1006
1007  dropped1:=0;
1008  fino_:=nil$
1009  gen fdep;
1010  for each h in fino_ do << % i.e. for each functionally dependent expression
1011   h:=reval h$
1012   h:=if not pairp h then list h else
1013      if (car h='plus) or (car h='difference) then cdr h else list h;
1014   gt1:=nil$
1015
1016   while h do <<
1017    g:=car h$ h:=cdr h$ % g is one term of the funct. dep. expression
1018    % drop minus sign
1019    if pairp g and car g='minus then g:=cadr g;
1020    % drop numerical denominator
1021    if pairp g and car g='quotient and numberp caddr g then g:=cadr g;
1022    % drop numerical factor
1023    if pairp g and car g='times then <<
1024     p:=nil;
1025     for each k in cdr g do % i.e. for each factor
1026     if numberp k or
1027        (pairp k and
1028         car k = 'quotient and
1029         numberp cadr k and
1030         numberp caddr k) then p:=cons(k,p);
1031     if p then <<
1032      if cdr p then p:=cons('times,p)
1033               else p:=car p;
1034      g:=reval {'quotient,g,p}
1035     >>
1036    >>$
1037    if null member(g,rtn) then <<gt1:=nil; % hcp is not contained in ansatz
1038                                 h:=nil>>  % to stop looking at further terms
1039                          else if null gt1 then gt1:=g
1040   >>$ % all terms of h have been looked at
1041   if gt1 then << % funct. dep. expression is still in the ansatz,
1042                  % --> drop gt1 from ansatz
1043    dropped1:=add1 dropped1$
1044    rtn:=delete(gt1,rtn)
1045   >>$
1046
1047  >>$
1048
1049  % The remaining terms get an undetermined coefficient and are added up
1050  fino_:=rtn$  rtn:=nil$
1051  while fino_ do <<
1052   h:=reval car fino_; fino_:=cdr fino_;
1053   f:=mkid('!&r,nfct_)$
1054   nfct_:=add1 nfct_$
1055   fl:=cons(f,fl)$
1056   rtn:=cons({'times,f,h},rtn)
1057  >>$
1058
1059  if tr_vec then
1060  write"dropped: ",dropped1,"+",dropped2," kept: ",length rtn$
1061  return reval
1062         cons('list,if null rtn then nil else
1063                    cons(if cdr rtn then cons('plus,rtn)
1064                                    else car rtn,
1065                         fl))
1066end$
1067%----------------------------------------------------
1068
1069algebraic procedure gpi(wgl,vl,gbase)$
1070% subroutine to generate polynomial identities between vectors
1071% as used by vinit().
1072begin scalar hh,vcl,id,fl,g,h$
1073 hh:=lisp(cons('list,for each h in std_wg(cdr vl) collect
1074                     cons('list,h)));
1075 hh:=gfi(wgl,hh,{},{});
1076 if hh neq {} then <<
1077  id:=first hh$
1078  fl:=rest hh$
1079  hh:={v2c id}$
1080  vcl:=for each h in vl join lisp cons('list,vc reval h);
1081  for each g in vcl do
1082  hh:=for each h in hh join coeff(h,g)$
1083  lisp(!!arbint:=0)$
1084  hh:=solve(hh,fl)$
1085  id:=sub(first hh,id);
1086  id:=for h:=1:lisp(!!arbint) collect num coeffn(id,arbcomplex(h),1);
1087
1088  for each h in id do
1089  if not fixp h then
1090  if gbase={} then gbase:={h}
1091              else <<
1092   h:=preduce(h,gbase);
1093   if h neq 0 then gbase:=groebner(cons(h,gbase))
1094  >>
1095 >>;
1096 return gbase
1097end$
1098%----------------------------------------------------
1099
1100algebraic procedure vinit(alle)$
1101% generates all polynomial identities gbase_ for all scalar and triple
1102% products from the 4 vectors in the list alle
1103begin scalar i,j,k,l,natbak$
1104 v_:=alle$
1105 torder(reverse genpro v_,lex)$
1106 gbase_:={};
1107 on gltbasis$
1108 for i:=0:3 do  % here for exactly 4 vectors
1109 for j:=0:3 do
1110 for k:=0:3 do
1111 for l:=0:3 do
1112 if ((i+j+k+l)> 0) and
1113    ((i+j+k+l)<11) then gbase_:=gpi({i,j,k,l},v_,gbase_)$
1114 heads_:=gltp$
1115 on nat
1116end$
1117%----------------------------------------------------
1118
1119symbolic procedure wg_li(a,vlw)$
1120% checks whether expression 'a' is homogeneous wrt to vlw which
1121% is a list of variables with weights, e.g.
1122%        vlw=((A 1 0 0) (B 0 1 0) (U 0 0 1) (V 1 0 1))$
1123% and in this case return the weightlist of 'a'
1124% It assumes the expression is a polynomial in the vectors, so any
1125% denominator is disregarded.
1126begin scalar wg,at1,h,wl,n,vlwcp,errorcd,m$
1127 a:=reval a$
1128 if pairp a and car a = 'quotient then a:=cadr a$
1129 a:=if pairp a and car a = 'plus then cdr a
1130                                 else list a$
1131
1132 repeat <<
1133  at1:=car a$  a:=cdr a$
1134  h:=get_vlist_of_term(at1)$  % e.g.   ((a . 1) (b . 1) (u . 2))
1135
1136  % to get total weightlist wl of the term el1 add for each vector its
1137  % weightlist times its multiplicity
1138  wl:=for n:=1:(length cdar vlw) collect 0;
1139  while h do <<
1140   vlwcp:=vlw$
1141   while vlwcp and ((caar vlwcp) neq (caar h)) do vlwcp:=cdr vlwcp;
1142   if null vlwcp then <<errorcd:=1;
1143                        write"Unspecified vector ",caar h," found!"$
1144                        terpri()>>
1145                 else for m:=1:(cdar h) do wl:=addvectowg(wl,cdar vlwcp)$
1146                      % adds weightlist of caar h to the vector wl
1147   h:=cdr h
1148  >>$
1149
1150  if null wg then wg:=wl else
1151  if wg neq wl then <<errorcd:=2;write"Expression is inhomogeneous!"$terpri()>>
1152 >> until null a or errorcd;
1153 return
1154 if errorcd then nil
1155            else wg
1156end$
1157%----------------------------------------------------
1158
1159symbolic operator fnc_dep$
1160symbolic procedure fnc_dep(a,li,vlw)$
1161% investigates whether 'a' is functionally
1162% independent of the elements of the list li or not.
1163% vlw is a list of variables with weights, e.g.
1164%        vlw={{A,1,0,0},{B,0,1,0},{U,0,0,1},{V,1,0,1}}$
1165% It uses the global variables v_ (algebraic list of vectors) and gbase_ (an
1166% algebraic Groebner basis of the identities between vectors v_).
1167begin scalar el,h,subli1,subli2,g,para,f,cnd,fl,ansatz,pl,n$
1168
1169 vlw:=for each el in cdr vlw collect cdr el;
1170 % check homogeneity of 'a' and each element el of li and
1171 % prepare a weight list for 'a' and el
1172 wgths_:=wg_li(a,vlw)$
1173
1174 h:=for each g in wgths_ sum g;
1175 if zerop h then return nil;
1176
1177 n:=0;
1178 for each el in cdr li do <<
1179  h:=gensym()$
1180  subli1:=cons({'equal,h,el},subli1);
1181  n:=add1 n$
1182  subli2:=cons({'equal,h,mkid('p_,n)},subli2);
1183  g:=wg_li(el,vlw)$
1184  para:=cons(cons(h,g),para)
1185 >>$
1186 subli1:=cons('list,subli1)$
1187 subli2:=cons('list,subli2)$
1188
1189 fino_:=nil;gen para;
1190
1191 if null fino_ then return nil$
1192 % write"wgths_=",wgths_$terpri()$
1193 % write"subli1=",subli1$  terpri()$
1194 % write"subli2=",subli2$  terpri()$
1195 % write"para=",para$    terpri()$
1196
1197 while fino_ do <<
1198  h:=reval car fino_; fino_:=cdr fino_;
1199  f:=mkid('!&r,nfct_)$
1200  nfct_:=add1 nfct_$
1201  fl:=cons(f,fl)$
1202  ansatz:=cons({'times,f,h},ansatz)
1203 >>$
1204 fl:=cons('list,fl)$
1205 ansatz:=cons('plus,ansatz);
1206 cnd:=reval {'difference,a,algebraic(sub(subli1,lisp ansatz))};
1207
1208 return
1209 algebraic <<
1210
1211  pl:=reverse genpro(v_)$
1212  torder(pl,lex)$
1213  cnd:={preduce(cnd,gbase_)}$
1214  for each g in pl do
1215  cnd:=for each h in cnd join coeff(h,g)$
1216
1217  h:=solve(cnd,fl)$
1218
1219  if h neq {} then <<
1220   lisp <<
1221    write "The expression in question is functionally dependent on"$
1222    terpri()$
1223    write "the list of expressions {p_1,p_2,...} in the following way:"$
1224   >>$
1225   write sub(subli2,sub(first h,ansatz));
1226   t
1227  >>          else nil
1228 >>
1229
1230end$
1231%----------------------------------------------------
1232
1233algebraic  <<
1234v_:={a,b,u,v}$
1235
1236torder(reverse genpro v_,lex)$
1237
1238gbase_ :={ - bb*uu*vv + bb*uv**2 + bu**2*vv - 2*bu*bv*uv + buv**2 + bv**2*uu,
1239 - ab*uu*vv + ab*uv**2 + au*bu*vv - au*bv*uv + auv*buv - av*bu*uv + av*bv*uu,
1240 - ab*bu*vv + ab*bv*uv + abv*buv + au*bb*vv - au*bv**2 - av*bb*uv + av*bu*bv,
1241 - ab*bu*uv + ab*bv*uu + abu*buv + au*bb*uv - au*bu*bv - av*bb*uu + av*bu**2,
1242 - abu*vv + abv*uv - auv*bv + av*buv,
1243 - abu*uv + abv*uu + au*buv - auv*bu,
1244ab*buv - abu*bv + abv*bu - auv*bb,
1245aa*buv - ab*auv - abu*av + abv*au,
1246 - aa*uu*vv + aa*uv**2 + au**2*vv - 2*au*av*uv + auv**2 + av**2*uu,
1247 - aa*bu*vv + aa*bv*uv + ab*au*vv - ab*av*uv + abv*auv - au*av*bv + av**2*bu,
1248 - aa*bu*uv + aa*bv*uu + ab*au*uv - ab*av*uu + abu*auv - au**2*bv + au*av*bu,
1249abu*au*vv - abu*av*uv - abv*au*uv + abv*av*uu + au*auv*bv - auv*av*bu,
1250ab*abu*vv - ab*abv*uv + ab*auv*bv - abu*av*bv + abv*av*bu - auv*av*bb,
1251aa*abu*vv - aa*abv*uv + aa*auv*bv - ab*auv*av - abu*av**2 + abv*au*av,
1252ab*abu*uv - ab*abv*uu + ab*auv*bu - abu*au*bv + abv*au*bu - au*auv*bb,
1253aa*abu*uv - aa*abv*uu + aa*auv*bu - ab*au*auv - abu*au*av + abv*au**2,
1254aa*abu*bv - aa*abv*bu + aa*auv*bb - ab**2*auv - ab*abu*av + ab*abv*au,
1255 - aa*bb*vv + aa*bv**2 + ab**2*vv - 2*ab*av*bv + abv**2 + av**2*bb,
1256 - aa*bb*uv + aa*bu*bv + ab**2*uv - ab*au*bv - ab*av*bu + abu*abv + au*av*bb,
1257 - ab*abu*bu*vv + ab*abu*bv*uv + ab*abv*bu*uv - ab*abv*bv*uu + abu*au*bb*vv -
1258abu*au*bv**2 - abu*av*bb*uv + abu*av*bu*bv - abv*au*bb*uv + abv*au*bu*bv +
1259abv*av*bb*uu - abv*av*bu**2,
1260 - aa*abu*bu*vv + aa*abu*bv*uv + aa*abv*bu*uv - aa*abv*bv*uu + ab*abu*au*vv -
1261ab*abu*av*uv - ab*abv*au*uv + ab*abv*av*uu - abu*au*av*bv + abu*av**2*bu +
1262abv*au**2*bv - abv*au*av*bu,
1263 - aa*abu*bb*vv + aa*abu*bv**2 + aa*abv*bb*uv - aa*abv*bu*bv + ab**2*abu*vv -
1264ab**2*abv*uv - 2*ab*abu*av*bv + ab*abv*au*bv + ab*abv*av*bu + abu*av**2*bb -
1265abv*au*av*bb,
1266 - aa*abu*bb*uv + aa*abu*bu*bv + aa*abv*bb*uu - aa*abv*bu**2 + ab**2*abu*uv -
1267ab**2*abv*uu - ab*abu*au*bv - ab*abu*av*bu + 2*ab*abv*au*bu + abu*au*av*bb -
1268abv*au**2*bb,
1269 - aa*bb*uu + aa*bu**2 + ab**2*uu - 2*ab*au*bu + abu**2 + au**2*bb,
1270aa*bb*uu*vv - aa*bb*uv**2 - aa*bu**2*vv + 2*aa*bu*bv*uv - aa*bv**2*uu -
1271ab**2*uu*vv + ab**2*uv**2 + 2*ab*au*bu*vv - 2*ab*au*bv*uv - 2*ab*av*bu*uv +
12722*ab*av*bv*uu - au**2*bb*vv + au**2*bv**2 + 2*au*av*bb*uv - 2*au*av*bu*bv -
1273av**2*bb*uu + av**2*bu**2}$
1274
1275heads_ :=
1276{buv**2,auv*buv,abv*buv,abu*buv,av*buv,au*buv,ab*buv,aa*buv,auv**2,abv*auv,
1277abu*auv,au*auv*bv,ab*auv*bv,aa*auv*bv,ab*auv*bu,aa*auv*bu,aa*auv*bb,abv**2,abu
1278*abv,ab*abv*bu*uv,aa*abv*bu*uv,aa*abv*bb*uv,aa*abv*bb*uu,abu**2,aa*bb*uu*vv}$
1279
1280>>;
1281
1282% kap:=!&eta**2$
1283% kap:=-a1**2-a2**2-a3**2$
1284%
1285% so(4),so(3,1),e(3)
1286% STRUC_CONS:={{U1,U2, U3}, {U2,U3, U1}, {U3,U1, U2},
1287%              {U1,V2, V3}, {U2,V3, V1}, {U3,V1, V2},
1288%              {U1,V3,-V2}, {U2,V1,-V3}, {U3,V2,-V1},
1289%              {V1,V2, kap*U3}, {V2,V3, kap*U1}, {V3,V1, kap*U2}}$
1290%
1291% so(3):
1292% STRUC_CONS:={{U1,U2, U3}, {U2,U3, U1}, {U3,U1, U2}}$
1293%
1294% e(3):
1295% STRUC_CONS:={{U1,U2, U3}, {U2,U3, U1}, {U3,U1, U2},
1296%              {U1,V2, V3}, {U2,V3, V1}, {U3,V1, V2},
1297%              {U1,V3,-V2}, {U2,V1,-V3}, {U3,V2,-V1} }$
1298%
1299% so(4):
1300% STRUC_CONS:={{U1,U2, U3}, {U2,U3, U1}, {U3,U1, U2},
1301%              {U1,V2, V3}, {U2,V3, V1}, {U3,V1, V2},
1302%              {U1,V3,-V2}, {U2,V1,-V3}, {U3,V2,-V1},
1303%              {V1,V2, U3}, {V2,V3, U1}, {V3,V1, U2} }$
1304%
1305% so(3,1):
1306% STRUC_CONS:={{U1,U2, U3}, {U2,U3, U1}, {U3,U1, U2},
1307%              {U1,V2, V3}, {U2,V3, V1}, {U3,V1, V2},
1308%              {U1,V3,-V2}, {U2,V1,-V3}, {U3,V2,-V1},
1309%              {V1,V2,-U3}, {V2,V3,-U1}, {V3,V1,-U2} }$
1310%
1311% so(3)^2:
1312% STRUC_CONS:={{U1,U2, U3}, {U2,U3, U1}, {U3,U1, U2},
1313%              {V1,V2, V3}, {V2,V3, V1}, {V3,V1, V2} }$
1314
1315end$
1316