source: git/Singular/LIB/zeroset.lib @ 35f23d

spielwiese
Last change on this file since 35f23d was 35f23d, checked in by Hans Schönemann <hannes@…>, 23 years ago
*hannes?tbayer: lib revisited git-svn-id: file:///usr/local/Singular/svn/trunk@4925 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 46.4 KB
Line 
1///////////////////////////////////////////////////////////////////////////////
2version="Id: zeroset.lib,v 1.0 2000/05/19 12:32:15 Singular Exp $";
3info="
4LIBRARY:  zeroset.lib      PROCEDURES FOR ROOTS AND FACTORIZATION
5
6AUTHOR:   Thomas Bayer,    email: bayert@in.tum.de
7
8PROCEDURES:
9
10 EGCD(f, g)    gcd over an algebraic extension field of Q
11 Factor(f)    factorization of f over an algebraic extension field
12 InvertNumber(c)  inverts an element of an algebraic extension field
13 LinearZeroSet(I)  find the linear (partial) solution of I
14 Quotient(f, g)    quotient q  of f w.r.t. g (in f = q*g + remainder)
15 Remainder(f,g)    remainder of the division of f by g
16 Roots(f)    computes all roots of f in an extension field of Q
17 SQFRNorm(f)    norm of f (f must be square-free)
18 ZeroSet(I)    zero-set of the 0-dim. ideal I
19
20SUB PROCEDURES:
21
22 EGCDMain(f, g)    gcd over an algebraic extension field of Q
23 FactorMain(f)    factorization of f over an algebraic extension field
24 InvertNumberMain(c)  inverts an element of an algebraic extension field
25 QuotientMain(f, g)  quotient of f w.r.t. g
26 RemainderMain(f,g)  remainder of the division of f by g
27 RootsMain(f)    computes all roots of f,might extend the groundfield
28 SQFRNormMain(f)  norm of f (f must be square-free)
29 ContainedQ(data, f)  f in data ?
30 SameQ(a, b)    a == b (list a,b)
31 TransferRing()    create a new basering (to use ...Main())
32 NewBaseRing()    create a new basering (return from  ...Main())
33 SimplifyData(data)  reduces entries of data w.r.t. mpoly
34 SimplifyPoly(f)  reduces coefficients of f w.r.t. mpoly
35 SimplifySolution(sol)  reduces the entries of sol w.r.t. the ideal mpoly
36
37 NOTE: this library is meant as a preliminary extension of the functionality
38 of Singular for univariate factorization of polynomials over simple algebraic
39 extensions in characteristic 0.
40 Subprocedures with postfix 'Main' require that the ring contains a variable
41 'a' and no parameters, and the ideal 'mpoly', where 'minpoly' from the
42 basering is stored.
43";
44
45// NOTE: This library has been written in the frame of the diploma thesis
46// 'Computing moduli spaces of semiquasihomogeneous singularites and an
47//  implementation in Singular', Arbeitsgruppe Algebraische Geometrie,
48// Fachbereich Mathematik, University Kaiserslautern,
49// Advisor: Prof. Gert-Martin Greuel
50
51// note : return a ring : ring need not be exported !!!
52
53// Arithmetic in Q(a)[x] without built-in procedures
54// assume basering = Q[x,a] and minpoly is represented by mpoly(a).
55// the algorithms are taken from "Polynomial Algorithms in Computer Algebra",
56// F. Winkler, Springer Verlag Wien, 1996.
57
58
59// To do :
60// square-free factorization
61// multiplicities
62
63// Improvement :
64// a main problem is the growth of the coefficients. Try Roots(x7 - 1)
65// return ideal mpoly !
66// mpoly is not monic, comes from primitive_extra
67
68// IMPLEMENTATION (last change: 10.12.2000)
69//
70// In procedures with name 'proc-name'Main a polynomial ring over a simple
71// extension field is represented as Q[x...,a] together with the ideal
72// 'mpoly' (attribute "isSB"). The arithmetic in the extension field is
73// implemented in the procedures in the procedures 'MultPolys' (multiplication)
74// and 'InvertNumber' (inversion). After addition and subtraction one should
75// apply 'SimplifyPoly' to the result to reduce the result w.r.t. 'mpoly'.
76// This is done by reducing each coefficient separately, which is more
77// efficient for polynomials with many terms.
78
79
80LIB "primitiv.lib";
81LIB "primdec.lib";
82
83///////////////////////////////////////////////////////////////////////////////
84
85proc Roots(poly f)
86"USAGE:   Roots(f); poly f
87PURPOSE: compute all roots of f in a finite extension of the groundfield
88         without multiplicities.
89RETURN:  ring, a polynomial ring over an extension field of the ground field,
90         containing a list 'roots', poly 'newA', poly 'f':
91   - 'roots' is the list of roots of the polynomial f (no multiplicities)
92         - if the groundfield is Q(a') and the extension field is Q(a), then
93     'newA' is the representation of a' in Q(a). If the basering
94           contains a parameter 'a' and the minpoly remains unchanged then
95           'newA' = 'a'. If the basering does not contain a parameter then
96           'newA' = 'a' (default).
97   - 'f' is the polynomial f in  Q(a) (a' being substituted by newA)
98ASSUME:  ground field to be Q or a simple extension of Q given by a minpoly
99EXAMPLE: example  Roots; shows an example
100"
101{
102  int dbPrt = printlevel-voice+3;
103
104  // create a new ring where par(1) is replaced by the variable
105  // with the same name or, if basering does not contain a parameter,
106  // with a new variable 'a'.
107
108  def ROB = basering;
109  def ROR = TransferRing(basering);
110  setring ROR;
111  export(ROR);
112
113  // get the polynomial f and find the roots
114
115  poly f = imap(ROB, f);
116  list result = RootsMain(f);  // find roots of f
117
118  // store the roots and the the new representation of 'a' and transform
119  // the coefficients of f.
120
121  list roots = result[1];
122  poly newA = result[2];
123  map F = basering, maxideal(1);
124  F[nvars(basering)] = newA;
125  poly fn = SimplifyPoly(F(f));
126
127  // create a new ring with minploy = mpoly[1] (from ROR)
128
129  def RON = NewBaseRing();
130  setring(RON);
131  list roots = imap(ROR, roots);
132  poly newA = imap(ROR, newA);
133  poly f = imap(ROR, fn);
134  kill(ROR);
135  export(roots);
136  export(newA);
137  export(f); dbprint(dbPrt,"
138// 'Roots' created a new ring which contains the list 'roots' and
139// the polynomials 'f' and 'newA'
140// To access the roots, newA and the new representation of f, type
141   def R = Roots(f); setring R; roots; newA; f;
142");
143  return(RON);
144}
145example
146{"EXAMPLE:";  echo = 2;
147  ring R = (0,a), x, lp;
148  minpoly = a2+1;
149  poly f = x3 - a;
150  def R1 = Roots(f);
151  setring R1;
152  minpoly;
153  newA;
154  f;
155  roots;
156  map F;
157  F[1] = roots[1];
158  F(f);
159}
160
161///////////////////////////////////////////////////////////////////////////////
162
163proc RootsMain(poly f)
164"USAGE:   RootsMain(f); poly f
165PURPOSE: compute all roots of f in a finite extension of the groundfield
166         without multiplicities.
167RETURN:  list, all entries are polynomials
168  _[1] = roots of f, each entry is a polynomial
169  _[2] = 'newA'  - if the groundfield is Q(a') and the extension field
170               is Q(a), then 'newA' is the representation of a' in Q(a)
171  _[3] = minpoly of the algebraic extension of the groundfield
172ASSUME:  basering = Q[x,a]
173   ideal mpoly must be defined, it might be 0 !
174NOTE:    might change the ideal mpoly !!
175EXAMPLE: example  Roots; shows an example
176"
177{
178  int i, linFactors, nlinFactors, dbPrt;
179  intvec wt = 1,0;    // deg(a) = 0
180  list factorList, nlFactors, nlMult, roots, result;
181  poly fa, lc;
182
183  dbPrt = printlevel-voice+3;
184
185  // factor f in Q(a)[t] to obtain the roots lying in Q(a)
186  // firstly, find roots of the linear factors,
187  // nonlinear factors are processed later
188
189  dbprint(dbPrt, "Roots of " + string(f) +  ", minimal polynomial = " + string(mpoly[1]));
190  factorList = FactorMain(f);          // Factorize f
191  dbprint(dbPrt, (" prime factors of f are : " + string(factorList[1])));
192
193  linFactors = 0;
194  nlinFactors = 0;
195  for(i = 2; i <= size(factorList[1]); i = i + 1) {  // find linear and nonlinear factors
196    fa = factorList[1][i];
197    if(deg(fa, wt) == 1) {
198      linFactors++;        // get the root from the linear factor
199      lc = LeadTerm(fa, 1)[3];
200      fa = MultPolys(InvertNumberMain(lc), fa); // make factor monic
201      roots[linFactors] = var(1) - fa;  // fa is monic !!
202    }
203    else {            // ignore nonlinear factors
204      nlinFactors++;
205      nlFactors[nlinFactors] = factorList[1][i];
206      nlMult[nlinFactors] = factorList[2][i];
207    }
208  }
209  if(linFactors == size(factorList[1]) - 1) {    // all roots of f are contained in the groundfield
210    result[1] = roots;
211    result[2] = var(2);
212    result[3] = mpoly[1];
213    return(result);
214  }
215
216  // process the nonlinear factors, i.e., extend the groundfield
217  // where a nonlinear factor (irreducible) is a minimal polynomial
218  // compute the primitive element of this extension
219
220  ideal primElem, minPolys, Fid;
221  list partSol;
222  map F, Xchange;
223  poly f1, newA, mp, oldMinPoly;
224
225  Fid = mpoly;
226  F[1] = var(1);
227  Xchange[1] = var(2);      // the variables have to be exchanged
228  Xchange[2] = var(1);      // for the use of 'primitive'
229
230  if(nlinFactors == 1) {            // one nl factor
231
232    // compute the roots of the nonlinear (irreducible, monic) factor f1 of f
233    // by extending the basefield by a' with minimal polynomial f1
234    // Then call Roots(f1) to find the roots of f1 over the new base field
235
236    f1 = nlFactors[1];
237    if(mpoly[1] != 0) {
238      mp = mpoly[1];
239      minPolys = Xchange(mp), Xchange(f1);
240      primElem = primitive_extra(minPolys);  // no random coord. change
241      mpoly = std(primElem[1]);
242      F = basering, maxideal(1);
243      F[2] = primElem[2];      // transfer all to the new representation
244      newA = primElem[2];      // new representation of a
245      f1 = SimplifyPoly(F(f1));     //reduce(F(f1), mpoly);
246      if(size(roots) > 0) {roots = SimplifyData(F(roots));}
247    }
248    else {
249      mpoly = std(Xchange(f1));
250      newA = var(2);
251    }
252    result[3] = mpoly[1];
253    oldMinPoly = mpoly[1];
254    partSol = RootsMain(f1);    // find roots of f1 over extended field
255
256    if(oldMinPoly != partSol[3]) {    // minpoly has changed ?
257      // all previously computed roots must be transformed
258      // because the minpoly has changed
259      result[3] = partSol[3];    // new minpoly
260      F[2] = partSol[2];    // new representation of algebraic number
261      if(size(roots) > 0) {roots = SimplifyData(F(roots)); }
262      newA = SimplifyPoly(F(newA)); // F(newA);
263    }
264    roots = roots + partSol[1];  // add roots
265    result[2] = newA;
266    result[1] = roots;
267  }
268  else {  // more than one nonlinear (irreducible) factor (f_1,...,f_r)
269    // solve each of them by RootsMain(f_i), append their roots
270    // change the minpoly and transform all previously computed
271    // roots if necessary.
272    // Note that the for-loop is more or less book-keeping
273
274    newA = var(2);
275    result[2] = newA;
276    for(i = 1; i <= size(nlFactors); i = i + 1) {
277      oldMinPoly = mpoly[1];
278      partSol = RootsMain(nlFactors[i]);    // main work
279      nlFactors[i] = 0;        // delete factor
280      result[3] = partSol[3];        // store minpoly
281
282      // book-keeping starts here as in the case 1 nonlinear factor
283
284      if(oldMinPoly != partSol[3]) { // minpoly has changed
285        F = basering, maxideal(1);
286        F[2] = partSol[2];    // transfer all to the new representation
287        newA = SimplifyPoly(F(newA));    // F(newA); new representation of a
288        result[2] = newA;
289        if(i < size(nlFactors)) {
290          nlFactors = SimplifyData(F(nlFactors));
291        } // transform remaining factors
292        if(size(roots) > 0) {roots = SimplifyData(F(roots));}
293      }
294      roots = roots + partSol[1];    // transform roots
295      result[1] = roots;
296    }  // end more than one nl factor
297
298  }
299  return(result);
300}
301
302///////////////////////////////////////////////////////////////////////////////
303
304proc ZeroSet(ideal I, list #)
305"USAGE:   ZeroSetMain(ideal I [, int opt]); ideal I, int opt
306PURPOSE: compute the zero-set of the zero-dim. ideal I, in a finite extension
307         of the groundfield.
308RETURN:  ring, a polynomial ring over an extension field of the ground field,
309         containing a list 'zeroset', a polynomial 'newA', and an ideal 'id'.
310   - 'zeroset'  is list of the zeros of the ideal 'I', each zero is
311           an ideal.
312         - if the groundfield is Q(a') and the extension field is Q(a), then
313     'newA' is the representation of a' in Q(a).  If the basering
314           contains a parameter 'a' and the minpoly remains unchanged then
315           'newA' = 'a'. If the basering does not contain a parameter then
316           'newA' = 'a' (default).
317   - 'id' is the ideal 'I'  in Q(a)[x_1,...] (a' substituted by 'newA')
318ASSUME:  dim(I) = 0, and ground field to be Q or a simple extension of Q
319         given by a minpoly.
320OPTIONS: opt = 0 no primary decomposition (default)
321   opt > 0 primary decomposition
322NOTE:    If I contains an algebraic number (parameter) then 'I' must be
323         transformed w.r.t. 'newA' in the new ring.
324EXAMPLE: example ZeroSet; shows an example
325"
326{
327  int primaryDecQ, dbPrt;
328  list rp;
329
330  dbPrt = printlevel-voice+2;
331
332  if(size(#) > 0) { primaryDecQ = #[1]; }
333  else { primaryDecQ = 0; }
334
335  // create a new ring 'ZSR' with one additional variable instead of the parameter
336  // if the basering does not contain a parameter then 'a' is used as the additional variable.
337
338  def RZSB = basering;
339  def ZSR = TransferRing(basering);
340  setring ZSR;
341  export(ZSR);
342
343  // get ideal I and find the zero-set
344
345  ideal id = std(imap(RZSB, I));
346        print(dim(id));
347        if(dim(id) > 1) {       // new variable adjoined to ZSR
348                ERROR(" ideal not zerodimensional ");
349        }
350
351  list result = ZeroSetMain(id, primaryDecQ);
352
353  // store the zero-set, minimal polynomial and the new representative of 'a'
354
355  list zeroset = result[1];
356  poly newA = result[2];
357  poly minPoly = result[3][1];
358
359  // transform the generators of the ideal I w.r.t. the new representation of 'a'
360
361  map F = basering, maxideal(1);
362  F[nvars(basering)] = newA;
363  id = SimplifyData(F(id));
364
365  // create a new ring with minpoly = minPoly
366
367  def RZBN = NewBaseRing();
368  setring RZBN;
369
370  list zeroset = imap(ZSR, zeroset);
371  poly newA = imap(ZSR, newA);
372  ideal id = imap(ZSR, id);
373  kill(ZSR);
374
375  export(id);
376  export(zeroset);
377  export(newA);
378    dbprint(dbPrt,"
379// 'ZeroSet' created a new ring which contains the list 'zeroset', the ideal
380// 'id' and the polynomial 'newA'. 'id' is the ideal of the input transformed
381// w.r.t. 'newA'.
382// To access the zero-set, 'newA' and the new representation of the ideal, type
383   def R = ZeroSet(I); setring R; zeroset; newA; id;
384");
385  return(RZBN);
386}
387example
388{"EXAMPLE:";  echo = 2;
389  ring R = (0,a), (x,y,z), lp;
390  minpoly = a2 + 1;
391  ideal I = x2 - 1/2, a*z - 1, y - 2;
392  def T = ZeroSet(I);
393  setring T;
394  minpoly;
395  newA;
396  id;
397  zeroset;
398  map F1 = basering, zeroset[1];
399  map F2 = basering, zeroset[2];
400  F1(id);
401  F2(id);
402}
403
404///////////////////////////////////////////////////////////////////////////////
405
406proc InvertNumberMain(poly f)
407"USAGE:   InvertNumberMain(f); poly f
408PURPOSE: compute 1/f if f is a number in Q(a) i.e., f is represented by a
409         polynomial in Q[a].
410RETURN:  poly 1/f
411ASSUME:  basering = Q[x_1,...,x_n,a], ideal 'mpoly' must be defined and != 0
412"
413{
414  if(diff(f, var(1)) != 0) { ERROR("number must not contain variable !");}
415
416  int n = nvars(basering);
417  def RINB = basering;
418  string ringSTR = "ring RINR = 0, " + string(var(n)) + ", dp;";
419  execute(ringSTR);        // new ring = Q[a]
420
421  list gcdList;
422  poly f, g, inv;
423
424  f = imap(RINB, f);
425  g = imap(RINB, mpoly)[1];
426
427  if(diff(f, var(1)) != 0) { inv = extgcd(f, g)[2]; }  // f contains var(1)
428  else {  inv = 1/f;}          // f element in Q
429
430  setring(RINB);
431  return(imap(RINR, inv));
432}
433
434///////////////////////////////////////////////////////////////////////////////
435
436proc MultPolys(poly f, poly g)
437"USAGE:   MultPolys(f, g); poly f,g
438PURPOSE: multiply the polynomials f and g and reduce them w.r.t. mpoly
439RETURN:  poly f*g
440ASSUME:  basering = Q[x,a], ideal mpoly must be defined, it might be 0 !
441"
442{
443  return(SimplifyPoly(f * g));
444}
445
446///////////////////////////////////////////////////////////////////////////////
447
448proc LeadTerm(poly f, int i)
449"USAGE:   LeadTerm(f); poly f, int i
450PURPOSE: compute the leading coef and term of f w.r.t var(i), where the last
451         ring variable is treated as a parameter.
452RETURN:  list of polynomials
453         _[1] = leading term
454         _[2] = leading monomial
455         _[3] = leading coefficient
456ASSUME:  basering = Q[x_1,...,x_n,a]
457"
458{
459  list result;
460  matrix co = coef(f, var(i));
461  result[1] = co[1, 1]*co[2, 1];
462  result[2] = co[1, 1];
463  result[3] = co[2, 1];
464  return(result);
465}
466
467///////////////////////////////////////////////////////////////////////////////
468
469proc Quotient(poly f, poly g)
470"USAGE:   Quotient(f, g); poly f, g;
471PURPOSE: compute the quotient q and remainder r s.t. f = g*q + r, deg(r) < g
472RETURN:  list of polynomials
473         _[1] = quotient  q
474         _[2] = remainder r
475ASSUME:  basering = Q[x] or Q(a)[x]
476EXAMPLE: example  Quotient; shows an example
477"
478{
479  def QUOB = basering;
480  def QUOR = TransferRing(basering);  // new ring with parameter 'a' replaced by a variable
481  setring QUOR;
482  export(QUOR);
483  poly f = imap(QUOB, f);
484  poly g = imap(QUOB, g);
485  list result = QuotientMain(f, g);
486
487  setring(QUOB);
488  list result = imap(QUOR, result);
489  kill(QUOR);
490  return(result);
491}
492example
493{"EXAMPLE:";  echo = 2;
494 ring R = (0,a), x, lp;
495 minpoly = a2+1;
496 poly f =  x4 - 2;
497 poly g = x - a;
498 list qr = Quotient(f, g);
499 qr;
500 qr[1]*g + qr[2] - f;
501}
502
503proc QuotientMain(poly f, poly g)
504"USAGE:   QuotientMain(f, g); poly f, g
505PURPOSE: compute the quotient q and remainder r s.t. f = g*q + r, deg(r) < g
506RETURN:  list of polynomials
507         _[1] = quotient  q
508         _[2] = remainder r
509ASSUME:  basering = Q[x,a] and ideal 'mpoly' is defined (it might be 0),
510         this represents the ring Q(a)[x] together with 'minpoly'.
511EXAMPLE: example  Quotient; shows an example
512"
513{
514  if(g == 0) { ERROR("Division by zero !");}
515
516  def QMB = basering;
517  def QMR = NewBaseRing();
518  setring QMR;
519  poly f, g, h;
520  h = imap(QMB, f) / imap(QMB, g);
521  setring QMB;
522  return(list(imap(QMR, h), 0));
523}
524
525///////////////////////////////////////////////////////////////////////////////
526
527proc Remainder(poly f, poly g)
528"USAGE:   Remainder(f, g); poly f, g
529PURPOSE: compute the remainder of the division of f by g, i.e. a polynomial r
530         s.t. f = g*q + r, deg(r) < g.
531RETURN:  poly
532ASSUME:  basering = Q[x] or Q(a)[x]
533"
534{
535  def REMB = basering;
536  def REMR = TransferRing(basering);  // new ring with parameter 'a' replaced by a variable
537  setring(REMR);
538  export(REMR);
539  poly f = imap(REMB, f);
540  poly g = imap(REMB, g);
541  poly h = RemainderMain(f, g);
542
543  setring(REMB);
544  poly r = imap(REMR, h);
545  kill(REMR);
546  return(r);
547}
548example
549{"EXAMPLE:";  echo = 2;
550 ring R = (0,a), x, lp;
551 minpoly = a2+1;
552 poly f =  x4 - 1;
553 poly g = x3 - 1;
554 Remainder(f, g);
555}
556
557proc RemainderMain(poly f, poly g)
558"USAGE:   RemainderMain(f, g); poly f, g
559PURPOSE: compute the remainder r s.t. f = g*q + r, deg(r) < g
560RETURN:  poly
561ASSUME:  basering = Q[x,a] and ideal 'mpoly' is defined (it might be 0),
562         this represents the ring Q(a)[x] together with 'minpoly'.
563"
564{
565  int dg;
566  intvec wt = 1,0;;
567  poly lc, g1, r;
568
569  if(deg(g, wt) == 0) { return(0); }
570
571  lc = LeadTerm(g, 1)[3];
572  g1 = MultPolys(InvertNumberMain(lc), g);  // make g monic
573
574  return(SimplifyPoly(reduce(f, std(g1))));
575}
576
577///////////////////////////////////////////////////////////////////////////////
578
579proc EGCD(poly f, poly g)
580"USAGE:   EGCDMain(f, g); poly f, g
581PURPOSE: compute the polynomial gcd of f and g over Q(a)[x]
582RETURN:  poly h st. h is a greatest common divisor of f and g (not nec. monic)
583ASSUME:  basering = Q(a)[t]
584EXAMPLE: example  EGCD; shows an example
585"
586{
587  def GCDB = basering;
588  def GCDR = TransferRing(basering);  // new ring with parameter 'a' replaced by a variable
589  setring GCDR;
590  export(GCDR);
591  poly f = imap(GCDB, f);
592  poly g = imap(GCDB, g);
593  poly h = EGCDMain(f, g);  // squarefree norm of f
594
595  setring(GCDB);
596  poly h = imap(GCDR, h);
597  kill(GCDR);
598  return(h);
599}
600example
601{"EXAMPLE:";  echo = 2;
602 ring R = (0,a), x, lp;
603 minpoly = a2+1;
604 poly f =  x4 - 1;
605 poly g = x2 - 2*a*x - 1;
606 EGCD(f, g);
607}
608
609proc EGCDMain(poly f, poly g)
610"USAGE:   EGCDMain(f, g); poly f, g
611PURPOSE: compute the polynomial gcd of f and g over Q(a)[x]
612RETURN:  poly
613ASSUME:  basering = Q[x,a] and ideal 'mpoly' is defined (it might be 0),
614         this represents the ring Q(a)[x] together with 'minpoly'.
615EXAMPLE: example EGCD; shows an example
616"
617// might be extended to return s1, s2 s.t. f*s1 + g*s2 = gcd
618{
619  int i = 1;
620  poly r1, r2, r;
621
622  r1 = f;
623  r2 = g;
624
625  while(r2 != 0) {
626    r  = RemainderMain(r1, r2);
627    r1 = r2;
628    r2 = r;
629  }
630  return(r1);
631}
632
633///////////////////////////////////////////////////////////////////////////////
634
635proc MEGCD(poly f, poly g, int varIndex)
636"USAGE:   MEGCD(f, g, i); poly f, g; int i
637PURPOSE: compute  the polynomial gcd of f and g in the i'th variable
638RETURN:  poly
639ASSUME:  f, g are polynomials in var(i),last variable is the algebraic number
640EXAMPLE: example  MEGCD; shows an example
641"
642// might be extended to return s1, s2 s.t. f*s1 + g*s2 = gc
643// not used !
644{
645  string @str, @sf, @sg, @mp, @parName;
646
647  def @RGCDB = basering;
648
649  @sf = string(f);
650  @sg = string(g);
651  @mp = string(minpoly);
652
653  if(npars(basering) == 0) { @parName = "0";}
654  else { @parName = "(0, " + parstr(basering) + ")"; }
655  @str = "ring @RGCD = " + @parName + ", " + string(var(varIndex)) + ", dp;";
656  execute(@str);
657  if(@mp != "0") { execute ("minpoly = " + @mp + ";"); }
658  execute("poly @f = " + @sf + ";");
659  execute("poly @g = " + @sg + ";");
660  export(@RGCD);
661  poly @h = EGCD(@f, @g);
662  setring(@RGCDB);
663  poly h = imap(@RGCD, @h);
664  kill(@RGCD);
665  return(h);
666}
667
668///////////////////////////////////////////////////////////////////////////////
669
670proc SQFRNorm(poly f)
671"USAGE:   SQFRNorm(f); poly f
672PURPOSE: compute the norm of the squarefree polynomial f in Q(a)[x].
673RETURN:  list
674         _[1] = squarefree norm of g (poly)
675         _[2] = g (= f(x - s*a)) (poly)
676         _[3] = s (int)
677ASSUME:  f must be squarefree, basering = Q(a)[x] and minpoly != 0.
678NOTE:    the norm is an element of Q[x]
679EXAMPLE: example  SQFRNorm; shows an example
680"
681{
682  def SNB = basering;
683  def SNR = TransferRing(basering);  // new ring with parameter 'a' replaced by a variable
684  setring SNR;
685  export(SNR);
686  poly f = imap(SNB, f);
687  list result = SQFRNormMain(f);  // squarefree norm of f
688
689  setring(SNB);
690  list result = imap(SNR, result);
691  kill(SNR);
692  return(result);
693}
694example
695{"EXAMPLE:";  echo = 2;
696   ring R = (0,a), x, lp;
697   minpoly = a2+1;
698  poly f =  x4 - 2*x + 1;
699  SQFRNorm(f);
700}
701
702proc SQFRNormMain(poly f)
703"USAGE:   SQFRNorm(f); poly f
704PURPOSE: compute the norm of the squarefree polynomial f in Q(a)[x].
705RETURN:  list
706         _[1] = squarefree norm of g (poly)
707         _[2] = g (= f(x - s*a)) (poly)
708         _[3] = s (int)
709ASSUME:  f must be squarefree, basering = Q[x,a] and ideal 'mpoly' is equal to 'minpoly',
710         this represents the ring Q(a)[x] together with 'minpoly'.
711NOTE:   the norm is an element of Q[x]
712EXAMPLE: example  SqfrNorm; shows an example
713"
714{
715  int s = 0;
716  intvec wt = 1,0;
717  ideal mapId;
718  // list result;
719  poly g, N, N1, h;
720  string ringSTR;
721
722  mapId[1] = var(1) - var(2);    // linear transformation
723  mapId[2] = var(2);
724  map Fs = basering, mapId;
725
726  N = resultant(f, mpoly[1], var(2));  // norm of f
727  N1 = diff(N, var(1));
728  g = f;
729
730  ringSTR = "ring SNRM1 = 0, " + string(var(1)) + ", dp;";  // univariate ring
731  def SNRMB = basering;
732  execute(ringSTR);
733  poly N, N1, h;        // N, N1 do not contain 'a', use built-in gcd
734  h = gcd(imap(SNRMB, N), imap(SNRMB, N1));
735  setring(SNRMB);
736  h = imap(SNRM1, h);
737  while(deg(h, wt) != 0) {    // while norm is not squarefree
738    s = s + 1;
739    g = reduce(Fs(g), mpoly);
740    N = reduce(resultant(g, mpoly[1], var(2)), mpoly);  // norm of g
741    N1 = reduce(diff(N, var(1)), mpoly);
742    setring(SNRM1);
743    h = gcd(imap(SNRMB, N), imap(SNRMB, N1));
744    setring(SNRMB);
745    h = imap(SNRM1, h);
746  }
747  return(list(N, g, s));
748}
749
750///////////////////////////////////////////////////////////////////////////////
751
752proc Factor(poly f)
753"USAGE:   Factor(f); poly f
754PURPOSE: compute the factorization of the squarefree poly f over Q(a)[t],
755         where minpoly  = p(a).
756RETURN:  list
757         _[1] = factors (monic), first entry is the leading coefficient
758         _[2] = multiplicities (not yet)
759ASSUME:  basering must be the univariate polynomial ring over a field which
760         is Q or a simple extension of Q given by a minpoly.
761NOTE:    if basering = Q[t] then this is the built-in 'factorize'.
762EXAMPLE: example  Factor; shows an example
763"
764{
765  def FRB = basering;
766  def FRR = TransferRing(basering);  // new ring with parameter 'a' replaced by a variable
767  setring FRR;
768  export(FRR);
769  poly f = imap(FRB, f);
770  list result = FactorMain(f);  // squarefree norm of f
771
772  setring(FRB);
773  list result = imap(FRR, result);
774  kill(FRR);
775  return(result);
776}
777example
778{"EXAMPLE:";  echo = 2;
779 ring R = (0,a), x, lp;
780 minpoly = a2+1;
781 poly f =  x4 - 1;
782 list fl = Factor(f);
783 fl;
784 fl[1][1]*fl[1][2]*fl[1][3]*fl[1][4]*fl[1][5] - f;
785}
786
787///////////////////////////////////////////////////////////////////////////////
788
789proc FactorMain(poly f)
790"USAGE:   FactorMain(f); poly f
791PURPOSE: compute the factorization of the squarefree poly f over Q(a)[t],
792         where minpoly  = p(a).
793RETURN:  list
794         _[1] = factors, first is a constant
795         _[2] = multiplicities (not yet)
796ASSUME:  basering = Q[x,a], represents Q(a)[x] and minpoly.
797   ideal mpoly must be defined, it might be 0 !
798EXAMPLE: example  Factor; shows an example
799"
800// extend this by a squarefree factorization !!
801// multiplicities are not valid !!
802{
803  int i, s;
804  list normList, factorList, quo_rem;
805  poly f1, h, h1, H, g, leadCoef, invCoeff;
806  ideal fac1, fac2;
807  map F;
808
809  // if no minimal polynomial is defined then use 'factorize'
810  // FactorOverQ is wrapped around 'factorize'
811
812  if(mpoly[1] == 0) {
813    // print(" factorize : deg = " + string(deg(f, intvec(1,0))));
814    factorList = factorize(f); // FactorOverQ(f);
815    return(factorList);
816  }
817
818  // if mpoly != 0 and f does not contain the algebraic number, a root of
819  // f might be contained in Q(a). Hence one must not use 'factorize'.
820
821  fac1[1] = 1;
822  fac2[1] = 1;
823  normList = SQFRNormMain(f);
824  // print(" factorize : deg = " + string(deg(normList[1], intvec(1,0))));
825  factorList = factorize(normList[1]);     // factor squarefree norm of f over Q[x]
826  g = normList[2];
827  s = normList[3];
828  F[1] = var(1) + s*var(2);      // inverse transformation
829  F[2] = var(2);
830  fac1[1] = factorList[1][1];
831  fac2[1] = factorList[2][1];
832  for(i = 2; i <= size(factorList[1]); i = i + 1) {
833    H = factorList[1][i];
834    h = EGCDMain(H, g);
835    quo_rem = QuotientMain(g, h);
836    g = quo_rem[1];
837    fac1[i] = SimplifyPoly(F(h));
838    fac2[i] = 1;        // to be changed later
839  }
840  return(list(fac1, fac2));
841}
842
843///////////////////////////////////////////////////////////////////////////////
844
845proc ZeroSetMain(ideal I, int primDecQ)
846"USAGE:   ZeroSetMain(ideal I, int opt); ideal I, int opt
847PURPOSE: compute the zero-set of the zero-dim. ideal I, in a simple extension
848         of the groundfield.
849RETURN:  list
850   - 'f' is the polynomial f in  Q(a) (a' being substituted by newA)
851         _[1] = zero-set (list), is the list of the zero-set of the ideal I,
852                each entry is an ideal.
853         _[2] = 'newA';  if the groundfield is Q(a') and the extension field
854                is Q(a), then 'newA' is the representation of a' in Q(a).
855                If the basering contains a parameter 'a' and the minpoly
856                remains unchanged then 'newA' = 'a'. If the basering does not
857                contain a parameter then 'newA' = 'a' (default).
858         _[3] = 'mpoly' (ideal), the minimal polynomial of the simple
859                extension of the ground field.
860ASSUME: basering = K[x_1,x_2,...,x_n] where K = Q or a simple extension of Q
861        given by a minpoly.
862  dim(I) = 0.
863NOTE:    opt = 0  no primary decomposition
864  opt > 0  use a primary decomposition
865EXAMPLE: example ZeroSet; shows an example
866"
867{
868  // main work is done in ZeroSetMainWork, here the zero-set of each ideal from the
869  // primary decompostion is coputed by menas of ZeroSetMainWork, and then the
870  // minpoly and the parameter representing the algebraic extension are
871  // transformed according to 'newA', i.e., only bookeeping is done.
872
873  int i, j, n, noMP, dbPrt;
874  intvec w;
875  list currentSol, result, idealList, primDecList, zeroSet;
876  ideal J;
877  map Fa;
878  poly newA, oldMinPoly;
879
880  dbPrt = printlevel-voice+2;
881  dbprint(dbPrt, "ZeroSet of " + string(I) + ", minpoly = " + string(minpoly));
882
883  n = nvars(basering) - 1;
884  for(i = 1; i <= n; i++) { w[i] = 1;}
885  w[n + 1] = 0;
886
887  if(primDecQ == 0) { return(ZeroSetMainWork(I, w, 0)); }
888
889  newA = var(n + 1);
890  if(mpoly[1] == 0) { noMP = 1;}
891  else {noMP = 0;}
892
893  primDecList = primdecGTZ(I);      // primary decomposition
894  dbprint(dbPrt, "primary decomposition consists of " + string(size(primDecList)) + " primary ideals ");
895  // idealList = PDSort(idealList);    // high degrees first
896
897  for(i = 1; i <= size(primDecList); i = i + 1) {
898    idealList[i] = primDecList[i][2];  // use prime component
899    dbprint(dbPrt, string(i) + "  " + string(idealList[i]));
900  }
901
902  // compute the zero-set of each primary ideal and join them.
903  // If necessary, change the groundfield and transform the zero-set
904
905  dbprint(dbPrt, "
906find the zero-set of each primary ideal, form the union
907and keep track of the minimal polynomials ");
908
909  for(i = 1; i <= size(idealList); i = i + 1) {
910    J = idealList[i];
911    idealList[i] = 0;
912    oldMinPoly = mpoly[1];
913    dbprint(dbPrt, " ideal#" + string(i) + " of " + string(size(idealList)) + " = " + string(J));
914    currentSol = ZeroSetMainWork(J, w, 0);
915
916    if(oldMinPoly != currentSol[3]) {   // change minpoly and transform solutions
917      dbprint(dbPrt, " change minpoly to " + string(currentSol[3][1]));
918      dbprint(dbPrt, " new representation of algebraic number = " + string(currentSol[2]));
919      if(!noMP) {      // transform the algebraic number a
920        Fa = basering, maxideal(1);
921        Fa[n + 1] = currentSol[2];
922        newA = SimplifyPoly(Fa(newA));  // new representation of a
923        if(size(zeroSet) > 0) {zeroSet = SimplifyZeroset(Fa(zeroSet)); }
924        if(i < size(idealList)) { idealList = SimplifyZeroset(Fa(idealList)); }
925      }
926      else { noMP = 0;}
927    }
928    zeroSet = zeroSet + currentSol[1];    // add new elements
929  }
930  return(list(zeroSet, newA, mpoly));
931}
932
933///////////////////////////////////////////////////////////////////////////////
934
935proc ZeroSetMainWork(ideal id, intvec wt, int sVars)
936"USAGE:   ZeroSetMainWork(I, wt, sVars);
937PURPOSE: compute the zero-set of the zero-dim. ideal I, in a finite extension
938         of the groundfield (without multiplicities).
939RETURN:  list, all entries are polynomials
940         _[1] = zeros, each entry is an ideal
941         _[2] = newA; if the groundfield is Q(a') this is the rep. of a' wrt a
942         _[3] = minpoly of the algebraic extension of the groundfield (ideal)
943         _[4] = name of algebraic number (default = 'a')
944ASSUME:  basering = Q[x_1,x_2,...,x_n,a]
945         ideal mpoly must be defined, it might be 0 !
946NOTE:    might change 'mpoly' !!
947EXAMPLE: example  IdealSolve; shows an example
948"
949{
950  int i, j, k, nrSols, n, noMP;
951  ideal I, generators, gens, solid, partsolid;
952  list linSol, linearSolution, nLinSol, nonlinSolutions, partSol, sol, solutions, result;
953  list linIndex, nlinIndex, index;
954  map Fa, Fsubs;
955  poly oldMinPoly, newA;
956
957  if(mpoly[1] == 0) { noMP = 1;}
958  else { noMP = 0;}
959  n = nvars(basering) - 1;
960  newA = var(n + 1);
961
962  I = std(id);
963
964  // find linear solutions of univariate generators
965
966  linSol = LinearZeroSetMain(I, wt);
967  generators = linSol[3];      // they are a standardbasis
968  linIndex = linSol[2];
969  linearSolution = linSol[1];
970  if(size(linIndex) + sVars == n) {    // all variables solved
971    solid = SubsMapIdeal(linearSolution, linIndex, 0);
972    result[1] = list(solid);
973    result[2] = var(n + 1);
974    result[3] = mpoly;
975    return(result);
976  }
977
978  // find roots of the nonlinear univariate polynomials of generators
979  // if necessary, transform linear solutions w.r.t. newA
980
981  oldMinPoly = mpoly[1];
982  nLinSol =  NonLinearZeroSetMain(generators, wt);    // find solutions of univariate generators
983  nonlinSolutions = nLinSol[1];    // store solutions
984  nlinIndex = nLinSol[4];     // and index of solved variables
985  generators = nLinSol[5];    // new generators
986
987  // change minpoly if necessary and transform the ideal and the partial solutions
988
989  if(oldMinPoly != nLinSol[3]) {
990    newA = nLinSol[2];
991    if(!noMP && size(linearSolution) > 0) {    // transform the algebraic number a
992      Fa = basering, maxideal(1);
993      Fa[n + 1] = newA;
994      linearSolution = SimplifyData(Fa(linearSolution));  // ...
995    }
996  }
997
998  // check if all variables are solved.
999
1000  if(size(linIndex) + size(nlinIndex) == n - sVars) {
1001    solutions = MergeSolutions(linearSolution, linIndex, nonlinSolutions, nlinIndex, list(), n);
1002  }
1003
1004  else {
1005
1006  // some variables are not solved.
1007  // substitute each partial solution in generators and find the
1008  // zero set of the resulting ideal by recursive application
1009  // of ZeroSetMainWork !
1010
1011  index = linIndex + nlinIndex;
1012  nrSols = 0;
1013  for(i = 1; i <=  size(nonlinSolutions); i = i + 1) {
1014    sol = linearSolution + nonlinSolutions[i];
1015    solid = SubsMapIdeal(sol, index, 1);
1016    Fsubs = basering, solid;
1017    gens = std(SimplifyData(Fsubs(generators)));    // substitute partial solution
1018    oldMinPoly = mpoly[1];
1019    partSol = ZeroSetMainWork(gens, wt, size(index) + sVars);
1020
1021    if(oldMinPoly != partSol[3]) {    // minpoly has changed
1022      Fa = basering, maxideal(1);
1023      Fa[n + 1] = partSol[2];    // a -> p(a), representation of a w.r.t. new minpoly
1024      newA = reduce(Fa(newA), mpoly);
1025      generators = std(SimplifyData(Fa(generators)));
1026      if(size(linearSolution) > 0) { linearSolution = SimplifyData(Fa(linearSolution));}
1027      if(size(nonlinSolutions) > 0) {
1028        nonlinSolutions = SimplifyZeroset(Fa(nonlinSolutions));
1029      }
1030      sol = linearSolution + nonlinSolutions[i];
1031    }
1032
1033    for(j = 1; j <= size(partSol[1]); j++) {   // for all partial solutions
1034      partsolid = partSol[1][j];
1035      for(k = 1; k <= size(index); k++) {
1036        partsolid[index[k]] = sol[k];
1037       }
1038      nrSols++;
1039      solutions[nrSols] = partsolid;
1040    }
1041  }
1042
1043  }  // end else
1044  return(list(solutions, newA, mpoly));
1045}
1046
1047///////////////////////////////////////////////////////////////////////////////
1048
1049proc LinearZeroSetMain(ideal I, intvec wt)
1050"USAGE:   LinearZeroSetMain(I, wt)
1051PURPOSE: solve the univariate linear polys in I
1052ASSUME:  basering = Q[x_1,...,x_n,a]
1053RETURN:  list
1054         _[1] = partial solution of I
1055         _[2] = index of solved vars
1056         _[3] = new generators (standardbasis)
1057"
1058{
1059  int i, ok, n, found, nrSols;
1060  ideal generators, newGens;
1061  list result, index, totalIndex, vars, sol, temp;
1062  map F;
1063  poly f;
1064
1065  result[1] = index;      // sol[1] should be the empty list
1066  n = nvars(basering) - 1;
1067  generators = I;        // might be wrong, use index !
1068  ok = 1;
1069  nrSols = 0;
1070  while(ok) {
1071    found = 0;
1072    for(i = 1; i <= size(generators); i = i + 1) {
1073      f = generators[i];
1074      vars = Variables(f, n);
1075      if(size(vars) == 1 && deg(f, wt) == 1) {  // univariate,linear
1076        nrSols++; found++;
1077        index[nrSols] = vars[1];
1078        sol[nrSols] = var(vars[1]) - MultPolys(InvertNumberMain(LeadTerm(f, vars[1])[3]), f);
1079      }
1080    }
1081    if(found > 0) {
1082      F = basering, SubsMapIdeal(sol, index, 1);
1083      newGens = std(SimplifyData(F(generators)));    // substitute, simplify alg. number
1084      if(size(newGens) == 0) {ok = 0;}
1085      generators = newGens;
1086    }
1087    else {
1088      ok = 0;
1089    }
1090  }
1091  if(nrSols > 0) { result[1] = sol;}
1092  result[2] = index;
1093  result[3] = generators;
1094  return(result);
1095}
1096
1097///////////////////////////////////////////////////////////////////////////////
1098
1099proc NonLinearZeroSetMain(ideal I, intvec wt)
1100"USAGE:   ZeroSetMainWork(I, wt, sVars);
1101PURPOSE: solves the (nonlinear) univariate polynomials in I
1102         of the groundfield (without multiplicities).
1103RETURN:  list, all entries are polynomials
1104         _[1] = list of solutions
1105         _[2] = newA
1106         _[3] = minpoly
1107         _[4] - index of solved variables
1108         _[5] = new representation of I
1109ASSUME:  basering = Q[x_1,x_2,...,x_n,a], ideal 'mpoly' must be defined,
1110         it might be 0 !
1111NOTE:    might change 'mpoly' !!
1112"
1113{
1114  int i, nrSols, ok, n;
1115  ideal generators;
1116  list result, sols, index, vars, partSol;
1117  map F;
1118  poly f, newA;
1119  string ringSTR;
1120
1121  def NLZR = basering;
1122  export(NLZR);
1123
1124  n = nvars(basering) - 1;
1125
1126  generators = I;
1127  newA = var(n + 1);
1128  result[2] = newA;            // default
1129  nrSols = 0;
1130  ok = 1;
1131  i = 1;
1132  while(ok) {
1133
1134    // test if the i-th generator of I is univariate
1135
1136    f = generators[i];
1137    vars = Variables(f, n);
1138    if(size(vars) == 1) {
1139      generators[i] = 0;
1140      generators = simplify(generators, 2);    // remove 0
1141      nrSols++;
1142      index[nrSols] = vars[1];      // store index of solved variable
1143
1144      // create univariate ring
1145
1146      ringSTR = "ring RIS1 = 0, (" + string(var(vars[1])) + ", " + string(var(n+1)) + "), lp;";
1147      execute(ringSTR);
1148      ideal mpoly = std(imap(NLZR, mpoly));
1149      list roots;
1150      poly f = imap(NLZR, f);
1151      export(RIS1);
1152      export(mpoly);
1153      roots = RootsMain(f);
1154
1155      // get "old" basering with new minpoly
1156
1157      setring(NLZR);
1158      partSol = imap(RIS1, roots);
1159      kill(RIS1);
1160      if(mpoly[1] != partSol[3]) {      // change minpoly
1161        mpoly = std(partSol[3]);
1162        F = NLZR, maxideal(1);
1163        F[n + 1] = partSol[2];
1164        if(size(sols) > 0) {sols = SimplifyZeroset(F(sols)); }
1165        newA = reduce(F(newA), mpoly);    // normal form
1166        result[2] = newA;
1167        generators = SimplifyData(F(generators));  // does not remove 0's
1168      }
1169      sols = ExtendSolutions(sols, partSol[1]);
1170    } // end univariate
1171    else {
1172      i = i + 1;
1173    }
1174    if(i > size(generators)) { ok = 0;}
1175  }
1176  result[1] = sols;
1177  result[3] = mpoly;
1178  result[4] = index;
1179  result[5] = std(generators);
1180
1181  kill(NLZR);
1182  return(result);
1183}
1184
1185///////////////////////////////////////////////////////////////////////////////
1186
1187static proc ExtendSolutions(list solutions, list newSolutions)
1188"USAGE:   ExtendSolutions(sols, newSols); list sols, newSols;
1189PURPOSE: extend the entries of 'sols' by the entries of 'newSols',
1190         each entry of 'newSols' is a number.
1191RETURN:  list
1192ASSUME:  basering = Q[x_1,...,x_n,a], ideal 'mpoly' must be defined,
1193         it might be 0 !
1194NOTE:    used by 'NonLinearZeroSetMain'
1195"
1196{
1197  int i, j, k, n, nrSols;
1198  list newSols, temp;
1199
1200  nrSols = size(solutions);
1201  if(nrSols > 0) {n = size(solutions[1]);}
1202  else {
1203    n = 0;
1204    nrSols = 1;
1205  }
1206  k = 0;
1207  for(i = 1; i <= nrSols; i++) {
1208    for(j = 1; j <= size(newSolutions); j++) {
1209      k++;
1210      if(n == 0) { temp[1] = newSolutions[j];}
1211      else {
1212        temp = solutions[i];
1213        temp[n + 1] = newSolutions[j];
1214      }
1215      newSols[k] = temp;
1216    }
1217  }
1218  return(newSols);
1219}
1220
1221///////////////////////////////////////////////////////////////////////////////
1222
1223static proc MergeSolutions(list sol1, list index1, list sol2, list index2)
1224"USAGE:   MergeSolutions(sol1, index1, sol2, index2); all parameters are lists
1225RETURN:  list
1226PURPOSE: create a list of solutions of size n, each entry of 'sol2' must
1227         have size n. 'sol1' is one partial solution (from LinearZeroSetMain)
1228         'sol2' is a list of partial solutions (from NonLinearZeroSetMain)
1229ASSUME:  'sol2' is not empty
1230NOTE:   used by 'ZeroSetMainWork'
1231{
1232  int i, j, k, m;
1233  ideal sol;
1234  list newSols;
1235
1236  m = 0;
1237  for(i = 1; i <= size(sol2); i++) {
1238    m++;
1239    newSols[m] = SubsMapIdeal(sol1 + sol2[i], index1 + index2, 0);
1240  }
1241  return(newSols);
1242}
1243
1244///////////////////////////////////////////////////////////////////////////////
1245
1246static proc SubsMapIdeal(list sol, list index, int opt)
1247"USAGE:   SubsMapIdeal(sol,index,opt); list sol, index; int opt;
1248PURPOSE: built an ideal I as follows.
1249         if i is contained in 'index' then set I[i] = sol[i]
1250         if i is not contained in 'index' then
1251         - opt = 0: set I[i] = 0
1252         - opt = 1: set I[i] = var(i)
1253         if opt = 1 and n = nvars(basering) then set I[n] = var(n).
1254RETURN:  ideal
1255ASSUME:  size(sol) = size(index) <= nvars(basering)
1256"
1257{
1258  int k = 0;
1259  ideal I;
1260  for(int i = 1; i <= nvars(basering) - 1; i = i + 1) {    // built subs. map
1261    if(ContainedQ(index, i)) {
1262      k++;
1263      I[index[k]] = sol[k];
1264    }
1265    else {
1266      if(opt) { I[i] = var(i); }
1267      else { I[i] = 0; }
1268    }
1269  }
1270  if(opt) {I[nvars(basering)] = var(nvars(basering));}
1271  return(I);
1272}
1273
1274///////////////////////////////////////////////////////////////////////////////
1275
1276proc SimplifyZeroset(data)
1277"USAGE:   SimplifyZeroset(data); list data
1278PURPOSE: reduce the entries of the elements of 'data' w.r.t. the ideal 'mpoly'
1279         'data' is a list of ideals/lists.
1280RETURN:  list
1281ASSUME:  basering = Q[x_1,...,x_n,a], order = lp
1282         'data' is a list of ideals
1283         ideal 'mpoly' must be defined, it might be 0 !
1284"
1285{
1286  int i;
1287  list result;
1288
1289  for(i = 1; i <= size(data); i++) {
1290    result[i] = SimplifyData(data[i]);
1291  }
1292  return(result);
1293}
1294
1295///////////////////////////////////////////////////////////////////////////////
1296
1297proc Variables(poly f, int n)
1298"USAGE:   Variables(f,n); poly f; int n;
1299PURPOSE: list of variables among var(1),...,var(n) which occur in f.
1300RETURN:  list
1301ASSUME:  n <= nvars(basering)
1302"
1303{
1304  int i, nrV;
1305  list index;
1306
1307  nrV = 0;
1308  for(i = 1; i <= n; i = i + 1) {
1309    if(diff(f, var(i)) != 0) { nrV++; index[nrV] = i; }
1310  }
1311  return(index);
1312}
1313
1314///////////////////////////////////////////////////////////////////////////////
1315
1316proc ContainedQ(data, f, list #)
1317"USAGE:    ContainedQ(data, f [, opt]); list data; f is of any type, int opt
1318PURPOSE:  test if 'f' is an element of 'data'.
1319RETURN:   int
1320          0 if 'f' not contained in 'data'
1321          1 if 'f' contained in 'data'
1322OPTIONS:  opt = 0 : use '==' for comparing f with elements from data
1323          opt = 1 : use 'SameQ' for comparing f with elements from data
1324"
1325{
1326  int opt, i, found;
1327  if(size(#) > 0) { opt = #[1];}
1328  else { opt = 0; }
1329  i = 1;
1330  found = 0;
1331
1332  while((!found) && (i <= size(data))) {
1333    if(opt == 0) {
1334      if(f == data[i]) { found = 1;}
1335      else {i = i + 1;}
1336    }
1337    else {
1338      if(SameQ(f, data[i])) { found = 1;}
1339      else {i = i + 1;}
1340    }
1341  }
1342  return(found);
1343}
1344
1345//////////////////////////////////////////////////////////////////////////////
1346
1347proc SameQ(a, b)
1348"USAGE:    SameQ(a, b); list/intvec a, b;
1349PURPOSE:  test a == b elementwise, i.e., a[i] = b[i].
1350RETURN:   int
1351          0 if a != b
1352          1 if a == b
1353"
1354{
1355  if(typeof(a) == typeof(b)) {
1356    if(typeof(a) == "list" || typeof(a) == "intvec") {
1357      if(size(a) == size(b)) {
1358        int i = 1;
1359        int ok = 1;
1360        while(ok && (i <= size(a))) {
1361          if(a[i] == b[i]) { i = i + 1;}
1362          else {ok = 0;}
1363        }
1364        return(ok);
1365      }
1366      else { return(0); }
1367    }
1368    else { return(a == b);}
1369  }
1370  else { return(0);}
1371}
1372
1373///////////////////////////////////////////////////////////////////////////////
1374
1375static proc SimplifyPoly(poly f)
1376"USAGE:   SimplifyPoly(f); poly f
1377PURPOSE: reduces the coefficients of f w.r.t. the ideal 'moly' if they contain
1378         the algebraic number 'a'.
1379RETURN:  poly
1380ASSUME:  basering = Q[x_1,...,x_n,a]
1381         ideal mpoly must be defined, it might be 0 !
1382"
1383{
1384  matrix coMx;
1385  poly f1, vp;
1386
1387  vp = 1;
1388  for(int i = 1; i < nvars(basering); i++) { vp = vp * var(i);}
1389
1390  coMx = coef(f, vp);
1391  f1 = 0;
1392  for(i = 1; i <= ncols(coMx); i++) {
1393    f1 = f1 + coMx[1, i] * reduce(coMx[2, i], mpoly);
1394  }
1395  return(f1);
1396}
1397
1398///////////////////////////////////////////////////////////////////////////////
1399
1400static proc SimplifyData(data)
1401"USAGE:   SimplifyData(data); ideal/list data;
1402PURPOSE: reduces the entries of 'data' w.r.t. the ideal 'mpoly' if they
1403         contain the algebraic number 'a'.
1404RETURN:  ideal/list
1405ASSUME:  basering = Q[x_1,...,x_n,a]
1406         ideal 'mpoly' must be defined, it might be 0 !
1407"
1408{
1409  int n;
1410  poly f;
1411
1412  if(typeof(data) == "ideal") { n = ncols(data); }
1413  else { n = size(data);}
1414
1415  for(int i = 1; i <= n; i++) {
1416    f = data[i];
1417    data[i] = SimplifyPoly(f);
1418  }
1419  return(data);
1420}
1421
1422///////////////////////////////////////////////////////////////////////////////
1423
1424static proc TransferRing(R)
1425"USAGE:   TransferRing(R);
1426PURPOSE: creates a new ring containing the same variables as R, but without
1427         parameters. If R contains a parameter then this parameter is added
1428         as the last variable and 'minpoly' is represented by the ideal
1429         'mpoly'. If the basering does not contain a parameter then 'a' will
1430         be added and 'mpoly' = 0.
1431RETURN:  ring
1432ASSUME:  R = K[x_1,...,x_n] where K = Q or K = Q(a).
1433NOTE:    Creates the ring needed for all prodecures with name 'proc-name'Main
1434"
1435{
1436  string ringSTR, parName, minPoly;
1437
1438  setring(R);
1439
1440  if(npars(basering) == 0) {
1441    parName = "a";
1442    minPoly = "0";
1443  }
1444  else {
1445    parName = parstr(basering);
1446    minPoly = string(minpoly);
1447  }
1448  ringSTR = "ring TR = 0, (" + varstr(basering) + "," + parName + "), lp;";
1449
1450  execute(ringSTR);
1451  execute("ideal mpoly = std(" + minPoly + ");");
1452  export(mpoly);
1453  return(TR);
1454}
1455
1456///////////////////////////////////////////////////////////////////////////////
1457
1458static proc NewBaseRing()
1459"USAGE:   NewBaseRing();
1460PURPOSE: creates a new ring, the last variable is added as a parameter.
1461         minpoly is set to mpoly[1].
1462RETURN:  ring
1463ASSUME:  basering = Q[x_1,...,x_n, a], 'mpoly' must be defined
1464"
1465{
1466  int n = nvars(basering);
1467  int MP;
1468  string ringSTR, parName, varString;
1469
1470  def BR = basering;
1471  if(mpoly[1] != 0) {
1472    parName = "(0, " + string(var(n)) + ")";
1473    MP = 1;
1474  }
1475  else {
1476    parName = "0";
1477    MP = 0;
1478  }
1479
1480
1481  for(int i = 1; i < n - 1; i++) {
1482    varString = varString + string(var(i)) + ",";
1483  }
1484  varString = varString + string(var(n-1));
1485
1486  ringSTR = "ring TR = " + parName + ", (" + varString + "), lp;";
1487  execute(ringSTR);
1488  if(MP) { minpoly = number(imap(BR, mpoly)[1]); }
1489  return(TR);
1490}
1491
1492///////////////////////////////////////////////////////////////////////////////
1493
1494/*
1495                           Examples:
1496
1497
1498// order = 20;
1499ring S1 = 0, (s(1..3)), lp;
1500ideal I = s(2)*s(3), s(1)^2*s(2)+s(1)^2*s(3)-1, s(1)^2*s(3)^2-s(3), s(2)^4-s(3)^4+s(1)^2, s(1)^4+s(2)^3-s(3)^3, s(3)^5-s(1)^2*s(3);
1501
1502// order = 10
1503ring S2 = 0, (s(1..5)), lp;
1504ideal I = s(2)+s(3)-s(5), s(4)^2-s(5), s(1)*s(5)+s(3)*s(4)-s(4)*s(5), s(1)*s(4)+s(3)-s(5), s(3)^2-2*s(3)*s(5), s(1)*s(3)-s(1)*s(5)+s(4)*s(5), s(1)^2+s(4)^2-2*s(5), -s(1)+s(5)^3, s(3)*s(5)^2+s(4)-s(5)^3, s(1)*s(5)^2-1;
1505
1506//order = 126
1507ring S3 =  0, (s(1..5)), lp;
1508ideal I = s(3)*s(4), s(2)*s(4), s(1)*s(3), s(1)*s(2), s(3)^3+s(4)^3-1, s(2)^3+s(4)^3-1, s(1)^3-s(4)^3, s(4)^4-s(4), s(1)*s(4)^3-s(1), s(5)^7-1;
1509
1510// order = 192
1511ring S4 = 0, (s(1..4)), lp;
1512ideal I = s(2)*s(3)^2*s(4)+s(1)*s(3)*s(4)^2, s(2)^2*s(3)*s(4)+s(1)*s(2)*s(4)^2, s(1)*s(3)^3+s(2)*s(4)^3, s(1)*s(2)*s(3)^2+s(1)^2*s(3)*s(4), s(1)^2*s(3)^2-s(2)^2*s(4)^2, s(1)*s(2)^2*s(3)+s(1)^2*s(2)*s(4), s(1)^3*s(3)+s(2)^3*s(4), s(2)^4-s(3)^4, s(1)*s(2)^3+s(3)*s(4)^3, s(1)^2*s(2)^2-s(3)^2*s(4)^2, s(1)^3*s(2)+s(3)^3*s(4), s(1)^4-s(4)^4, s(3)^5*s(4)-s(3)*s(4)^5, s(3)^8+14*s(3)^4*s(4)^4+s(4)^8-1, 15*s(2)*s(3)*s(4)^7-s(1)*s(4)^8+s(1), 15*s(3)^4*s(4)^5+s(4)^9-s(4), 16*s(3)*s(4)^9-s(3)*s(4), 16*s(2)*s(4)^9-s(2)*s(4), 16*s(1)*s(3)*s(4)^8-s(1)*s(3), 16*s(1)*s(2)*s(4)^8-s(1)*s(2), 16*s(1)*s(4)^10-15*s(2)*s(3)*s(4)-16*s(1)*s(4)^2, 16*s(1)^2*s(4)^9-15*s(1)*s(2)*s(3)-16*s(1)^2*s(4), 16*s(4)^13+15*s(3)^4*s(4)-16*s(4)^5;
1513
1514ring R = (0,a), (x,y,z), lp;
1515minpoly = a2 + 1;
1516ideal I1 = x2 - 1/2, a*z - 1, y - 2;
1517ideal I2 = x3 - 1/2, a*z2 - 3, y - 2*a;
1518*/
1519
1520
1521
1522
1523
1524
1525
1526
Note: See TracBrowser for help on using the repository browser.