source: git/Singular/LIB/zeroset.lib @ 3c8425

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