source: git/Singular/LIB/polymake.lib @ 69b66ef

spielwiese
Last change on this file since 69b66ef was 69b66ef, checked in by Thomas Markwig <keilen@…>, 16 years ago
triangulations has been adopted so as to get along with the format of topcom version 0.15. git-svn-id: file:///usr/local/Singular/svn/trunk@10948 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 84.3 KB
Line 
1version="$Id: polymake.lib,v 1.4 2008-08-06 13:14:56 keilen Exp $";
2category="Tropical Geometry";
3info="
4   LIBRARY:         polymake.lib
5
6   AUTHORS:         Thomas Markwig,  email: keilen@mathematik.uni-kl.de
7
8   KEYWORDS:        polytope, fan, secondary fan, secondary polytope, polymake,
9                    Newton polytope, Groebner fan
10
11   WARNING:
12     Most procedures will not work unless polymake or topcom is installed and
13     if so, they will only work with the operating system LINUX!
14     For more detailed information see IMPORTANT NOTE respectively consult the
15     help string of the procedures.
16
17   IMPORTANT NOTE:
18     Even though this is a Singular library for computing polytopes and fans such
19     as the Newton polytope or the Groebner fan of a polynomial, most of the hard
20     computations are NOT done by Singular but by the program
21     -  polymake by Ewgenij Gawrilow, TU Berlin and Michael Joswig, TU Darmstadt
22        (see http://www.math.tu-berlin.de/polymake/), 
23     respectively (only in the procedure triangularions) by the program
24     -  topcom by Joerg Rambau, Universitaet Bayreuth
25        (see http://www.uni-bayreuth.de/departments/wirtschaftsmathematik/rambau/TOPCOM);
26     this library should rather be seen as an interface which allows to use a (very limited)
27     number of options which polymake respectively topcom offers to compute with polytopes
28     and fans and to make the results available in Singular for further computations;
29     moreover, the user familiar with Singular does not have to learn the syntax of polymake
30     or topcom, if the options offered here are sufficient for his purposes.
31     Note, though, that the procedures concerned with planar polygons are independent of
32     both, polymake and topcom.
33
34   PROCEDURES USING POLYMAKE:
35     polymakePolytope(list)            computes the vertices of a polytope using polymake
36     newtonPolytope(poly)              computes the Newton polytope of the polynomial
37     newtonPolytopeLP(poly)            computes the lattice points of the Newton polytope of the polynomial
38     normalFan(intmat,intmat,list)     computes the normal fan of a polytope
39     groebnerFan(poly)                 computes the Groebner fan of a polynomial
40     intmatToPolymake(intmat,string)   transforms an integer matrix into polymake format
41     polymakeToIntmat(string,string)   transforms polymake output into an integer matrix
42
43   PROCEDURES USING TOPCOM:
44     triangulations(list)          computes all triangulations of a marked polytope
45     secondaryPolytope(list)       computes the secondary polytope of a marked polytope
46
47   PROCEDURES CONERNED WITH PLANAR POLYGONS:
48     cycleLength(list,intvec)      computes the cycleLength of cycle dual to list with interior point intvec
49     splitPolygon(list)            splits a marked polygon into vertices, facets and interior points
50     eta(list,list)                computes the eta-vector of a triangulation
51     findOrientedBoundary(list)    computes the boundary of the convex hull of a list of lattice points
52     cyclePoints(list,list,int)    computes lattice points connected to a lattice point in a triangulation
53     latticeArea(list)             computes the lattice area of a polygon
54     picksFormula(list)            computes the ingrediants of Pick's formula for a polygon
55     ellipticNF(list)              computes the normal form of an elliptic polygon
56     ellipticNFDB(int)             displays the 16 normal forms of elliptic polygons
57";
58
59////////////////////////////////////////////////////////////////////////////////////
60/// Auxilary Static Procedures in this Library
61////////////////////////////////////////////////////////////////////////////////////
62/// - scalarproduct
63/// - intmatcoldelete
64/// - intmatconcat
65/// - sortlist
66/// - minInList
67/// - stringdelete
68/// - abs
69/// - commondenominator
70/// - maxPosInIntvec
71/// - maxPosInIntmat
72/// - sortintvec
73/// - matrixtointmat
74/////////////////////////////////////////////////////////////////////////////////////
75
76////////////////////////////////////////////////////////////////////////////////////
77LIB "poly.lib";
78LIB "linalg.lib";
79LIB "random.lib";
80////////////////////////////////////////////////////////////////////////////////////
81
82////////////////////////////////////////////////////////////////////////////////////////
83/// PROCEDURES USING POLYMAKE
84////////////////////////////////////////////////////////////////////////////////////////
85
86proc polymakePolytope (intmat polytope,list #)
87"USAGE:  polymakePolytope(polytope[,#]);   polytope list, # string
88ASSUME:  each row of polytope gives the coordinates of a lattice point of a polytope
89         with their affine coordinates as given by the output of secondaryPolytope
90PURPOSE: the procedure calls polymake to compute the vertices of the polytope as well
91         as its dimension and information on its facets
92RETURN:  list, L with four entries
93              L[1] : an integer matrix whose rows are the coordinates of vertices
94                     of the polytope
95              L[2] : the dimension of the polytope
96              L[3] : a list whose ith entry explains to which vertices the ith vertex
97                     of the Newton polytope is connected -- i.e. L[3][i] is an integer
98                     vector and an entry k in there means that the vertex L[1][i] is
99                     connected to the vertex L[1][k]
100              L[4] : an integer matrix whose rows mulitplied by (1,var(1),...,var(nvar)) give
101                     a linear system of equations describing the affine hull of the polytope,
102                     i.e. the smallest affine space containing the polytope
103NOTE: -  for its computations the procedure calls the program polymake by Ewgenij Gawrilow,
104         TU Berlin and Michael Joswig, TU Darmstadt; it therefore is necessary that
105         this program is installed in order to use this procedure;
106         see http://www.math.tu-berlin.de/polymake/
107      -  note that in the vertex edge graph we have changed the polymake convention which
108         starts indexing its vertices by zero while we start with one !
109      -  the procedure creates the file  /tmp/polytope.polymake which contains the polytope
110         in polymake format and which can be used for further computations with polymake
111      -  moreover, the procedure creates the file /tmp/polytope.output which it deletes
112         again before ending
113      -  it is possible to give as an optional second argument as string which then will be
114         used instead of 'polytope' in the name of the polymake output file
115EXAMPLE: example polymakePolytope;   shows an example"
116{
117  // the header for the file secendarypolytope.polymake
118  string sp="_application polytope
119_version 2.2
120_type RationalPolytope
121
122POINTS
123";
124  int i,j;
125  // set the name for the polymake output file
126  if (size(#)>0)
127  {
128    if (typeof(#[1])=="string")
129    {
130      string dateiname=#[1];
131    }
132    else
133    {
134      string dateiname="polytope";
135    }
136  }
137  else
138  {
139    string dateiname="polytope";
140  }
141  // create the lattice point list for polymake
142  sp=sp+intmatToPolymake(polytope,"points");
143  // initialise dateiname.polymake and compute the vertices
144  write(":w /tmp/"+dateiname+".polymake",sp);
145  system("sh","cd /tmp; polymake "+dateiname+".polymake VERTICES > "+dateiname+".output");
146  string vertices=read("/tmp/"+dateiname+".output");
147  system("sh","/bin/rm /tmp/"+dateiname+".output");
148  intmat np=polymakeToIntmat(vertices,"affine");
149  // compute the dimension
150  system("sh","cd /tmp; polymake "+dateiname+".polymake DIM > "+dateiname+".output");
151  string pdim=read("/tmp/"+dateiname+".output");
152  system("sh","/bin/rm /tmp/"+dateiname+".output");
153  pdim=pdim[5,size(pdim)-6];
154  execute("int nd="+pdim+";");
155  // compute the vertex-edge graph
156  system("sh","cd /tmp; polymake "+dateiname+".polymake GRAPH > "+dateiname+".output");
157  string vertexedgegraph=read("/tmp/"+dateiname+".output");
158  system("sh","/bin/rm /tmp/"+dateiname+".output");
159  vertexedgegraph=vertexedgegraph[7,size(vertexedgegraph)-8];
160  string newveg;
161  for (i=1;i<=size(vertexedgegraph);i++)
162  {
163    if (vertexedgegraph[i]=="{")
164    {
165      newveg=newveg+"intvec(";
166    }
167    else
168    {
169      if (vertexedgegraph[i]=="}")
170      {
171        newveg=newveg+"),";
172      }
173      else
174      {
175        if (vertexedgegraph[i]==" ")
176        {
177          newveg=newveg+",";
178        }
179        else
180        {
181          newveg=newveg+vertexedgegraph[i];
182        }
183      }
184    }
185  } 
186  newveg=newveg[1,size(newveg)-1];
187  execute("list nveg="+newveg+";");
188  // raise each entry in nveg by one
189  for (i=1;i<=size(nveg);i++)
190  {
191    for (j=1;j<=size(nveg[i]);j++)
192    {
193      nveg[i][j]=nveg[i][j]+1;
194    }
195  }
196  // compute the affine hull
197  system("sh","cd /tmp; polymake "+dateiname+".polymake AFFINE_HULL > "+dateiname+".output");
198  string equations=read("/tmp/"+dateiname+".output");
199  system("sh","/bin/rm /tmp/"+dateiname+".output");
200  if (size(equations)>14)
201  {
202    intmat neq=polymakeToIntmat(equations,"cleardenom");
203  }
204  else
205  {
206    intmat neq[1][ncols(polytope)+1];
207  }
208  return(list(np,nd,nveg,neq));
209}
210example
211{
212   "EXAMPLE:";
213   echo=2;
214   // the lattice points of the unit square in the plane
215   list points=intvec(0,0),intvec(0,1),intvec(1,0),intvec(1,1);
216   // the secondary polytope of this lattice point configuration is computed
217   intmat secpoly=secondaryPolytope(points)[1];
218   list np=polymakePolytope(secpoly);
219   // the vertices of the Newton polytope are:
220   np[1];
221   // its dimension is
222   np[2];
223   // np[3] contains information how the vertices are connected to each other,
224   // e.g. the first vertex (number 0) is connected to the second one
225   np[3][1];
226   // the affine hull has the equation
227   ring r=0,x(1..4),dp;
228   matrix M[5][1]=1,x(1),x(2),x(3),x(4);
229   np[4]*M;
230}
231
232proc newtonPolytope (poly f,list #)
233"USAGE: newtonPolytope(f[,#]);  f poly, # string
234RETURN: list, L with four entries
235              L[1] : an integer matrix whose rows are the coordinates of vertices
236                     of the Newton polytope of f
237              L[2] : the dimension of the Newton polytope of f
238              L[3] : a list whose ith entry explains to which vertices the ith vertex
239                     of the Newton polytope is connected -- i.e. L[3][i] is an integer
240                     vector and an entry k in there means that the vertex L[1][i] is
241                     connected to the vertex L[1][k]
242              L[4] : an integer matrix whose rows mulitplied by (1,var(1),...,var(nvar)) give
243                     a linear system of equations describing the affine hull of the Newton
244                     polytope, i.e. the smallest affine space containing the Newton polytope
245NOTE: -  if we replace the first column of L[4] by zeros, i.e. if we move the affine hull to
246         the origin, then we get the equations for the orthogonal comploment of the linearity
247         space of the normal fan dual to the Newton polytope, i.e. we get the EQUATIONS that
248         we need as input for polymake when computing the normal fan
249      -  the procedure calls for its computation polymake by Ewgenij Gawrilow,
250         TU Berlin and Michael Joswig, so it only works if polymake is installed;
251         see http://www.math.tu-berlin.de/polymake/
252      -  the procedure creates the file  /tmp/newtonPolytope.polymake which contains the polytope
253         in polymake format and which can be used for further computations with polymake
254      -  moreover, the procedure creates the file /tmp/newtonPolytope.output which it deletes
255         again before ending
256      -  it is possible to give as an optional second argument as string which then will be
257         used instead of 'newtonPolytope' in the name of the polymake output file
258EXAMPLE: example newtonPolytope;   shows an example"
259{
260  int i,j;
261  // compute the list of exponent vectors of the polynomial, which are the lattice points
262  // whose convex hull is the Newton polytope of f
263  intmat exponents[size(f)][nvars(basering)];
264  while (f!=0)
265  {
266    i++;
267    exponents[i,1..nvars(basering)]=leadexp(f);
268    f=f-lead(f);
269  }
270  if (size(#)==0)
271  {
272    #[1]="newtonPolytope";
273  }
274  // call polymakePolytope with exponents
275  return(polymakePolytope(exponents,#));
276}
277example
278{
279   "EXAMPLE:";
280   echo=2;
281   ring r=0,(x,y,z),dp;
282   matrix M[4][1]=1,x,y,z;
283   poly f=y3+x2+xy+2xz+yz+z2+1;
284   // the Newton polytope of f is
285   list np=newtonPolytope(f);
286   // the vertices of the Newton polytope are:
287   np[1];
288   // its dimension is
289   np[2];
290   // np[3] contains information how the vertices are connected to each other,
291   // e.g. the first vertex (number 0) is connected to the second, third and
292   //      fourth vertex
293   np[3][1];
294   //////////////////////////
295   f=x2-y3;
296   // the Newton polytope of f is
297   np=newtonPolytope(f);
298   // the vertices of the Newton polytope are:
299   np[1];
300   // its dimension is
301   np[2];   
302   // the Newton polytope is contained in the affine space given by the equations
303   np[4]*M;
304}
305
306proc newtonPolytopeLP (poly f)
307"USAGE:  newtonPolytopeLP(f);  f poly
308RETURN: list, the exponent vectors of the monomials occuring in f, i.e. the lattice
309              points of the Newton polytope of f
310EXAMPLE: example normalFan;   shows an example"
311{
312  list np;
313  int i=1;
314  while (f!=0)
315  {
316    np[i]=leadexp(f);
317    f=f-lead(f);
318    i++;
319  }
320  return(np);
321}
322example
323{
324   "EXAMPLE:";
325   echo=2;
326   ring r=0,(x,y,z),dp;
327   poly f=y3+x2+xy+2xz+yz+z2+1;
328   // the lattice points of the Newton polytope of f are
329   newtonPolytopeLP(f);
330}
331
332proc normalFan (intmat vertices,intmat affinehull,list graph,int er,list #)
333"USAGE:  normalFan (vert,aff,graph,rays,[,#]);   vert,aff intmat,  graph list, rays int, # string
334ASSUME:  - vert is an integer matrix whose rows are the coordinate of the vertices of
335           a convex lattice polygon;
336         - aff describes the affine hull of this polytope, i.e.
337           the smallest affine space containing it, in the following sense:
338           denote by n the number of columns of vert, then multiply aff by (1,x(1),...,x(n))
339           and set the resulting terms to zero in order to get the equations for the affine hull;
340         - the ith entry of graph is an integer vector describing to which vertices
341           the ith vertex is connected, i.e. a k as entry means that the vertex vert[i] is
342           connected to vert[k];
343         - the integer rays is either one (if the extreme rays should be computed) or zero (otherwise)
344RETURN:  list, the ith entry of L[1] contains information about the cone in the normal fan
345               dual to the ith vertex of the polytope
346               L[1][i][1] = integer matrix representing the inequalities which describe the
347                            cone dual to the ith vertex
348               L[1][i][2] = a list which contains the inequalities represented by L[i][1]
349                            as a list of strings, where we use the variables x(1),...,x(n)
350               L[1][i][3] = only present if 'er' is set to 1; in that case it is an interger matrix
351                            whose rows are the extreme rays of the cone
352               L[2] = is an integer matrix whose rows span the linearity space of the fan,
353                      i.e. the linear space which is contained in each cone
354NOTE:    - the procedure calls for its computation polymake by Ewgenij Gawrilow,
355           TU Berlin and Michael Joswig, so it only works if polymake is installed;
356           see http://www.math.tu-berlin.de/polymake/
357         - in the optional argument # it is possible to hand over other names for the
358           variables to be used -- be carful, the format must be correct and that is
359           not tested, e.g. if you want the variable names to be u00,u10,u01,u11
360           then you must hand over the string u11,u10,u01,u11
361EXAMPLE: example normalFan;   shows an example"
362{
363  list ineq; // stores the inequalities of the cones
364  int i,j,k;
365  // we work over the following ring 
366  execute("ring ineqring=0,x(1.."+string(ncols(vertices))+"),lp;");
367  string greatersign=">";
368  // create the variable names
369  if (size(#)>0)
370  {
371    if (typeof(#[1])=="string")
372    {
373      kill ineqring;
374      execute("ring ineqring=0,("+#[1]+"),lp;");
375    }
376    if (size(#)>1)
377    {
378      greatersign="<";
379    }
380  }
381  //////////////////////////////////////////////////////////////////
382  // Compute first the inequalities of the cones
383  //////////////////////////////////////////////////////////////////
384  matrix VAR[1][ncols(vertices)]=maxideal(1);
385  matrix EXP[ncols(vertices)][1];
386  poly p,pl,pr;
387  // consider all vertices of the polytope
388  for (i=1;i<=nrows(vertices);i++)
389  {
390    // first we produce for each vertex in the polytope
391    // the inequalities describing the dual cone in the normal fan
392    list pp;  // contain strings representing the inequalities describing the normal cone
393    intmat ie[size(graph[i])][ncols(vertices)]; // contains the inequalities as rows
394    // consider all the vertices to which the ith vertex in the polytope is connected by an edge
395    for (j=1;j<=size(graph[i]);j++)
396    {
397      // produce the vector ie_j pointing from the jth vertex to the ith vertex;
398      // this will be the jth inequality for the cone in the normal fan dual to the ith vertex
399      ie[j,1..ncols(vertices)]=vertices[i,1..ncols(vertices)]-vertices[graph[i][j],1..ncols(vertices)];
400      EXP=ie[j,1..ncols(vertices)];
401      // build a linear polynomial with the entries of ie_j as coefficients
402      p=(VAR*EXP)[1,1];
403      pl,pr=0,0;
404      // separate the terms with positive coefficients in p from those with negative coefficients
405      for (k=1;k<=size(p);k++)
406      {
407        if (leadcoef(p[k])<0)
408        {
409          pr=pr-p[k];
410        }
411        else
412        {
413          pl=pl+p[k];
414        }
415      }
416      // build the string which represents the jth inequality for the cone dual to the ith vertex
417      // as polynomial inequality of type string, and store this in the list pp as jth entry
418      pp[j]=string(pl)+" "+greatersign+" "+string(pr);
419    }
420    // all inequalities for the ith vertex are stored in the list ineq
421    ineq[i]=list(ie,pp);
422    kill ie,pp; // kill certain lists
423  }
424  // remove the first column of affine hull to compute the linearity space
425  intmat linearity=intmatcoldelete(affinehull,1);
426  //////////////////////////////////////////////////////////////////
427  // Compute next the extreme rays of the cones
428  //////////////////////////////////////////////////////////////////
429  if (er==1)
430  {
431    list extremerays; // keeps the result
432    string polymake; // keeps polymake output
433    // the header for ineq.polymake
434    string head="_application polytope
435_version 2.2
436_type RationalPolytope
437
438INEQUALITIES
439";
440    // the tail for both polymake files
441    string tail="
442EQUATIONS
443";
444    tail=tail+intmatToPolymake(linearity,"rays");
445    string ungleichungen; // keeps the inequalities for the polymake code
446    intmat M; // the matrix keeping the inequalities
447    // create the file ineq.output
448    write(":w /tmp/ineq.output","");
449    int dimension; // keeps the dimension of the intersection the bad cones with the u11tobeseencone
450    for (i=1;i<=size(ineq);i++)
451    {
452      i,". Cone of ",nrows(vertices); // indicate how many vertices have been dealt with
453      ungleichungen=intmatToPolymake(ineq[i][1],"rays");
454      // write the inequalities to ineq.polymake and call polymake
455      write(":w /tmp/ineq.polymake",head+ungleichungen+tail);
456      ungleichungen=""; // clear ungleichungen
457      system("sh","cd /tmp; /bin/rm ineq.output; polymake ineq.polymake VERTICES > ineq.output");
458      // read the result of polymake
459      polymake=read("/tmp/ineq.output");
460      intmat VERT=polymakeToIntmat(polymake,"affine");
461      extremerays[i]=VERT;
462      kill VERT;
463    }
464    for (i=1;i<=size(ineq);i++)
465    {
466      ineq[i]=ineq[i]+list(extremerays[i]);
467    }
468  }
469  // get the linearity space
470  return(list(ineq,linearity));
471}
472example
473{
474   "EXAMPLE:";
475   echo=2;
476   ring r=0,(x,y,z),dp;
477   matrix M[4][1]=1,x,y,z;
478   poly f=y3+x2+xy+2xz+yz+z2+1;
479   // the Newton polytope of f is
480   list np=newtonPolytope(f);
481   // the Groebner fan of f, i.e. the normal fan of the Newton polytope
482   list gf=normalFan(np[1],np[4],np[3],1,"x,y,z");
483   // the number of cones in the Groebner fan of f is:
484   size(gf[1]);
485   // the inequalities of the first cone as matrix are:
486   print(gf[1][1][1]);
487   // the inequalities of the first cone as string are:
488   print(gf[1][1][2]);
489   // the rows of the following matrix are the extreme rays of the first cone:
490   print(gf[1][1][3]);
491   // each cone contains the linearity space spanned by:
492   print(gf[2]);
493}
494
495proc groebnerFan (poly f,list #)
496"USAGE:  groebnerFan(f[,#]);  f poly, # string
497RETURN:  list, the ith entry of L[1] contains information about the ith cone in the Groebner fan
498               dual to the ith vertex in the Newton polytope of the f
499               L[1][i][1] = integer matrix representing the inequalities which describe the cone         
500               L[1][i][2] = a list which contains the inequalities represented by L[i][1]
501                            as a list of strings
502               L[1][i][3] = an interger matrix whose rows are the extreme rays of the cone
503               L[2] = is an integer matrix whose rows span the linearity space of the fan,
504                      i.e. the linear space which is contained in each cone               
505               L[3] = the Newton polytope of f in the format of the procedure newtonPolytope
506NOTE:    - if you have alread computed the Newton polytope of f then you might want
507           to use the procedure normalFan instead in order to avoid doing costly computation
508           twice
509         - the procedure calls for its computation polymake by Ewgenij Gawrilow,
510           TU Berlin and Michael Joswig, so it only works if polymake is installed;
511           see http://www.math.tu-berlin.de/polymake/
512         - the procedure creates the file  /tmp/newtonPolytope.polymake which contains the
513           Newton polytope of f in polymake format and which can be used for further
514           computations with polymake
515         - it is possible to give as an optional second argument as string which then will be
516           used instead of 'newtonPolytope' in the name of the polymake output file
517EXAMPLE: example groebnerFan;   shows an example"
518{
519  int i,j;
520  // compute the list of exponent vectors of the polynomial, which are the lattice points
521  // whose convex hull is the Newton polytope of f
522  intmat exponents[size(f)][nvars(basering)];
523  while (f!=0)
524  {
525    i++;
526    exponents[i,1..nvars(basering)]=leadexp(f);
527    f=f-lead(f);
528  }
529  if (size(#)==0)
530  {
531    #[1]="newtonPolytope";
532  }
533  // call polymakePolytope with exponents
534  list newtonp=polymakePolytope(exponents,"newtonPolytope");
535  // get the variables as string
536  string variablen;
537  for (i=1;i<=nvars(basering);i++)
538  {
539    variablen=variablen+string(var(i))+",";
540  }
541  variablen=variablen[1,size(variablen)-1];
542  // call normalFan in order to compute the Groebner fan
543  list gf=normalFan(newtonp[1],newtonp[4],newtonp[3],1,variablen);
544  // append newtonp to gf
545  gf[3]=newtonp;
546  // append newtonp the exponent vectors to gt
547  gf[4]=exponents;
548  return(gf);
549}
550example
551{
552   "EXAMPLE:";
553   echo=2;
554   ring r=0,(x,y,z),dp;
555   matrix M[4][1]=1,x,y,z;
556   poly f=y3+x2+xy+2xz+yz+z2+1;
557   // the Newton polytope of f is
558   list gf=groebnerFan(f);
559   // the exponent vectors of f are ordered as follows
560   gf[4];
561   // the first cone of the groebner fan has the inequalities
562   gf[1][1][1];
563   // as a string they look like
564   gf[1][1][2];
565   // and it has the extreme rays
566   print(gf[1][1][3]);
567   // the linearity space is spanned by
568   print(gf[2]);
569   // the vertices of the Newton polytope are:
570   gf[3][1];
571   // its dimension is
572   gf[3][2];
573   // np[3] contains information how the vertices are connected to each other,
574   // e.g. the first vertex is connected to the second, third and fourth vertex
575   gf[3][3][1];
576}
577
578
579
580proc intmatToPolymake (intmat M,string art)
581"USAGE:  intmatToPolymake(M,art);  M intmat, art string
582ASSUME:  - M is an integer matrix which should be transformed into polymake format;
583         - art is one of the following strings
584           - 'rays'   : indicating that a first column of 0's should be added
585           - 'points' : indicating that a first column of 1's should be added
586RETURN:  string, the matrix is transformed in a string and a first column has been added
587EXAMPLE: example intmatToPolymake;   shows an example"
588{
589  if (art=="rays")
590  {
591    string anf="0 ";
592  }
593  else
594  {
595    string anf="1 ";
596  }
597  string sp;
598  int i,j;
599  // create the lattice point list for polymake
600  for (i=1;i<=nrows(M);i++)
601  {
602    sp=sp+anf;
603    for (j=1;j<=ncols(M);j++)
604    {
605      sp=sp+string(M[i,j])+" ";
606      if (j==ncols(M))
607      {
608        sp=sp+"
609";
610      }
611    }
612  }
613  return(sp);
614}
615example
616{
617   "EXAMPLE:";
618   echo=2;
619   intmat M[3][4]=1,2,3,4,5,6,7,8,9,10,11,12;
620   intmatToPolymake(M,"rays");
621   intmatToPolymake(M,"points");
622}
623
624proc polymakeToIntmat (string pm,string art)
625"USAGE:  polymakeToIntmat(pm,art);  pm, art string
626ASSUME:  pm is the result of calling polymake with one 'argument' like VERTICES, AFFINE_HULL, etc.,
627         so that the first row of the string is the name of the corresponding 'argument' and
628         the further rows contain the result which consists of vectors either over the integers
629         or over the rationals
630RETURN:  intmat, the rows of the matrix are basically the vectors in pm from the second row on
631                 where each row has been multiplied with the lowest common multiple of the
632                 denominators of its entries so as to be an integer matrix; moreover,
633                 if art=='affine', then the first column is omitted since we only want affine
634                 coordinates
635EXAMPLE: example polymakeToIntmat;   shows an example"
636{
637  // we need a line break
638  string zeilenumbruch="
639";
640  // remove the 'argment' name, i.e. the first row of pm
641  while (pm[1]!=zeilenumbruch)
642  {
643    pm=stringdelete(pm,1);
644  }
645  pm=stringdelete(pm,1); 
646  // find out how many entries each vector has, namely one more than 'spaces' in a row
647  int i=1;
648  int s=1;
649  int z=1;
650  while (pm[i]!=zeilenumbruch)
651  {
652    if (pm[i]==" ")
653    {
654      s++;
655    }
656    i++;
657  }
658  // if we want to have affine coordinates
659  if (art=="affine")
660  {   
661    s--; // then there is one column less
662    // and the entry of the first column (in the first row) has to be removed
663    while (pm[1]!=" ")
664    {
665      pm=stringdelete(pm,1);
666    }
667    pm=stringdelete(pm,1);
668  }
669  // we add two line breaks at the end in order to have this as a stopping criterion
670  pm=pm+zeilenumbruch+zeilenumbruch;
671  // we now have to work through each row
672  for (i=1;i<=size(pm);i++)
673  {
674    // if there are two consecutive line breaks we are done
675    if ((pm[i]==zeilenumbruch) and (pm[i+1]==zeilenumbruch))
676    {
677      i=size(pm)+1;
678    }
679    else
680    {
681      // a line break has to be replaced by a comma
682      if (pm[i]==zeilenumbruch)
683      {
684        z++;
685        pm[i]=",";
686        // if we want to have affine coordinates, then we have to delete the first entry in each row
687        if (art=="affine")
688        {
689         while (pm[i+1]!=" ")
690         {
691           pm=stringdelete(pm,i+1);
692         }
693         pm=stringdelete(pm,i+1);
694        }
695      }
696      // a space has to be replaced by a comma
697      if (pm[i]==" ")
698      {
699        pm[i]=",";     
700      }
701    }
702  }
703  // if we have introduced superflous commata at the end, they should be removed
704  while (pm[size(pm)]==",")
705  {
706    pm=stringdelete(pm,size(pm));
707  }
708  // since the matrix could be over the rationals, we need a ring with rational coefficients
709  ring zwischering=0,x,lp;   
710  // create the matrix with the elements of pm as entries
711  execute("matrix mm["+string(z)+"]["+string(s)+"]="+pm+";");
712  // transform this into an integer matrix
713  matrix M[1][ncols(mm)]; // takes a row of mm
714  int cm;  // takes a lowest common multiple
715  // multiply each row by an integer such that its entries are integers
716  for (int j=1;j<=nrows(mm);j++)
717  {
718    M=mm[j,1..ncols(mm)];
719    cm=commondenominator(M);
720    for (i=1;i<=ncols(mm);i++)
721    {
722      mm[j,i]=cm*mm[j,i];
723    }
724  }
725  // transform the matrix mm into an integer matrix
726  execute("intmat im["+string(z)+"]["+string(s)+"]="+string(mm)+";");
727  return(im);
728}
729example
730{
731   "EXAMPLE:";
732   echo=2;
733   // this is the usual output of some polymake computation
734   string pm="VERTICES
7350 1 3 5/3 1/3 -1 -23/3 -1/3 5/3 1/3 1
7360 1 3 -23/3 5/3 1 5/3 1/3 1/3 -1/3 -1
7370 1 1 1/3 -1/3 -1 5/3 1/3 -23/3 5/3 3
7380 1 1 5/3 -23/3 3 1/3 5/3 -1/3 1/3 -1
7390 1 -1 1/3 5/3 3 -1/3 -23/3 1/3 5/3 1
7400 1 -1 -1/3 1/3 1 1/3 5/3 5/3 -23/3 3
7410 1 -1 1 3 -5 -1 3 -1 1 -1
7420 1 -1 -1 -1 -1 1 1 3 3 -5
7430 1 -5 3 1 -1 3 -1 1 -1 -1
744
745";
746   intmat PM=polymakeToIntmat(pm,"affine");
747   // note that the first column has been removed, since we asked for
748   // affine coordinates, and the denominators have been cleared
749   print(PM);
750}
751
752////////////////////////////////////////////////////////////////////////////////////////
753/// PROCEDURES USING TOPCOM
754////////////////////////////////////////////////////////////////////////////////////////
755
756proc triangulations (list polygon)
757"USAGE:  triangulations(polygon); list polygon
758ASSUME:  polygon is a list of integer vectors of the same size representing the affine
759         coordinates of the lattice points
760PURPOSE: the procedure considers the marked polytope given as the convex hull of
761         the lattice points and with these lattice points as markings; it then
762         computes all possible triangulations of this marked polytope
763RETURN:  list, each entry corresponds to one triangulation and the ith entry is
764               itself a list of integer vectors of size three, where each integer
765               vector defines one triangle in the triangulation by telling which
766               points of the input are the vertices of the triangle
767NOTE:  - the procedure calls for its computations the program points2triangs
768         from the program topcom by Joerg Rambau, Universitaet Bayreuth; it
769         therefore is necessary that this program is installed in order to use this
770         procedure;
771         see http://www.uni-bayreuth.de/departments/wirtschaftsmathematik/rambau/TOPCOM
772       - the procedure creates the files /tmp/triangulationsinput and /tmp/triangulationsoutput;
773         the former is used as input for points2triangs and the latter is its output
774         containing the triangulations of corresponding to points in the format
775         of points2triangs; this can be use for further computations with topcom
776       - note that an integer i in an integer vector representing a triangle refers to
777         the ith lattice point, i.e. polygon[i]; this convention is different from
778         TOPCOM's convention, where i would refer to the i-1st lattice point
779EXAMPLE: example triangulations;   shows an example"
780{
781  int i,j;
782  // prepare the input for points2triangs by writing the input polygon in the
783  // necessary format
784  string spi="[";
785  for (i=1;i<=size(polygon);i++)
786  {
787    polygon[i][size(polygon[i])+1]=1;
788    spi=spi+"["+string(polygon[i])+"]";
789    if (i<size(polygon))
790    {
791      spi=spi+",";
792    }
793  }
794  spi=spi+"]";
795  write(":w /tmp/triangulationsinput",spi);
796  // call points2triangs
797  system("sh","cd /tmp; points2triangs < triangulationsinput > triangulationsoutput");
798  string p2t=read("/tmp/triangulationsoutput"); // takes the result of points2triangs
799  // preprocessing of p2t if points2triangs is version >= 0.15 brings p2t to the format of version 0.14
800  string np2t; // takes the triangulations in Singular format
801  for (i=1;i<=size(p2t)-2;i++)
802  {
803    if ((p2t[i]==":") and (p2t[i+1]=="=") and (p2t[i+2]=="["))
804    {
805      np2t=np2t+p2t[i]+p2t[i+1];
806      i=i+3;
807      while (p2t[i]!=":")
808      {
809        i=i+1;
810      }
811    }
812    else
813    {
814      if ((p2t[i]=="]") and (p2t[i+1]==";"))
815      {
816        np2t=np2t+p2t[i+1];
817        i=i+1;
818      }
819      else
820      {       
821        np2t=np2t+p2t[i];
822      }
823    }
824  }
825  if (p2t[size(p2t)-1]=="]")
826  {
827    np2t=np2t+p2t[size(p2t)];
828  }
829  else
830  {
831    if (np2t[size(np2t)]!=";")
832    {     
833      np2t=np2t+p2t[size(p2t)-1]+p2t[size(p2t)];
834    }
835  }
836  p2t=np2t;
837  np2t="";
838  // transform the points2triangs output of version 0.14 into Singular format
839  for (i=1;i<=size(p2t);i++)
840  {
841    if (p2t[i]=="=")
842    {
843      np2t=np2t+p2t[i]+"list(";
844      i++;
845    }
846    else
847    {
848      if (p2t[i]!=":")
849      {
850        if ((p2t[i]=="}") and (p2t[i+1]=="}"))
851        {
852          np2t=np2t+"))";
853          i++;
854        }     
855        else
856        {
857          if (p2t[i]=="{")
858          {
859            np2t=np2t+"intvec(";
860          }
861          else
862          {
863            if (p2t[i]=="}")
864            {
865              np2t=np2t+")";
866            }
867            else
868            {
869              np2t=np2t+p2t[i];
870            }
871          }
872        }
873      }
874    }
875  }
876  list T;
877  execute(np2t);
878  // raise each index by one
879  for (i=1;i<=size(T);i++)
880  {
881    for (j=1;j<=size(T[i]);j++)
882    {
883      T[i][j]=T[i][j]+1;
884    }
885  }
886  return(T);
887}
888example
889{
890   "EXAMPLE:";
891   echo=2;
892   // the lattice points of the unit square in the plane
893   list polygon=intvec(0,0),intvec(0,1),intvec(1,0),intvec(1,1);
894   // the triangulations of this lattice point configuration are computed
895   list triang=triangulations(polygon);
896   triang;
897}
898
899proc secondaryPolytope (list polygon,list #)
900"USAGE:  secondaryPolytope(polygon[,#]); list polygon, list #
901ASSUME:  - polygon is a list of integer vectors of the same size representing the affine
902           coordinates of lattice points
903         - if the triangulations of the corresponding polygon have already been computed
904           with the procedure triangulations then these can be given as a second (optional)
905           argument in order to avoid doing this computation again
906PURPOSE: the procedure considers the marked polytope given as the convex hull of
907         the lattice points and with these lattice points as markings; it then
908         computes the lattice points of the secondary polytope given by this
909         marked polytope which correspond to the triangulations computed by
910         the procedure triangulations
911RETURN:  list, say L, such that:
912               L[1] = intmat, each row gives the affine coordinates of a lattice point
913                      in the secondary polytope given by the marked
914                      polytope corresponding to polygon
915               L[2] = the list of corresponding triangulations
916NOTE:    if the triangluations are not handed over as optional argument the procedure calls
917         for its computation of these triangulations the program points2triangs
918         from the program topcom by Joerg Rambau, Universitaet Bayreuth; it
919         therefore is necessary that this program is installed in order to use this
920         procedure;
921         see http://www.uni-bayreuth.de/departments/wirtschaftsmathematik/rambau/TOPCOM
922EXAMPLE: example secondaryPolytope;   shows an example"
923{
924  // compute the triangulations of the point configuration with points2triangs
925  if (size(#)==0)
926  {
927    list triangs=triangulations(polygon);
928  }
929  else
930  {
931    list triangs=#;
932  }
933  int i,j,k,l;
934  intmat N[2][2]; // is used to compute areas of triangles
935  intvec vertex;  // stores a point in the secondary polytope as intermediate result
936  int eintrag;
937  int halt;
938  intmat secpoly[size(triangs)][size(polygon)];   // stores all lattice points of the secondary polytope
939  // consider each triangulation and compute the corresponding point in the secondary polytope
940  for (i=1;i<=size(triangs);i++)
941  {
942    // for each triangulation we have to compute the coordinates corresponding to each marked point
943    for (j=1;j<=size(polygon);j++)
944    {
945      eintrag=0;
946      // for each marked point we have to consider all triangles in the triangulation
947      // which involve this particular point
948      for (k=1;k<=size(triangs[i]);k++)
949      {
950        halt=0;
951        for (l=1;(l<=3) and (halt==0);l++)
952        {
953          if (triangs[i][k][l]==j)
954          {
955            halt=1;
956            N[1,1]=polygon[triangs[i][k][3]][1]-polygon[triangs[i][k][1]][1];
957            N[1,2]=polygon[triangs[i][k][2]][1]-polygon[triangs[i][k][1]][1];
958            N[2,1]=polygon[triangs[i][k][3]][2]-polygon[triangs[i][k][1]][2];
959            N[2,2]=polygon[triangs[i][k][2]][2]-polygon[triangs[i][k][1]][2];
960            eintrag=eintrag+abs(det(N));
961          }
962        }
963      }
964      vertex[j]=eintrag;
965    }
966    secpoly[i,1..size(polygon)]=vertex;
967  }
968  return(list(secpoly,triangs));         
969}
970example
971{
972   "EXAMPLE:";
973   echo=2;
974   // the lattice points of the unit square in the plane
975   list polygon=intvec(0,0),intvec(0,1),intvec(1,0),intvec(1,1);
976   // the secondary polytope of this lattice point configuration is computed
977   list secpoly=secondaryPolytope(polygon);
978   // the points in the secondary polytope
979   print(secpoly[1]);
980   // the corresponding triangulations
981   secpoly[2];
982}
983
984////////////////////////////////////////////////////////////////////////////////////////
985/// PROCEDURES CONCERNED WITH PLANAR POLYGONS
986////////////////////////////////////////////////////////////////////////////////////////
987
988proc cycleLength (list boundary,intvec interior)
989"USAGE:  cycleLength(boundary,interior); list boundary, intvec interior
990ASSUME:  boundary is a list of integer vectors describing a cycle in some convex lattice
991         polygon around the lattice point interior ordered clock wise
992RETURN:  string, the cycle length of the corresponding cycle in the dual tropical curve
993EXAMPLE: example cycleLength;   shows an example"
994{
995  int j;
996  // create a ring whose variables are indexed by the points in boundary resp. by interior
997  string rst="ring cyclering=0,(u"+string(interior[1])+string(interior[2]);
998  for (j=1;j<=size(boundary);j++)
999  {
1000    rst=rst+",u"+string(boundary[j][1])+string(boundary[j][2]);
1001  }
1002  rst=rst+"),lp;";
1003  execute(rst);
1004  // add the first and second point at the end of boundary
1005  boundary[size(boundary)+1]=boundary[1];
1006  boundary[size(boundary)+1]=boundary[2];
1007  poly cl,summand; // takes the cycle length
1008  matrix N1[2][2]; // used to compute the area of a triangle
1009  matrix N2[2][2]; // used to compute the area of a triangle
1010  matrix N3[2][2]; // used to compute the area of a triangle
1011  // for each original point in the boundary compute its contribution to the cycle
1012  for (j=2;j<=size(boundary)-1;j++)
1013  {
1014    N1=boundary[j-1]-interior,boundary[j]-interior;
1015    N2=boundary[j]-interior,boundary[j+1]-interior;
1016    N3=boundary[j+1]-interior,boundary[j-1]-interior;
1017    execute("summand=-u"+string(boundary[j][1])+string(boundary[j][2])+"+u"+string(interior[1])+string(interior[2])+";");
1018    summand=summand*(det(N1)+det(N2)+det(N3))/(det(N1)*det(N2));
1019    cl=cl+summand;
1020  }
1021  return(string(cl));
1022}
1023example
1024{
1025   "EXAMPLE:";
1026   echo=2;
1027   // the integer vectors in boundary are lattice points on the boundary
1028   // of a convex lattice polygon in the plane
1029   list boundary=intvec(0,0),intvec(0,1),intvec(0,2),intvec(2,2),intvec(2,1),intvec(2,0);
1030   // interior is a lattice point in the interior of this lattice polygon
1031   intvec interior=1,1;
1032   // compute the general cycle length of a cycle of the corresponding cycle
1033   // in the dual tropical curve -- note that (0,1) and (2,1) do not contribute
1034   cycleLength(boundary,interior);
1035}
1036
1037proc splitPolygon (list markings)
1038"USAGE:  splitPolygon (markings);  markings list
1039ASSUME:  markings is a list of integer vectors representing lattice points in the plane
1040         which we consider as the marked points of the convex lattice polytope spanned by them
1041PURPOSE: split the marked points in the vertices, the points on the facets which are not vertices,
1042         and the interior points
1043RETURN:  list, L consisting of three lists
1044               L[1]    : represents the vertices the polygon ordered clockwise
1045                         L[1][i][1] = intvec, the coordinates of the ith vertex
1046                         L[1][i][2] = int, the position of L[1][i][1] in markings
1047               L[2][i] : represents the lattice points on the facet of the polygon with
1048                         endpoints L[1][i] and L[1][i+1] (i considered modulo size(L[1]))
1049                         L[2][i][j][1] = intvec, the coordinates of the jth lattice point on that facet
1050                         L[2][i][j][2] = int, the position of L[2][i][j][1] in markings
1051               L[3]    : represents the interior lattice points of the polygon
1052                         L[3][i][1] = intvec, the coordinates of the ith interior point
1053                         L[3][i][2] = int, the position of L[3][i][1] in markings
1054EXAMPLE: example splitPolygon;   shows an example"
1055{
1056  list vert; // stores the result
1057  // compute the boundary of the polygon in an oriented way
1058  list pb=findOrientedBoundary(markings);
1059  // the vertices are just the second entry of pb
1060  vert[1]=pb[2];
1061  int i,j,k;      // indices
1062  list boundary;  // stores the points on the facets of the polygon which are not vertices
1063  // append to the boundary points as well as to the vertices the first vertex a second time
1064  pb[1]=pb[1]+list(pb[1][1]);
1065  pb[2]=pb[2]+list(pb[2][1]);
1066  // for each vertex find all points on the facet of the polygon with this vertex
1067  // and the next vertex as endpoints
1068  int z=2;
1069  for (i=1;i<=size(vert[1]);i++)
1070  {
1071    j=1;
1072    list facet; // stores the points on this facet which are not vertices
1073    // while the next vertex is not reached, store the boundary lattice point
1074    while (pb[1][z]!=pb[2][i+1])
1075    {
1076      facet[j]=pb[1][z];
1077      j++;
1078      z++;
1079    }
1080    // store the points on the ith facet as boundary[i]
1081    boundary[i]=facet;
1082    kill facet;
1083    z++;
1084  }
1085  // store the information on the boundary in vert[2]
1086  vert[2]=boundary;
1087  // find the remaining points in the input which are not on the boundary by checking
1088  // for each point in markings if it is contained in pb[1]
1089  list interior=markings;
1090  for (i=size(interior);i>=1;i--)
1091  {
1092    for (j=1;j<=size(pb[1])-1;j++)
1093    {
1094      if (interior[i]==pb[1][j])
1095      {
1096        interior=delete(interior,i);
1097        j=size(pb[1]);
1098      }
1099    }
1100  }
1101  // store the interior points in vert[3]
1102  vert[3]=interior;
1103  // add to each point in vert the index which it gets from its position in the input markings;
1104  // do so for ver[1]
1105  for (i=1;i<=size(vert[1]);i++)
1106  {
1107    j=1;
1108    while (markings[j]!=vert[1][i])
1109    {
1110      j++;
1111    }
1112    vert[1][i]=list(vert[1][i],j);
1113  }
1114  // do so for ver[2]
1115  for (i=1;i<=size(vert[2]);i++)
1116  {
1117    for (k=1;k<=size(vert[2][i]);k++)
1118    {
1119      j=1;
1120      while (markings[j]!=vert[2][i][k])
1121      {
1122        j++;
1123      }
1124      vert[2][i][k]=list(vert[2][i][k],j);
1125    }
1126  }
1127  // do so for ver[3]
1128  for (i=1;i<=size(vert[3]);i++)
1129  {
1130    j=1;
1131    while (markings[j]!=vert[3][i])
1132    {
1133      j++;
1134    }
1135    vert[3][i]=list(vert[3][i],j);
1136  } 
1137  return(vert);
1138}
1139example
1140{
1141   "EXAMPLE:";
1142   echo=2;
1143   // the lattice polygon spanned by the points (0,0), (3,0) and (0,3)
1144   // with all integer points as markings
1145   list polygon=intvec(1,1),intvec(3,0),intvec(2,0),intvec(1,0),intvec(0,0),intvec(2,1),intvec(0,1),intvec(1,2),intvec(0,2),intvec(0,3);
1146   // split the polygon in its vertices, its facets and its interior points
1147   list sp=splitPolygon(polygon);
1148   // the vertices
1149   sp[1];
1150   // the points on facets which are not vertices
1151   sp[2];
1152   // the interior points
1153   sp[3];
1154}
1155
1156
1157proc eta (list triang,list polygon)
1158"USAGE:  eta(triang,polygon);  triang, polygon list
1159ASSUME:  polygon has the format of the output of splitPolygon, i.e. it is a list with three
1160         entries describing a convex lattice polygon in the following way:
1161         polygon[1] : is a list of lists; for each i the entry polygon[1][i][1] is a lattice point which is
1162                      a vertex of the lattice polygon, and polygon[1][i][2] is an integer assigned to
1163                      this lattice point as identifying index
1164         polygon[2] : is a list of lists; for each vertex of the polygon, i.e. for each entry in polygon[1],
1165                      it contains a list polygon[2][i], which contains the lattice points on the facet
1166                      with endpoints polygon[1][i] and polygon[1][i+1] - i considered mod size(polygon[1]);
1167                      each such lattice point contributes an entry polygon[2][i][j][1] which is an integer
1168                      vector giving the coordinate of the lattice point and an entry polygon[2][i][j][2]
1169                      which is the identifying index
1170         polygon[3] : is a list of lists, where each entry corresponds to a lattice point in the
1171                      interior of the polygon, with polygon[3][j][1] being the coordinates of the point
1172                      and polygon[3][j][2] being the identifying index;
1173         triang is a list of integer vectors all of size three describing a triangulation of the
1174         polygon described by polygon; if an entry of triang is the vector (i,j,k) then the triangle
1175         is build by the vertices with indices i, j and k
1176RETURN:  intvec, the integer vector eta describing that vertex of the Newton polytope discriminant
1177                 of the polygone whose dual cone in the Groebner fan contains the cone of the
1178                 secondary fan of the polygon corresponding to the given triangulation
1179NOTE:    for a better description of eta see either Gelfand, Kapranov, Zelevinski: Discriminants,
1180         Resultants and multidimensional Determinants. Chapter 10.
1181EXAMPLE: example eta;   shows an example"
1182{
1183  int i,j,k,l,m,n; // index variables
1184  list ordpolygon;   // stores the lattice points in the order used in the triangulation
1185  list triangarea; // stores the areas of the triangulations
1186  intmat N[2][2];  // used to compute triangle areas
1187  // 1) store the lattice points in the order used in the triangulation
1188  // go first through all vertices of the polytope
1189  for (j=1;j<=size(polygon[1]);j++)
1190  {
1191    ordpolygon[polygon[1][j][2]]=polygon[1][j][1];
1192  }
1193  // then consider all inner points
1194  for (j=1;j<=size(polygon[3]);j++)
1195  {
1196    ordpolygon[polygon[3][j][2]]=polygon[3][j][1];
1197  }
1198  // finally consider all lattice points on the boundary which are not vertices
1199  for (j=1;j<=size(polygon[2]);j++)
1200  {
1201    for (i=1;i<=size(polygon[2][j]);i++)
1202    {
1203      ordpolygon[polygon[2][j][i][2]]=polygon[2][j][i][1];
1204    }
1205  }
1206  // 2) compute for each triangle in the triangulation the area of the triangle
1207  for (i=1;i<=size(triang);i++)
1208  {
1209    // Note that the ith lattice point in orderedpolygon has the number i-1 in the triangulation!
1210    N=ordpolygon[triang[i][1]]-ordpolygon[triang[i][2]],ordpolygon[triang[i][1]]-ordpolygon[triang[i][3]];
1211    triangarea[i]=abs(det(N));
1212  }
1213  intvec ETA;        // stores the eta_ij
1214  int etaij;         // stores the part of eta_ij during computations which comes from triangle areas
1215  int seitenlaenge;  // stores the part of eta_ij during computations which comes from boundary facets
1216  list seiten;       // stores the lattice points on facets of the polygon
1217  intvec v;          // used to compute a facet length
1218  // 3) store first in seiten[i] all lattice points on the facet connecting the ith vertex,
1219  //    i.e. polygon[1][i], with the i+1st vertex, i.e. polygon[1][i+1], where we replace i+1
1220  //    1 if i=size(polygon[1]);
1221  //    then append the last entry of seiten once more at the very beginning of seiten, so
1222  //    that the index is shifted by one
1223  for (i=1;i<=size(polygon[1]);i++)
1224  {
1225    if (i<size(polygon[1]))
1226    {
1227      seiten[i]=list(polygon[1][i])+polygon[2][i]+list(polygon[1][i+1]);
1228    }
1229    else
1230    {
1231      seiten[i]=list(polygon[1][i])+polygon[2][i]+list(polygon[1][1]);
1232    }
1233  }
1234  seiten=insert(seiten,seiten[size(seiten)],0);
1235  // 4) compute the eta_ij for all vertices of the polygon
1236  for (j=1;j<=size(polygon[1]);j++)
1237  {
1238    // the vertex itself contributes a 1
1239    etaij=1;
1240    // check for each triangle in the triangulation ...
1241    for (k=1;k<=size(triang);k++)
1242    {
1243      // ... if the vertex is actually a vertex of the triangle ...
1244      if ((polygon[1][j][2]==triang[k][1]) or (polygon[1][j][2]==triang[k][2]) or (polygon[1][j][2]==triang[k][3]))
1245      {
1246        // ... if so, add the area of the triangle to etaij
1247        etaij=etaij+triangarea[k];
1248        // then check if that triangle has a facet which is contained in one of the
1249        // two facets of the polygon which are adjecent to the given vertex ...
1250        // these two facets are seiten[j] and seiten[j+1]
1251        for (n=j;n<=j+1;n++)
1252        {
1253          // check for each lattice point in the facet of the polygon ...
1254          for (l=1;l<=size(seiten[n]);l++)
1255          {
1256            // ... and for each lattice point in the triangle ...
1257            for (m=1;m<=size(triang[k]);m++)
1258            {
1259              // ... if they coincide and are not the vertex itself ...
1260              if ((seiten[n][l][2]==triang[k][m]) and (seiten[n][l][2]!=polygon[1][j][2]))
1261              {
1262                // if so, then compute the vector pointing from this lattice point to the vertex
1263                v=polygon[1][j][1]-seiten[n][l][1];
1264                // and the lattice length of this vector has to be subtracted from etaij
1265                etaij=etaij-abs(gcd(v[1],v[2]));
1266              }
1267            }
1268          }
1269        }
1270      }
1271    }
1272    // store etaij in the list
1273    ETA[polygon[1][j][2]]=etaij;
1274  }
1275  // 5) compute the eta_ij for all lattice points on the facets of the polygon which are not vertices,
1276  //    these are the lattice points in polygon[2][1] to polygon[2][size(polygon[1])]
1277  for (i=1;i<=size(polygon[2]);i++)
1278  {
1279    for (j=1;j<=size(polygon[2][i]);j++)
1280    {     
1281      // initialise etaij
1282      etaij=0;
1283      // initialise seitenlaenge
1284      seitenlaenge=0;
1285      // check for each triangle in the triangulation ...
1286      for (k=1;k<=size(triang);k++)
1287      {
1288        // ... if the vertex is actually a vertex of the triangle ...
1289        if ((polygon[2][i][j][2]==triang[k][1]) or (polygon[2][i][j][2]==triang[k][2]) or (polygon[2][i][j][2]==triang[k][3]))
1290        {
1291          // ... if so, add the area of the triangle to etaij
1292          etaij=etaij+triangarea[k];
1293          // then check if that triangle has a facet which is contained in the
1294          // facet of the polygon which contains the lattice point in question,
1295          // this is the facet seiten[i+1];
1296          // check for each lattice point in the facet of the polygon ...
1297          for (l=1;l<=size(seiten[i+1]);l++)
1298          {
1299            // ... and for each lattice point in the triangle ...
1300            for (m=1;m<=size(triang[k]);m++)
1301            {           
1302              // ... if they coincide and are not the vertex itself ...
1303              if ((seiten[i+1][l][2]==triang[k][m]) and (seiten[i+1][l][2]!=polygon[2][i][j][2]))
1304              {
1305                // if so, then compute the vector pointing from this lattice point to the vertex
1306                v=polygon[2][i][j][1]-seiten[i+1][l][1];
1307                // and the lattice length of this vector contributes to seitenlaenge
1308                seitenlaenge=seitenlaenge+abs(gcd(v[1],v[2]));
1309              }
1310            }
1311          }
1312        }
1313      }
1314      // if the lattice point was a vertex of any triangle in the triangulation ...
1315      if (etaij!=0)
1316      {
1317        // then eta_ij is the sum of the triangle areas minus seitenlaenge
1318        ETA[polygon[2][i][j][2]]=etaij-seitenlaenge;
1319      }
1320      else
1321      {
1322        // otherwise it is just zero
1323        ETA[polygon[2][i][j][2]]=0;
1324      }
1325    }
1326  }
1327  // 4) compute the eta_ij for all inner lattice points of the polygon
1328  for (j=1;j<=size(polygon[3]);j++)
1329  {
1330    // initialise etaij
1331    etaij=0;
1332    // check for each triangle in the triangulation ...
1333    for (k=1;k<=size(triang);k++)
1334    {
1335      // ... if the vertex is actually a vertex of the triangle ...
1336      if ((polygon[3][j][2]==triang[k][1]) or (polygon[3][j][2]==triang[k][2]) or (polygon[3][j][2]==triang[k][3]))
1337      {
1338        // ... if so, add the area of the triangle to etaij
1339        etaij=etaij+triangarea[k];
1340      }
1341    }
1342    // store etaij in ETA
1343    ETA[polygon[3][j][2]]=etaij;
1344  }
1345  return(ETA);
1346}
1347example
1348{
1349   "EXAMPLE:";
1350   echo=2;
1351   // the lattice polygon spanned by the points (0,0), (3,0) and (0,3)
1352   // with all integer points as markings
1353   list polygon=intvec(1,1),intvec(3,0),intvec(2,0),intvec(1,0),intvec(0,0),intvec(2,1),intvec(0,1),intvec(1,2),intvec(0,2),intvec(0,3);
1354   // split the polygon in its vertices, its facets and its interior points
1355   list sp=splitPolygon(polygon);
1356   // define a triangulation by connecting the only interior point with the vertices
1357   list triang=intvec(1,2,5),intvec(1,5,10),intvec(1,5,10);
1358   // compute the eta-vector of this triangulation
1359   eta(triang,sp);
1360}
1361 
1362proc findOrientedBoundary (list polygon)
1363"USAGE:      findOrientedBoundary(polygon); polygon list
1364ASSUME:      polygon is a list of integer vectors defining integer lattice points in the plane
1365RETURN:      list, l[1] = list of integer vectors such that the polygonal path defined by
1366                          these is the boundary of the convex hull of the lattice points in polygon
1367                   l[2] = list, the redundant points in l[1] have been removed
1368EXAMPLE:     example findOrientedBoundary;   shows an example"
1369{
1370  // Order the vertices such that passing from one to the next we travel along
1371  // the boundary of the convex hull of the vertices clock wise
1372  int d,k,i,j;
1373  intmat D[2][2];
1374  /////////////////////////////////////
1375  // Treat first the pathological cases that the polygon is not two-dimensional:
1376  /////////////////////////////////////
1377  // if the polygon is empty or only one point or a line segment of two points
1378  if (size(polygon)<=2)
1379  {
1380    return(list(polygon,polygon));
1381  }
1382  // check is the polygon is only a line segment given by more than two points;
1383  // for this first compute sum of the absolute values of the determinants of the matrices whose
1384  // rows are the vectors pointing from the first to the second point and from the
1385  // the first point to the ith point for i=3,...,size(polygon); if this sum is zero
1386  // then the polygon is a line segment and we have to find its end points
1387  d=0;
1388  for (i=3;i<=size(polygon);i++)
1389  {
1390    D=polygon[2]-polygon[1],polygon[i]-polygon[1];
1391    d=d+abs(det(D));
1392  }
1393  if (d==0) // then polygon is a line segment
1394  {
1395    intmat laenge[size(polygon)][size(polygon)];
1396    intvec mp;
1397    //   for this collect first all vectors pointing from one lattice point to the next,
1398    //   compute their pairwise angles and their lengths
1399    for (i=1;i<=size(polygon)-1;i++)
1400    {     
1401      for (j=i+1;j<=size(polygon);j++)
1402      {
1403        mp=polygon[i]-polygon[j];
1404        laenge[i,j]=abs(gcd(mp[1],mp[2]));
1405      }
1406    }
1407    mp=maxPosInIntmat(laenge);
1408    list endpoints=polygon[mp[1]],polygon[mp[2]];
1409    intvec abstand;
1410    for (i=1;i<=size(polygon);i++)
1411    {
1412      abstand[i]=0;
1413      if (i<mp[1])
1414      {
1415        abstand[i]=laenge[i,mp[1]];
1416      }
1417      if (i>mp[1])
1418      {
1419        abstand[i]=laenge[mp[1],i];
1420      }
1421    }
1422    polygon=sortlistbyintvec(polygon,abstand);
1423    return(list(polygon,endpoints));
1424  } 
1425  ///////////////////////////////////////////////////////////////
1426  list orderedvertices;  // stores the vertices in an ordered way
1427  list minimisedorderedvertices;  // stores the vertices in an ordered way; redundant ones removed
1428  list comparevertices; // stores vertices which should be compared to the testvertex
1429  orderedvertices[1]=polygon[1]; // set the starting vertex
1430  minimisedorderedvertices[1]=polygon[1]; // set the starting vertex
1431  intvec testvertex=polygon[1];  // the vertex to which the others have to be compared
1432  intvec startvertex=polygon[1]; // keep the starting vertex to test, when the end is reached
1433  int endtest;                    // is set to one, when the end is reached
1434  int startvertexfound;// is 1, once for some testvertex a candidate for the next vertex has been found
1435  polygon=delete(polygon,1);    // delete the testvertex
1436  intvec v,w;
1437  int l=1;  // counts the vertices
1438  // the basic idea is that a vertex can be the next one on the boundary if all other vertices
1439  // ly to the right of the vector v pointing from the testvertex to this one; this can be tested
1440  // by checking if the determinant of the 2x2-matrix with first column v and second column the vector w,
1441  // pointing from the testvertex to the new vertex, is non-positive; if this is the case for all
1442  // new vertices, then the one in consideration is a possible choice for the next vertex on the boundary
1443  // and it is stored in naechste; we can then order the candidates according to their distance from
1444  // the testvertex; then they occur on the boundary in that order!
1445  while (endtest==0)
1446  {
1447    list naechste;  // stores the possible choices for the next vertex
1448    k=1;
1449    for (i=1;i<=size(polygon);i++)
1450    {
1451      d=0;  // stores the value of the determinant of (v,w)
1452      v=polygon[i]-testvertex; // points from the testvertex to the ith vertex
1453      comparevertices=delete(polygon,i); // we needn't compare v to itself
1454      // we should compare v to the startvertex-testvertex; in the first calling of the loop
1455      // this is irrelevant since the difference will be zero; however, later on it will
1456      // be vital, since we delete the vertices which we have already tested from the list
1457      // of all vertices, and when all vertices on the boundary have been found we would
1458      // therefore find a vertex in the interior as candidate; but always testing against
1459      // the starting vertex, this can not happen
1460      comparevertices[size(comparevertices)+1]=startvertex;
1461      for (j=1;(j<=size(comparevertices)) and (d<=0);j++)
1462      {
1463        w=comparevertices[j]-testvertex; // points form the testvertex to the jth vertex
1464        D=v,w;
1465        d=det(D);
1466      }
1467      if (d<=0) // if all determinants are non-positive, then the ith vertex is a candidate
1468      {
1469        naechste[k]=list(polygon[i],i,scalarproduct(v,v)); // we store the vertex, its position, and its
1470        k++;                                                // distance from the testvertex
1471      }
1472    }
1473    if (size(naechste)>0) // then a candidate for the next vertex has been found
1474    {     
1475      startvertexfound=1; // at least once a candidate has been found
1476      naechste=sortlist(naechste,3);  //we order the candidates according to their distance from testvertex;
1477      for (j=1;j<=size(naechste);j++) // then we store them in this order in orderedvertices
1478      {
1479        l++;
1480        orderedvertices[l]=naechste[j][1];
1481      }
1482      testvertex=naechste[size(naechste)][1];  // we store the last one as next testvertex;
1483      minimisedorderedvertices[size(minimisedorderedvertices)+1]=testvertex; // store the next corner of NSD
1484      naechste=sortlist(naechste,2);           // then we reorder the vertices according to their position
1485      for (j=size(naechste);j>=1;j--)          // and we delete them from the vertices
1486      {
1487        polygon=delete(polygon,naechste[j][2]);
1488      }
1489    }
1490    else // that means either that the vertex was inside the polygon,
1491    {    // or that we have reached the last vertex on the boundary of the polytope
1492      if (startvertexfound==0) // the vertex was in the interior; we delete it and start all over again
1493      {       
1494        orderedvertices[1]=polygon[1];
1495        minimisedorderedvertices[1]=polygon[1];
1496        testvertex=polygon[1];
1497        startvertex=polygon[1];
1498        polygon=delete(polygon,1);
1499      }
1500      else // we have reached the last vertex on the boundary of the polytope and can stop
1501      {
1502        endtest=1;
1503      }
1504    }
1505    kill naechste;
1506  }
1507  // test if the first vertex in minimisedorderedvertices is on the same line with the second and
1508  // the last, i.e. if we started our search in the middle of a face; if so, delete it
1509  v=minimisedorderedvertices[2]-minimisedorderedvertices[1];
1510  w=minimisedorderedvertices[size(minimisedorderedvertices)]-minimisedorderedvertices[1];
1511  D=v,w;
1512  if (det(D)==0)
1513  {
1514    minimisedorderedvertices=delete(minimisedorderedvertices,1);
1515  }
1516  // test if the first vertex in minimisedorderedvertices is on the same line with the two
1517  // last ones, i.e. if we started our search at the end of a face; if so, delete it
1518  v=minimisedorderedvertices[size(minimisedorderedvertices)-1]-minimisedorderedvertices[1];
1519  w=minimisedorderedvertices[size(minimisedorderedvertices)]-minimisedorderedvertices[1];
1520  D=v,w;
1521  if (det(D)==0)
1522  {
1523    minimisedorderedvertices=delete(minimisedorderedvertices,size(minimisedorderedvertices));
1524  }
1525  return(list(orderedvertices,minimisedorderedvertices));
1526}
1527example
1528{
1529   "EXAMPLE:";
1530   echo=2;
1531// the following lattice points in the plane define a polygon
1532   list polygon=intvec(0,0),intvec(3,1),intvec(1,0),intvec(2,0),intvec(1,1),intvec(3,2),intvec(1,2),intvec(2,3),intvec(2,4);
1533// we compute its boundary
1534   list boundarypolygon=findOrientedBoundary(polygon);
1535// the points on the boundary ordered clockwise are boundarypolygon[1]
1536   boundarypolygon[1];
1537// the vertices of the boundary are boundarypolygon[2]
1538   boundarypolygon[2];
1539}
1540
1541
1542proc cyclePoints (list triang,list points,int pt)
1543"USAGE:      cyclePoints(triang,points,pt)  triang,points list, pt int
1544ASSUME:      points is a list of integer vectors describing the lattice points of a marked polygon;
1545             triang is a list of integer vectors describing a triangulation of the marked polygon
1546             in the sense that an integer vector of the form (i,j,k) describes the triangle formed
1547             by polygon[i], polygon[j] and polygon[k];
1548             pt is an integer between 1 and size(points), singling out a lattice point among
1549             the marked points
1550PURPOSE:     consider the convex lattice polygon, say P, spanned by all lattice points in points which
1551             in the triangulation triang are connected to the point points[pt]; the procedure
1552             computes all marked points in points which ly on the boundary of that polygon, ordered
1553             clockwise
1554RETURN:      list, of integer vectors which are the coordinates of the lattice points on
1555                   the boundary of the above mentioned polygon P, if this polygon is not the
1556                   empty set (that would be the case if points[pt] is not a vertex of any 
1557                   triangle in the triangulation); otherwise return the empty list
1558EXAMPLE:     example cyclePoints;   shows an example"
1559{
1560  int i,j; // indices
1561  list v;  // saves the indices of lattice points connected to the interior point in the triangulation
1562  // save all points in triangulations containing pt in v
1563  for (i=1;i<=size(triang);i++)
1564  {
1565    if ((triang[i][1]==pt) or (triang[i][2]==pt) or (triang[i][3]==pt))
1566    {
1567      j++;
1568      v[3*j-2]=triang[i][1];
1569      v[3*j-1]=triang[i][2];
1570      v[3*j]=triang[i][3];
1571    }
1572  }
1573  if (size(v)==0)
1574  {
1575    return(list());
1576  }
1577  // remove pt itself and redundancies in v
1578  for (i=size(v);i>=1;i--)
1579  {
1580    j=1;
1581    while ((j<i) and (v[i]!=v[j]))
1582    {
1583      j++;
1584    }
1585    if ((j<i) or (v[i]==pt))
1586    {
1587      v=delete(v,i);
1588    }
1589  }
1590  // save in pts the coordinates of the points with indices in v
1591  list pts;
1592  for (i=1;i<=size(v);i++)
1593  {
1594    pts[i]=points[v[i]];
1595  }
1596  // consider the convex polytope spanned by the points in pts, find the points on the
1597  // boundary and order them clockwise
1598  return(findOrientedBoundary(pts)[1]);
1599}
1600example
1601{
1602   "EXAMPLE:";
1603   echo=2;
1604   // the lattice polygon spanned by the points (0,0), (3,0) and (0,3)
1605   // with all integer points as markings
1606   list points=intvec(1,1),intvec(3,0),intvec(2,0),intvec(1,0),intvec(0,0),intvec(2,1),intvec(0,1),intvec(1,2),intvec(0,2),intvec(0,3);
1607   // define a triangulation
1608   list triang=intvec(1,2,5),intvec(1,5,7),intvec(1,7,9),intvec(8,9,10),intvec(1,8,9),intvec(1,2,8);
1609   // compute the points connected to (1,1) in triang
1610   cyclePoints(triang,points,1);
1611}
1612
1613proc latticeArea (list polygon)
1614"USAGE:  latticeArea(polygon);   polygon list
1615ASSUME:  polygon is a list of integer vectors in the plane
1616RETURN:  int, the lattice area of the convex hull of the lattice points in polygon,
1617              i.e. twice the Euclidean area
1618EXAMPLE: example polygonlatticeArea;   shows an example"
1619{
1620  list pg=findOrientedBoundary(polygon)[2];
1621  int area;
1622  intmat M[2][2];
1623  for (int i=2;i<=size(pg)-1;i++)
1624  {
1625    M[1,1..2]=pg[i]-pg[1];
1626    M[2,1..2]=pg[i+1]-pg[1];
1627    area=area+abs(det(M));
1628  }
1629  return(area);
1630}
1631example
1632{
1633   "EXAMPLE:";
1634   echo=2;
1635   // define a polygon with lattice area 5
1636   list polygon=intvec(1,2),intvec(1,0),intvec(2,0),intvec(1,1),intvec(2,1),intvec(0,0);
1637   latticeArea(polygon);
1638}
1639
1640proc picksFormula (list polygon)
1641"USAGE:  picksFormula(polygon);   polygon list
1642ASSUME:  polygon is a list of integer vectors in the plane and consider their convex hull C
1643RETURN:  list, L of three integersthe
1644               L[1] : the lattice area of C, i.e. twice the Euclidean area
1645               L[2] : the number of lattice points on the boundary of C
1646               L[3] : the number of interior lattice points of C
1647NOTE:    the integers in L are related by Pick's formula, namely: L[1]=L[2]+2*L[3]-2
1648EXAMPLE: example picksFormula;   shows an example"
1649{
1650  list pg=findOrientedBoundary(polygon)[2];
1651  int area,bdpts,i;
1652  intmat M[2][2];
1653  // compute the lattice area of the polygon, i.e. twice the Euclidean area
1654  for (i=2;i<=size(pg)-1;i++)
1655  {
1656    M[1,1..2]=pg[i]-pg[1];
1657    M[2,1..2]=pg[i+1]-pg[1];
1658    area=area+abs(det(M));
1659  }
1660  // compute the number of lattice points on the boundary
1661  intvec edge;
1662  pg[size(pg)+1]=pg[1];
1663  for (i=1;i<=size(pg)-1;i++)
1664  {
1665    edge=pg[i]-pg[i+1];
1666    bdpts=bdpts+abs(gcd(edge[1],edge[2]));
1667  }
1668  // Pick's formula says that the lattice area A, the number g of interior points and
1669  // the number b of boundary points are connected by the formula: A=b+2g-2
1670  return(list(area,bdpts,(area-bdpts+2)/2));
1671}
1672example
1673{
1674   "EXAMPLE:";
1675   echo=2;
1676   // define a polygon with lattice area 5
1677   list polygon=intvec(1,2),intvec(1,0),intvec(2,0),intvec(1,1),intvec(2,1),intvec(0,0);
1678   list pick=picksFormula(polygon);
1679   // the lattice area of the polygon is:
1680   pick[1];
1681   // the number of lattice points on the boundary is:
1682   pick[2];
1683   // the number of interior lattice points is:
1684   pick[3];
1685   // the number's are related by Pick's formula:
1686   pick[1]-pick[2]-2*pick[3]+2;
1687}
1688
1689proc ellipticNF (list polygon)
1690"USAGE:  ellipticNF(polygon);   polygon list
1691ASSUME:  polygon is a list of integer vectors in the plane such that their convex hull C
1692         has precisely one interior lattice point; i.e. C is the Newton polygon of an
1693         elliptic curve
1694PURPOSE: compute the normal form of the polygon with respect to the unimodular affine
1695         transformations T=A*x+v; there are sixteen different normal forms
1696         (see e.g. Bjorn Poonen, Fernando Rodriguez-Villegas: Lattice Polygons and
1697                   the number 12.  Amer. Math. Monthly  107  (2000),  no. 3, 238--250.)
1698RETURN:  list, L such that
1699               L[1] : list whose entries are the vertices of the normal form of the polygon
1700               L[2] : the matrix A of the unimodular transformation
1701               L[3] : the translation vector v of the unimodular transformation
1702               L[4] : list such that the ith entry is the image of polygon[i] under the
1703                      unimodular transformation T
1704EXAMPLE: example ellipticNF;   shows an example"
1705{
1706  int i;            // index
1707  intvec edge;      // stores the vector of an edge
1708  intvec boundary;  // stores the lattice lengths of the edges of the Newton cylce
1709  // find the vertices of the Newton cycle and order it clockwise
1710  list pg=findOrientedBoundary(polygon)[2];
1711  // check if there is precisely one interior point in the Newton polygon
1712  if (picksFormula(pg)[3]!=1)
1713  {
1714    ERROR("The polygon has not precisely one interior point!");
1715  }
1716  // insert the first vertex at the end once again
1717  pg[size(pg)+1]=pg[1];
1718  // compute the number of lattice points on each edge
1719  for (i=1;i<=size(pg)-1;i++)
1720  {
1721    edge=pg[i]-pg[i+1];
1722    boundary[i]=1+abs(gcd(edge[1],edge[2]));
1723  }
1724  // store the values of boundary once more adding the first two at the end
1725  intvec tboundary=boundary,boundary[1],boundary[2];
1726  // sort boundary in an asecending way
1727  intvec sbd=sortintvec(boundary);
1728  // find the first edge having the maximal number of lattice points
1729  int max=maxPosInIntvec(boundary);
1730  // some computations have to be done over the rationals
1731  ring transformationring=0,x,lp;
1732  intvec trans;    // stores the vector by which we have to translate the polygon
1733  intmat A[2][2];  // stores the matrix by which we have to transform the polygon
1734  matrix M[3][3];  // stores the projective coordinates of the points which are to be transformed
1735  matrix N[3][3];  // stores the projective coordinates of the points to which M is to be transformed
1736  intmat T[3][3];  // stores the unimodular affine transformation in projective form
1737  // add the second point of pg once again at the end
1738  pg=insert(pg,pg[2],size(pg));
1739  // if there is only one edge which has the maximal number of lattice points, then M should be:
1740  M=pg[max],1,pg[max+1],1,pg[max+2],1;
1741  // consider the 16 different cases which can occur:
1742  // Case 1:
1743  if (sbd==intvec(2,2,2))
1744  {
1745    N=0,1,1,1,2,1,2,0,1;
1746  }
1747  // Case 2:
1748  if (sbd==intvec(2,2,3))
1749  {
1750    N=2,0,1,0,0,1,1,2,1;
1751  }
1752  // Case 3:
1753  if (sbd==intvec(2,3,4))
1754  {
1755    // here the orientation of the Newton polygon is important !
1756    if (tboundary[max+1]==3)
1757    {
1758      N=3,0,1,0,0,1,0,2,1;
1759    }
1760    else
1761    {
1762      N=0,0,1,3,0,1,0,2,1;
1763    }
1764  }
1765  // Case 4:
1766  if (sbd==intvec(3,3,5))
1767  {
1768    N=4,0,1,0,0,1,0,2,1;
1769  }
1770  // Case 5:
1771  if (sbd==intvec(4,4,4))
1772  {
1773    N=3,0,1,0,0,1,0,3,1;
1774  }
1775  // Case 6+7:
1776  if (sbd==intvec(2,2,2,2))
1777  {
1778    // there are two different polygons which has four edges all of length 2,
1779    // but only one of them has two edges whose direction vectors form a matrix
1780    // of determinant 3
1781    A=pg[1]-pg[2],pg[3]-pg[2];
1782    while ((max<4) and (det(A)!=3))
1783    {
1784      max++;
1785      A=pg[max]-pg[max+1],pg[max+2]-pg[max+1];
1786    }
1787    // Case 6:
1788    if (det(A)==3)
1789    {
1790      M=pg[max],1,pg[max+1],1,pg[max+2],1;
1791      N=1,0,1,0,2,1,2,1,1;
1792    }
1793    // Case 7:
1794    else
1795    {
1796      N=2,1,1,1,0,1,0,1,1;
1797    }
1798  }
1799  // Case 8:
1800  if (sbd==intvec(2,2,2,3))
1801  {
1802    // the orientation of the polygon is important
1803    A=pg[max]-pg[max+1],pg[max+2]-pg[max+1];
1804    if (det(A)==2)
1805    {
1806      N=2,0,1,0,0,1,0,1,1;
1807    }
1808    else
1809    {
1810      N=0,0,1,2,0,1,1,2,1;
1811    }
1812  }
1813  // Case 9:
1814  if (sbd==intvec(2,2,3,3))
1815  {
1816    // if max==1, then the 5th entry in tboundary is the same as the first
1817    if (max==1)
1818    {
1819      max=5;
1820    }
1821    // if boundary=3,2,2,3 then set max=4
1822    if (tboundary[max+1]!=3)
1823    {
1824      max=4;
1825    }
1826    M=pg[max],1,pg[max+1],1,pg[max+2],1;
1827    // the orientation of the polygon matters
1828    A=pg[max-1]-pg[max],pg[max+1]-pg[max];   
1829    if (det(A)==4)
1830    {
1831      N=2,0,1,0,0,1,0,2,1;
1832    }
1833    else
1834    {
1835      N=0,2,1,0,0,1,2,0,1;
1836    }
1837  }
1838  // Case 10:
1839  if (sbd==intvec(2,2,3,4))
1840  {
1841    // the orientation of the polygon matters
1842    if (tboundary[max+1]==3)
1843    {
1844      N=3,0,1,0,0,1,0,2,1;
1845    }
1846    else
1847    {
1848      N=0,0,1,3,0,1,2,1,1;
1849    }
1850  }
1851  // Case 11:
1852  if (sbd==intvec(2,3,3,4))
1853  {
1854    N=3,0,1,0,0,1,0,2,1;
1855  }
1856  // Case 12:
1857  if (sbd==intvec(3,3,3,3))
1858  {
1859    N=2,0,1,0,0,1,0,2,1;
1860  }
1861  // Case 13:
1862  if (sbd==intvec(2,2,2,2,2))
1863  {
1864    // compute the angles of the polygon vertices
1865    intvec dt;
1866    for (i=1;i<=5;i++)
1867    {
1868      A=pg[i]-pg[i+1],pg[i+2]-pg[i+1];
1869      dt[i]=det(A);
1870    }
1871    dt[6]=dt[1];
1872    // find the vertex to be mapped to (0,1)
1873    max=1;
1874    while ((dt[max]!=2) or (dt[max+1]!=2))
1875    {
1876      max++;
1877    }   
1878    M=pg[max],1,pg[max+1],1,pg[max+2],1;
1879    N=0,1,1,1,2,1,2,1,1;
1880  }
1881  // Case 14:
1882  if (sbd==intvec(2,2,2,2,3))
1883  {
1884    N=2,0,1,0,0,1,0,1,1;
1885  }
1886  // Case 15:
1887  if (sbd==intvec(2,2,2,3,3))
1888  {
1889    // find the vertix to be mapped to (2,0)
1890    if (tboundary[max+1]!=3)
1891    {
1892      max=5;
1893      M=pg[max],1,pg[max+1],1,pg[max+2],1;
1894    }
1895    N=2,0,1,0,0,1,0,2,1;
1896  }
1897  // Case 16:
1898  if (sbd==intvec(2,2,2,2,2,2))
1899  {
1900    N=2,0,1,1,0,1,0,1,1;
1901  }
1902  // we have to transpose the matrices M and N
1903  M=transpose(M);
1904  N=transpose(N);
1905  // compute the unimodular affine transformation, which is of the form
1906  // A11 A12 | T1
1907  // A21 A22 | T2
1908  //  0   0  | 1
1909  T=matrixtointmat(N*inverse(M));
1910  // the upper-left 2x2-block is A
1911  A=T[1..2,1..2];
1912  // the upper-right 2x1-block is the translation vector
1913  trans=T[1,3],T[2,3];
1914  // transform now the lattice points of the polygon with respect to A and T
1915  list nf;
1916  for (i=1;i<=size(polygon);i++)
1917  {
1918    intmat V[2][1]=polygon[i];
1919    V=A*V;
1920    nf[i]=intvec(V[1,1]+trans[1],V[2,1]+trans[2]);
1921    kill V;
1922  }
1923  return(list(findOrientedBoundary(nf)[2],A,trans,nf));
1924}
1925example
1926{
1927   "EXAMPLE:";
1928   echo=2;
1929   ring r=0,(x,y),dp;
1930   // the Newton polygon of the following polynomial has precisely one interior point
1931   poly f=x22y11+x19y10+x17y9+x16y9+x12y7+x9y6+x7y5+x2y3;
1932   list polygon=newtonPolytopeLP(f);
1933   // its lattice points are
1934   polygon;
1935   // find its normal form
1936   list nf=ellipticNF(polygon);
1937   // the vertices of the normal form are
1938   nf[1];
1939   // it has been transformed by the unimodular affine transformation A*x+v
1940   // with matrix A
1941   nf[2];
1942   // and translation vector v
1943   nf[3];
1944   // the 3rd lattice point ...
1945   polygon[3];
1946   // ... has been transformed to
1947   nf[4][3];
1948}
1949
1950
1951proc ellipticNFDB (int n,list #)
1952"USAGE:  ellipticNFDB(n[,#]);   n int, # list
1953ASSUME:  n is an intger between 1 and 16
1954PURPOSE: this is a database storing the 16 normal forms of planar polygons with
1955         precisely one interior point up to unimodular affine transformations
1956         (see e.g. Bjorn Poonen, Fernando Rodriguez-Villegas: Lattice Polygons and
1957                   the number 12.  Amer. Math. Monthly  107  (2000),  no. 3, 238--250.)
1958RETURN:  list, L such that
1959               L[1] : list whose entries are the vertices of the nth normal form
1960               L[2] : list whose entries are all the lattice points of the nth normal form
1961               L[3] : only present if the optional parameter # is present, and then
1962                      it is a polynomial in the variables (x,y) whose Newton polygon
1963                      is the nth normal form
1964NOTE:    the optional parameter is only allowed if the basering has the variables x and y
1965EXAMPLE: example ellipticNFDB;   shows an example"
1966{
1967  if ((n<1) or (n>16))
1968  {
1969    ERROR("n is not between 1 and 16.");
1970  }
1971  if (size(#)>0)
1972  {
1973    if ((defined(x)==0) or (defined(y)==0))
1974    {
1975      ERROR("The variables x and y are not defined.");
1976    }
1977  }
1978  if ((defined(x)==0) or (defined(y)==0))
1979  {
1980    ring nfring=0,(x,y),dp;
1981  }
1982  // store the normal forms as polynomials
1983  list nf=x2+y+xy2,x2+x+1+xy2,x3+x2+x+1+y2+y,x4+x3+x2+x+1+y2+y+x2y,x3+x2+x+1+x2y+y+xy2+y2+y3,
1984    x2+x+x2y+y2,x2y+x+y+xy2,x2+x+1+y+xy2,x2+x+1+y+xy2+y2,x3+x2+x+1+x2y+y+y2,x3+x2+x+1+x2y+y+xy2+y2,
1985    x2+x+1+x2y+y+x2y2+xy2+y2,x+1+x2y+y+xy2,x2+x+1+x2y+y+xy2,x2+x+1+x2y+y+xy2+y2,x2+x+x2y+y+xy2+y2;
1986  list pg=newtonPolytopeLP(nf[n]);
1987  if (size(#)==0)
1988  {
1989    return(list(findOrientedBoundary(pg)[2],pg));
1990  }
1991  else
1992  {
1993    return(list(findOrientedBoundary(pg)[2],pg,nf[n]));
1994  }
1995}
1996example
1997{
1998   "EXAMPLE:";
1999   echo=2;
2000   list nf=ellipticNFDB(5);
2001   // the vertices of the 5th normal form are
2002   nf[1];
2003   // its lattice points are
2004   nf[2];
2005}
2006
2007/////////////////////////////////////////////////////////////////////////////////
2008/////////////////////////////////////////////////////////////////////////////////
2009/// AUXILARY PROCEDURES, WHICH ARE DECLARED STATIC
2010/////////////////////////////////////////////////////////////////////////////////
2011/////////////////////////////////////////////////////////////////////////////////
2012/// - scalarproduct
2013/// - intmatcoldelete
2014/// - intmatconcat
2015/// - sortlist
2016/// - minInList
2017/// - stringdelete
2018/// - abs
2019/// - commondenominator
2020/// - maxPosInIntvec
2021/// - maxPosInIntmat
2022/// - sortintvec
2023/// - matrixtointmat
2024/////////////////////////////////////////////////////////////////////////////////
2025
2026static proc scalarproduct (intvec w,intvec v)
2027"USAGE:      scalarproduct(w,v); w,v intvec
2028ASSUME:      w and v are integer vectors of the same length
2029RETURN:      int, the scalarproduct of v and w
2030NOTE:        the procedure is called by findOrientedBoundary"
2031{
2032  int sp;
2033  for (int i=1;i<=size(w);i++)
2034  {
2035    sp=sp+v[i]*w[i];
2036  }
2037  return(sp);
2038}
2039
2040static proc intmatcoldelete (intmat w,int i)
2041"USAGE:      intmatcoldelete(w,i); w intmat, i int
2042RETURN:      intmat, the integer matrix w with the ith comlumn deleted
2043NOTE:        the procedure is called by intmatsort and normalFan"
2044{
2045  if ((i<1) or (i>ncols(w)) or (ncols(w)==1))
2046  {
2047    return(w);
2048  }
2049  if (i==1)
2050  {
2051    intmat M[nrows(w)][ncols(w)-1]=w[1..nrows(w),2..ncols(w)];
2052    return(M);
2053  }
2054  if (i==ncols(w))
2055  {
2056    intmat M[nrows(w)][ncols(w)-1]=w[1..nrows(w),1..ncols(w)-1];
2057    return(M);
2058  }
2059  else
2060  {
2061    intmat M[nrows(w)][i-1]=w[1..nrows(w),1..i-1];
2062    intmat N[nrows(w)][ncols(w)-i]=w[1..nrows(w),i+1..ncols(w)];
2063    return(intmatconcat(M,N));
2064  }
2065}
2066
2067static proc intmatconcat (intmat M,intmat N)
2068"USAGE:      intmatconcat(M,N); M,N intmat
2069RETURN:      intmat, M and N concatenated
2070NOTE:        the procedure is called by intmatcoldelete and sortintmat"
2071{
2072  if (nrows(M)>=nrows(N))
2073  {
2074    int m=nrows(M);
2075   
2076  }
2077  else
2078  {
2079    int m=nrows(N);
2080  }
2081  intmat P[m][ncols(M)+ncols(N)];
2082  P[1..nrows(M),1..ncols(M)]=M[1..nrows(M),1..ncols(M)];
2083  P[1..nrows(N),ncols(M)+1..ncols(M)+ncols(N)]=N[1..nrows(N),1..ncols(N)];
2084  return(P);
2085}
2086
2087static proc sortlist (list v,int pos)
2088"USAGE:      sortlist(v,pos); v list, pos int
2089RETURN:      list, the list L ordered in an ascending way according to the pos-th entries
2090NOTE:        called by tropicalCurve"
2091{
2092  if(size(v)==1)
2093  {
2094    return(v);
2095  }
2096  list w=minInList(v,pos);
2097  v=delete(v,w[2]);
2098  v=sortlist(v,pos);
2099  v=list(w[1])+v;
2100  return(v);
2101}
2102
2103static proc minInList (list v,int pos)
2104"USAGE:      minInList(v,pos); v list, pos int
2105RETURN:      list, (v[i],i) such that v[i][pos] is minimal
2106NOTE:        called by sortlist"
2107{
2108  int min=v[1][pos];
2109  int minpos=1;
2110  for (int i=2;i<=size(v);i++)
2111  {
2112    if (v[i][pos]<min)
2113    {
2114      min=v[i][pos];
2115      minpos=i;
2116    }
2117  }
2118  return(list(v[minpos],minpos));
2119}
2120
2121static proc stringdelete (string w,int i)
2122"USAGE:      stringdelete(w,i); w string, i int
2123RETURN:      string, the string w with the ith component deleted
2124NOTE:        the procedure is called by texnumber and choosegfanvector"
2125{
2126  if ((i>size(w)) or (i<=0))
2127  {
2128    return(w);
2129  }
2130  if ((size(w)==1) and (i==1))
2131  {
2132    return("");
2133   
2134  }
2135  if (i==1)
2136  {
2137    return(w[2..size(w)]);
2138  }
2139  if (i==size(w))
2140  {
2141    return(w[1..size(w)-1]);
2142  }
2143  else
2144  {
2145    string erg=w[1..i-1],w[i+1..size(w)];
2146    return(erg);
2147  }
2148}
2149
2150static proc abs (def n)
2151"USAGE:      abs(n); n poly or int
2152RETURN:      poly or int, the absolute value of n"
2153{
2154  if (n>=0)
2155  {
2156    return(n);
2157  }
2158  else
2159  {
2160    return(-n);
2161  }
2162}
2163
2164static proc commondenominator (matrix M)
2165"USAGE:   commondenominator(M);  M matrix
2166ASSUME:   the base ring has characteristic zero
2167RETURN:   int, the lowest common multiple of the denominators of the leading coefficients
2168               of the entries in M
2169NOTE:        the procedure is called from polymakeToIntmat"
2170{
2171  int i,j;
2172  int kgV=1;
2173  // successively build the lowest common multiple of the denominators of the leading coefficients
2174  // of the entries in M
2175  for (i=1;i<=nrows(M);i++)
2176  {
2177    for (j=1;j<=ncols(M);j++)
2178    {
2179      kgV=lcm(kgV,int(denominator(leadcoef(M[i,j]))));
2180    }
2181  }
2182  return(kgV);
2183}
2184
2185static proc maxPosInIntvec (intvec v)
2186"USAGE:      maxPosInIntvec(v); v intvec
2187RETURN:      int, the first position of a maximal entry in v
2188NOTE:        called by sortintmat"
2189{
2190  int max=v[1];
2191  int maxpos=1;
2192  for (int i=2;i<=size(v);i++)
2193  {
2194    if (v[i]>max)
2195    {
2196      max=v[i];
2197      maxpos=i;
2198    }
2199  }
2200  return(maxpos);
2201}
2202
2203static proc maxPosInIntmat (intmat v)
2204"USAGE:      maxPosInIntmat(v); v intmat
2205ASSUME:      v has a unique maximal entry
2206RETURN:      intvec, the position (i,j) of the maximal entry in v
2207NOTE:        called by findOrientedBoundary"
2208{
2209  int max=v[1,1];
2210  intvec maxpos=1,1;
2211  int i,j;
2212  for (i=1;i<=nrows(v);i++)
2213  {
2214    for (j=1;j<=ncols(v);j++)
2215    {
2216      if (v[i,j]>max)
2217      {
2218        max=v[i,j];
2219        maxpos=i,j;
2220      }
2221    }
2222  }
2223  return(maxpos);
2224}
2225
2226static proc sortintvec (intvec w)
2227"USAGE:      sortintvec(v); v intvec
2228RETURN:      intvec, the entries of v are ordered in an ascending way
2229NOTE:        called from ellipticNF"
2230{
2231  int j,k,stop;
2232  intvec v=w[1];
2233  for (j=2;j<=size(w);j++)
2234  {
2235    k=1;
2236    stop=0;
2237    while ((k<=size(v)) and (stop==0))
2238    {
2239      if (v[k]<w[j])
2240      {
2241        k++;
2242      }
2243      else
2244      {
2245        stop=1;
2246      }
2247    }
2248    if (k==size(v)+1)
2249    {
2250      v=v,w[j];
2251    }
2252    else
2253    {
2254      if (k==1)
2255      {
2256        v=w[j],v;
2257      }
2258      else
2259      {
2260        v=v[1..k-1],w[j],v[k..size(v)];
2261      }
2262    }
2263  }
2264  return(v);
2265}
2266
2267static proc sortlistbyintvec (list L,intvec w)
2268"USAGE:      sortlistbyintvec(L,w); L list, w intvec
2269RETURN:      list, the entries of L are ordered such that the corresponding reordering of
2270                   w would order w in an ascending way
2271NOTE:        called from ellipticNF"
2272{
2273  int j,k,stop;
2274  intvec v=w[1];
2275  list LL=L[1];
2276  for (j=2;j<=size(w);j++)
2277  {
2278    k=1;
2279    stop=0;
2280    while ((k<=size(v)) and (stop==0))
2281    {
2282      if (v[k]<w[j])
2283      {
2284        k++;
2285      }
2286      else
2287      {
2288        stop=1;
2289      }
2290    }
2291    if (k==size(v)+1)
2292    {
2293      v=v,w[j];
2294      LL=insert(LL,L[j],size(LL));
2295    }
2296    else
2297    {
2298      if (k==1)
2299      {
2300        v=w[j],v;
2301        LL=insert(LL,L[j]);
2302      }
2303      else
2304      {
2305        v=v[1..k-1],w[j],v[k..size(v)];
2306        LL=insert(LL,L[j],k-1);
2307      }
2308    }
2309  }
2310  return(LL);
2311}
2312
2313static proc matrixtointmat (matrix MM)
2314"USAGE:      matrixtointmat(v); MM matrix
2315ASSUME:      MM is a matrix with only integers as entries
2316RETURN:      intmat, the matrix MM has been transformed to type intmat
2317NOTE:        called from ellipticNF"
2318{
2319  intmat M[nrows(MM)][ncols(MM)]=M;
2320  int i,j;
2321  for (i=1;i<=nrows(M);i++)
2322  {
2323    for (j=1;j<=ncols(M);j++)
2324    {
2325      execute("M["+string(i)+","+string(j)+"]="+string(MM[i,j])+";");
2326    }
2327  }
2328  return(M);
2329}
2330
2331//////////////////////////////////////////////////////////////////////////////
2332
2333static proc polygonToCoordinates (list points)
2334"USAGE:      polygonToCoordinates(points);   points list
2335ASSUME:      points is a list of integer vectors each of size two describing the
2336             marked points of a convex lattice polygon like the output of polygonDB
2337RETURN:      list, the first entry is a string representing the coordinates corresponding
2338                   to the latticpoints seperated by commata
2339                   the second entry is a list where the ith entry is a string representing
2340                   the coordinate of corresponding to the ith lattice point
2341                   the third entry is the latex format of the first entry
2342NOTE:        the procedure is called by fan"
2343{
2344  string coord;
2345  list coords;
2346  string latex;
2347  for (int i=1;i<=size(points);i++)
2348  {
2349    coords[i]="u"+string(points[i][1])+string(points[i][2]);
2350    coord=coord+coords[i]+",";
2351    latex=latex+"u_{"+string(points[i][1])+string(points[i][2])+"},";
2352  }
2353  coord=coord[1,size(coord)-1];
2354  latex=latex[1,size(latex)-1];
2355  return(list(coord,coords,latex));
2356}
2357
2358
2359/*
2360proc ADeterminant (list polygon,list #)
2361{
2362  list triangs=triangulations(polygon);
2363  list sppg=splitPolygon(polygon);
2364  list etavectors;
2365  int i,j;
2366  int stop;
2367  for (i=1;i<=size(triangs);i++)
2368  {
2369    etavectors[i]=eta(triangs[i],sppg);
2370  }
2371  size(etavectors);
2372 
2373  for (i=size(etavectors);i>=2;i--)
2374  {
2375    stop=0;
2376    for (j=1;(j<i) and (stop==0);j++)
2377    {
2378      if (etavectors[i]==etavectors[j])
2379      {
2380        etavectors=delete(etavectors,i);
2381        stop=1;
2382      }
2383    }
2384  }
2385  size(etavectors);
2386  if (size(#)>0)
2387  {
2388    execute("ring ADring=(0,a(1.."+string(size(etavectors))+")),("+polygonToCoordinates(polygon)[1]+"),lp;");
2389    list terme;
2390    poly ad,term;
2391    matrix XE[1][1];
2392    for (i=1;i<=size(etavectors);i++)
2393    {
2394      term=1;
2395      for (j=1;j<=nvars(basering);j++)
2396      {
2397        term=term*var(j)^etavectors[i][j];
2398      }
2399      terme[i]=term;
2400      ad=ad+a(i)*term;
2401    }
2402    matrix M[size(etavectors)][nvars(basering)];
2403    for (i=1;i<=size(etavectors);i++)
2404    {
2405    }
2406    return(list(etavectors,string(ad)));
2407   
2408   
2409  }
2410 
2411  return(etavectors);
2412}
2413
2414proc adsub ()
2415{
2416  ring r=0,(x,y,u00,u10,u20,u01,u11,u02,a(1..5)),dp;
2417  poly f1=(3x-y+1)*(2x+y+1);
2418  poly f2=(7x+2y-1)*(x+y);
2419  poly f3=(x-y-2)*(x+y+3);
2420  poly f4=(17x-11y+3)*(x+7y-2);
2421  poly f5=(x+2y-7)*(3x+3y-1);
2422  poly f6=(2x+12y-17)*(33x-3y-1);
2423  matrix M1=coeffs(f1,ideal(1,x,x2,y,xy,y2));
2424  matrix M2=coeffs(f2,ideal(1,x,x2,y,xy,y2));
2425  matrix M3=coeffs(f3,ideal(1,x,x2,y,xy,y2));
2426  matrix M4=coeffs(f4,ideal(1,x,x2,y,xy,y2));
2427  matrix M5=coeffs(f5,ideal(1,x,x2,y,xy,y2));
2428  matrix M6=coeffs(f6,ideal(1,x,x2,y,xy,y2));
2429  poly f=(a(5))*u00*u20*u02+(a(3))*u00*u11^2+(a(4))*u10^2*u02+(a(2))*u10*u01*u11+(a(1))*u20*u01^2;
2430  poly g1=substitute(f,u00,M1[1,1],u10,M1[2,1],u20,M1[3,1],u01,M1[4,1],u11,M1[5,1],u02,M1[6,1]);
2431  poly g2=substitute(f,u00,M2[1,1],u10,M2[2,1],u20,M2[3,1],u01,M2[4,1],u11,M2[5,1],u02,M2[6,1]);
2432  poly g3=substitute(f,u00,M3[1,1],u10,M3[2,1],u20,M3[3,1],u01,M3[4,1],u11,M3[5,1],u02,M3[6,1]);
2433  poly g4=substitute(f,u00,M4[1,1],u10,M4[2,1],u20,M4[3,1],u01,M4[4,1],u11,M4[5,1],u02,M4[6,1]);
2434  poly g5=substitute(f,u00,M5[1,1],u10,M5[2,1],u20,M5[3,1],u01,M5[4,1],u11,M5[5,1],u02,M5[6,1]);
2435  poly g6=substitute(f,u00,M6[1,1],u10,M6[2,1],u20,M6[3,1],u01,M6[4,1],u11,M6[5,1],u02,M6[6,1]);
2436  ideal i=g1,g2,g3,g4,g5,g6;
2437  option(redSB);
2438  ideal j=std(i);
2439  poly ff=substitute(f,a(5),4,a(4),-1,a(3),-1,a(2),1,a(1),-1);
2440  return(string(ff));
2441}
2442
2443*/
Note: See TracBrowser for help on using the repository browser.