source: git/Singular/LIB/alexpoly.lib @ 0be039

fieker-DuValspielwiese
Last change on this file since 0be039 was a8a6b8, checked in by Hans Schoenemann <hannes@…>, 6 years ago
chg: version/date of libs, p1
  • Property mode set to 100644
File size: 94.9 KB
Line 
1////
2version="version alexpoly.lib 4.1.1.0 Dec_2017 "; // $Id$
3category="Singularities";
4info="
5LIBRARY:  alexpoly.lib   Resolution Graph and Alexander Polynomial
6AUTHOR:   Fernando Hernando Carrillo, hernando@agt.uva.es
7          Thomas Keilen,   keilen@mathematik.uni-kl.de
8
9OVERVIEW:
10 A library for computing the resolution graph of a plane curve singularity f,
11 the total multiplicities of the total transforms of the branches of f along
12 the exceptional divisors of a minimal good resolution of f, the Alexander
13 polynomial of f, and the zeta function of its monodromy operator.
14
15PROCEDURES:
16 resolutiongraph(f);        resolution graph f
17 totalmultiplicities(f);    resolution graph, total multiplicities and strict multiplicities of f
18 alexanderpolynomial(f);    Alexander polynomial of f
19 semigroup(f);              calculates generators for the semigroup of f
20 proximitymatrix(f);        calculates the proximity matrix of f
21 multseq2charexp(v);        converts multiplicity sequence to characteristic exponents
22 charexp2multseq(v);        converts characteristic exponents to multiplicity sequence
23 charexp2generators(v);     converts characteristic exponents to generators of the semigroup
24 charexp2inter(c,e);        converts contact matrix and charact. exp. to intersection matrix
25 charexp2conductor(v);      converts characteristic exponents to conductor
26 charexp2poly(v,a);         calculates a polynomial f with characteristic exponents v
27 tau_es2(f);                equisingular Tjurina number of f
28
29KEYWORDS: Hamburger-Noether expansion; Puiseux expansion; curve singularities;
30          topological invariants; Alexander polynomial; resolution graph;
31          total multiplicities; equisingular Tjurina number
32";
33
34///////////////////////////////////////////////////////////////////////////////////////////
35LIB "hnoether.lib";
36///////////////////////////////////////////////////////////////////////////////////////////
37
38proc resolutiongraph (def INPUT,list #)
39"USAGE:  resolutiongraph(INPUT); INPUT poly or list
40ASSUME:  INPUT is either a REDUCED bivariate polynomial defining a plane curve singularity,
41         or the output of @code{hnexpansion(f[,\"ess\"])}, or the list @code{hne} in
42         the ring created by @code{hnexpansion(f[,\"ess\"])}, or the output of
43         @code{develop(f)} resp. of @code{extdevelop(f,n)}, or a list containing
44         the contact matrix and a list of integer vectors with the characteristic exponents
45         of the branches of a plane curve singularity, or an integer vector containing the
46         characteristic exponents of an irreducible plane curve singularity.
47RETURN:  intmat, the incidence matrix of the resolution graph of the plane curve
48         defined by INPUT, where the entries on the diagonal are the weights of the
49         vertices of the graph and a negative entry corresponds to the strict transform
50         of a branch of the curve.
51NOTE:    In case the Hamburger-Noether expansion of the curve f is needed
52         for other purposes as well it is better to calculate this first
53         with the aid of @code{hnexpansion} and use it as input instead of
54         the polynomial itself.
55         @*
56         If you are not sure whether the INPUT polynomial is reduced or not, use
57         @code{squarefree(INPUT)} as input instead.
58SEE ALSO: develop, hnexpansion, totalmultiplicities, alexanderpolynomial
59EXAMPLE: example resolutiongraph;  shows an example
60"
61{
62  return(totalmultiplicities(INPUT,#)[1]);
63}
64example
65{
66  "EXAMPLE:";
67  echo=2;
68  ring r=0,(x,y),ls;
69  poly f1=(y2-x3)^2-4x5y-x7;
70  poly f2=y2-x3;
71  poly f3=y3-x2;
72  resolutiongraph(f1*f2*f3);
73}
74
75proc totalmultiplicities (def INPUT, list #)
76"USAGE:  totalmultiplicities(INPUT); INPUT poly or list
77ASSUME:  INPUT is either a REDUCED bivariate polynomial defining a plane curve singularity,
78         or the output of @code{hnexpansion(f[,\"ess\"])}, or the list @code{hne} in
79         the ring created by @code{hnexpansion(f[,\"ess\"])}, or the output of
80         @code{develop(f)} resp. of @code{extdevelop(f,n)}, or a list containing
81         the contact matrix and a list of integer vectors with the characteristic exponents
82         of the branches of a plane curve singularity, or an integer vector containing the
83         characteristic exponents of an irreducible plane curve singularity.
84RETURN:  list @code{L} of three integer matrices. @code{L[1]} is the incidence matrix of
85         the resolution graph of the plane curve defined by INPUT, where the entries on the
86         diagonal are the weights of the vertices of the graph and a negative entry corresponds
87         to the strict transform of a branch of the curve. @code{L[2]} is an integer matrix,
88         which has for each vertex in the graph a row and for each branch of the curve a column.
89         The entry in position [i,j] contains the total multiplicity of the j-th branch (i.e. the
90         branch with weight -j in @code{L[1]}) along the exceptional divisor corresponding
91         to the i-th row in @code{L[1]}. In particular, the i-th row contains
92         the total multiplicities of the branches of the plane curve (defined by INPUT) along
93         the exceptional divisor which corresponds to the i-th row in the incidence matrix
94         @code{L[1]}. @code{L[3]} is an integer matrix which contains the (strict) multiplicities
95         of the branches of the curve along the exceptional divisors in the same way as @code{L[2]}
96         contains the total multiplicities.
97NOTE:    The total multiplicty of a branch along an exceptional divisor is the multiplicity
98         with which this exceptional divisor occurs in the total transform of this branch
99         under the resolution corresponding to the resolution graph.
100         @*
101         In case the Hamburger-Noether expansion of the curve f is needed
102         for other purposes as well it is better to calculate this first
103         with the aid of @code{hnexpansion} and use it as input instead of
104         the polynomial itself.
105         @*
106         If you are not sure whether the INPUT polynomial is reduced or not, use
107         @code{squarefree(INPUT)} as input instead.
108SEE ALSO: develop, hnexpansion, alexanderpolynomial, resolutiongraph
109EXAMPLE: example totalmultiplicities;  shows an example
110"
111{
112  ///////////////////////////////////////////////////////////////////////////////////////////////
113  /// The algorithm described in [JP] DeJong, Pfister, Local Analytic Geometry, Vieweg 2000,
114  /// is used for the implementation -- the missing case is included by appropriate sorting.
115  ///////////////////////////////////////////////////////////////////////////////////////////////
116  /// If # is empty, then an additional sorting of the branches will be made, so that
117  /// the branches can be split with split_graph in order to get the graphs of the curves
118  /// separated on the first exceptional divisor. Otherwise split_graph should not be applied!
119  ///////////////////////////////////////////////////////////////////////////////////////////////
120  /// If #[1]="tau", then totalmultiplicities is called for the use in tau_es2 - thus it returns
121  /// the prolonged resolutiongraphs of the branches, their multiplicity sequences and their
122  /// contact matrix - sorted appropriately.
123  ///////////////////////////////////////////////////////////////////////////////////////////////
124  int i,j,s,e,ii;
125  intmat helpmati,helpmatii;
126  intvec helpvec;
127  int inputispoly=0;
128  /////////////////////////////////////////////////////////////////////////////////
129  // Decide, which kind of input we have, and define the contact matrix
130  /////////////////////////////////////////////////////////////////////////////////
131  // Input: a polynomial defining a plane curve singularity.
132  //////////////////////////////////////////////////////////////////////////////
133  if (typeof(INPUT)=="poly")
134  {
135    /*
136    poly f=squarefree(INPUT);
137    if ( deg(f)!=deg(INPUT) )
138    {
139      dbprint(printlevel-voice+4,"// input polynomial was not reduced");
140      dbprint(printlevel-voice+4,"// we continue with its reduction");
141    }
142    list I@N@V=invariants(f);
143    */
144    list I@N@V=invariants(INPUT);
145    inputispoly=1;
146  }
147  else
148  {
149    ///////////////////////////////////////////////////////////////////////////////////
150    // Input: the vector of characteristic exponents of an irreducible plane curve
151    ///////////////////////////////////////////////////////////////////////////////////
152    if (typeof(INPUT)=="intvec")
153    {
154      list charexp;
155      charexp[1]=INPUT;
156      intmat contact[1][1]=0;
157    }
158    else
159    {
160      if (typeof(INPUT)=="list")
161      {
162        /////////////////////////////////////////////////////////////////////////////////
163        // Input: intersection-matrix and characteristic exponents.
164        //////////////////////////////////////////////////////////////////////////////
165        if (typeof(INPUT[1])=="intmat")
166        {
167          intmat contact=INPUT[1];
168          list charexp=INPUT[2];
169        }
170        else
171        {
172          /////////////////////////////////////////////////////////////////////////////////
173          // Input: output of hnexpansion or hne in the ring created by hnexpansion
174          //////////////////////////////////////////////////////////////////////////////
175          if ((typeof(INPUT[1])=="ring") or (typeof(INPUT[1])=="list"))
176          {
177            list I@N@V=invariants(INPUT);
178          }
179          else
180          {
181            ////////////////////////////////////////////////////////////////////////////////////
182            // Input: output of reddevelop or extdevelop -- irreducible plane curve singularity
183            ////////////////////////////////////////////////////////////////////////////////////
184            if (typeof(INPUT[1])=="matrix")
185            {
186              list charexp=invariants(INPUT)[1];
187              intmat contact[1][1]=0;
188            }
189            else
190            {
191              ERROR("The input is invalid!");
192            }
193          }
194        }
195      }
196      else
197      {
198        ERROR("The input is invalid!");
199      }
200    }
201  }
202  ///////////////////////////////////////////////////////////////////////////////////////////////////
203  // If the input was a polynomial or a HN-Expansion, then calculate the contact matrix and char.exponents.
204  ///////////////////////////////////////////////////////////////////////////////////////////////////
205  if (defined(I@N@V))
206  {
207    intmat contact=I@N@V[size(I@N@V)][1];   // contact numbers
208    list charexp;                       // characteristic exponents
209    for (i=1;i<=size(I@N@V)-1;i++)
210    {
211      charexp[i]=I@N@V[i][1];
212    }
213  }
214  //////////////////////////////////////////////////////////////////////////////
215  // Find the maximal contact numbers of the branches
216  //////////////////////////////////////////////////////////////////////////////
217  int r=ncols(contact);   // number of branches
218  intvec maxcontact;      // maximal contactnumber of branch i with other branches
219  for (i=1;i<=r;i++)
220  {
221    maxcontact[i]=max_in_intvec(intvec(contact[i,1..r]));
222  }
223  ///////////////////////////////////////////////////////////////////////////////
224  // Define the graphs of the branches and prolong them if necessary.
225  ///////////////////////////////////////////////////////////////////////////////
226  intmat gr,gr_red,grp;      // a subgraph, a reduced subgraph, a prolonged subgraph
227  int omega;              // point of highest weight in subgraph
228  list graphs;            // contains the subgraphs of the C_i
229  list totmult;           // contains the total multiplicities of the subgraphs
230  list multipl;           // contains the multiplicities of the subgraphs
231  list gr_tm;             // takes a single subgraph and tot.mult.
232  intvec tm,mt;           // total multiplicities and multiplicities
233  for (i=1;i<=r;i++)
234  {
235    gr_tm=irred_resgraph_totmult(charexp[i]); // graph, total multipl. and multipl. of the ith branch
236    gr=gr_tm[1];  // the graph of the ith branch
237    tm=gr_tm[2];  // the total multiplicities of the ith branch
238    mt=gr_tm[3];  // the multiplicities of the ith branch
239    omega=nrows(gr)-1;  // maximal weight in the graph of the ith branch
240    // If the maximal contact of the ith branch with some other branch is larger
241    // than the maximal weight omega, then the graph has to be polonged.
242    if (omega<maxcontact[i])
243    {
244      grp=intmat(intvec(0),maxcontact[i]+1,maxcontact[i]+1);
245      // save the graph without the point of the strict transform
246      if (omega>=1) // otherwise the graph consists only of the strict transform
247      {
248        grp[1..omega,1..omega]=gr[1..omega,1..omega];
249      }
250      // add the points of multiplicity 1 up to weight maxcontact[i] and the strict transform
251      // and connect them
252      for (j=omega+1;j<=maxcontact[i]+1;j++)
253      {
254        // adding the vertex to the graph and adding the total multiplicities
255        if (j<=maxcontact[i])
256        {
257          grp[j,j]=j;
258          if (j>1)
259          {
260            tm[j]=tm[j-1]+1;
261            mt[j]=1;
262          }
263          else  // then there is no previous point in the graph
264          {
265            tm[j]=1;
266            mt[j]=1;
267          }
268        }
269        // connecting the vertex with the previous part of the graph
270        if (j>1)  // otherwise there is nothing to connect to
271        {
272          grp[j-1,j]=1;
273          grp[j,j-1]=1;
274        }
275      }
276      gr=grp;  // replace the subgraph by the prolonged subgraph
277    }
278    gr[nrows(gr),ncols(gr)]=-i;  // give the strict transform in the ith branch weight -i
279    graphs[i]=gr;
280    totmult[i]=tm;
281    multipl[i]=mt;
282  }
283  ///////////////////////////////////////////////////////////////////////////////
284  // Check, if the procedure is called from inside tau_es2.
285  int check_tau;
286  if (size(#)==1)
287  {
288    if (#[1]=="tau")
289    {
290      check_tau=1;
291    }
292  }
293  /////////////////////////////////////////////////////////////////////////////////
294  // The procedure tau_es2 expects the branches to be ordered according to their
295  // contact during the resolution process.
296  /////////////////////////////////////////////////////////////////////////////////
297  if ((size(#)==0) or (check_tau==1))
298  {
299    list SORT;
300    for (i=1;i<=ncols(contact)-2;i++)
301    {
302      SORT=sort_branches(contact,graphs,totmult,multipl,i,ncols(contact));
303      contact=SORT[1];
304      graphs=SORT[2];
305      totmult=SORT[3];
306      multipl=SORT[4];
307    }
308  }
309  ///////////////////////////////////////////////////////////////////////////////////
310  /// If the procedure is called from inside tau_es2, the output will be the prolonged
311  /// resolutiongraphs of the branches, their multiplicity sequences and their contact matrix.
312  if (check_tau==1)
313  {
314    return(list(graphs,multipl,contact));
315  }
316  /////////////////////////////////////////////////////////////////////////////////////
317  // Sort the branches in such a way, that in the blowing up procedure whenever two branches
318  // C_i and C_j have contact k (i.e. after k steps they are separated) and one of the following
319  // situations occurs:
320  // A) some exceptional divisor E_l (l<k) still intersects C_i after k steps of blowing up
321  //    and no such E_l intersects C_j
322  // OR
323  // B) some exceptional divisor E_l (l<k-1) still intersects C_i after k steps of blowing up
324  //    and another one (necessarily E_k-1) intersects C_j,
325  // THEN: i<j!
326  /////////////////////////////////////////////////////////////////////////////////////////
327  // This means in the algorithm for glueing graphs together described in [JP] p.217-19
328  // the Case 3 never occurs -- and Case 1 only occurs, if it is unavoidable, that is when
329  // C_1 there meets an E_l with l<k.
330  // (Otherwise we say that (C_i,C_j) has "bad contact".)
331  ////////////////////////////////////////////////////////////////////////////////////////
332  // We can detect this by looking at the graphs of C_i and C_j. If E_l stays together with
333  // C_i and not with C_j in the k-th step of blowing up, then in the graph of C_i
334  // k and l are NOT connected, while in the graph of C_j they are!
335  //////////////////////////////////////////////////////////////////////////////////////////
336  // Note also, that for a fixed pair (i,j) this situation can only occur for ONE l (in Case A: l<k
337  // and possibly l=k-1;  in Case B: l<k-1).
338  //////////////////////////////////////////////////////////////////////////////////////////
339  // Our algorithm now works as follows. Start with i=1 and j=2.
340  // While (i<r=number of branches) do as follows: Check C_i with C_j.
341  // If a bad contact (C_i,C_j) occurs, then MOVE C_j to the position of C_i (and move all C_t
342  // with t>=i, t!=j  one position further). Else do nothing particular.
343  // Then, if j<r set j=j+1. Else set j=i+2 and i=i+1.  End of While.
344  // To see that this works we note that if (C_i,C_j) has bad contact for some j>i, then
345  // (C_j,C_t) does NOT have bad contact for t=i+1,...,j-1. For this we consider the 3 cases:
346  // 1)  contact(C_t,C_j)=contact(C_i,C_j)=k:  E_l stays with C_j in k-th step and C_t and C_j
347  //                                           separate there, so (C_t,C_j) has bad contact
348  //                                           and hence (C_j,C_t) does NOT have bad contact
349  // 2)  contact(C_t,C_j)>contact(C_i,C_j)=k:  CANNOT HAPPEN - C_i had no bad contact with C_t,
350  //                                           hence E_l did not stay with C_t in the k-th step;
351  //                                           however, E_l stays with C_j there, so C_t and C_j
352  //                                           cannot have a contact higher than k
353  // 3)  contact(C_t,C_j)<contact(C_i,C_j)=k:  when C_t and C_j separate, C_j and C_i are still
354  //                                           together; and since (C_i,C_t) did not have bad
355  //                                           contact also (C_j,C_t) cannot have bad contact.
356  // This ensures that when we do the moving of the graphs, we do NOT create any new bad contacts.
357  //////////////////////////////////////////////////////////////////////////////
358  i=1;
359  j=2;
360  intvec connections_i,connections_j;
361  int n_i,n_j;
362  int bad_contact;
363  list newpos;  // when reordering the branches, here we save the new order of the old branches
364  for (ii=1;ii<=r;ii++)
365  {
366    newpos[ii]=ii;
367  }
368  while (i<r)
369  {
370    // Test graphs[i] with graphs[j] for bad contact.
371    connections_i=find_lower_connection_points(graphs[i],contact[i,j]);
372    if (connections_i[1]==0) // no connection point of lower weight there
373    {
374      n_i=0;
375    }
376    else
377    {
378      n_i=size(connections_i);
379    }
380    connections_j=find_lower_connection_points(graphs[j],contact[i,j]);
381    if (connections_j[1]==0) // no connection point of lower weight there
382    {
383      n_j=0;
384    }
385    else
386    {
387      n_j=size(connections_j);
388    }
389    bad_contact=0;
390    ii=1;
391    // The points of weight k=contact(C_i,C_j) in C_i and C_j are connectd to n_i respectively
392    // n_j points of weight less than k, where n_i and n_j might take values among 0, 1 and 2.
393    // n_j=2:        Then E_k is intersected by E_k-1 and E_l (l<k-1) in the k-th step, however
394    //               C_j does not stay with anyone of those, so (C_i,C_j) does not have bad contact.
395    // n_i=0:        Then C_i stays with E_k-1 and there is no E_l with l<k-1 in the k-th step,
396    //               hence (C_i,C_j) does not have bad contact.
397    // n_i=1, n_j=0: Analogously, then C_j stays with E_k-1 and there is no E_l (l<k-1). This means
398    //               (C_i,C_j) has bad contact.
399    // n_i=1, n_j=1: EITHER there is no E_l (l<k-1) and C_i and C_j both separate from E_k-1
400    //               in the k-th step of blowing up (hence (C_i,C_j) does not have bad contact).
401    //               OR there is an E_l (l<k-1) with which one stays and the other one stays
402    //               with E_k-1 (bad contact, if E_l stays with C_j; good contact otherwise).
403    // n_i=2,        E_k is intersected by E_k-1 and E_l in the k-th step and C_i does not
404    //               stay together with any of those.
405    //        n_j=0: This CANNOT occur, since then C_j would have to stay together with E_l
406    //               and E_k-1, which is impossible.
407    //        n_j=1: Then C_j stays together with either E_l or with E_k-1, however both cases
408    //               imply that (C_i,C_j) has bad contact
409    // ALTERNATIVE CONSIDERATION FOR DISTINGUISHING THE CASES:
410    // n_i<n_j   : C_i stays with "more" E's than C_j does (only one is possible of course!),
411    //             hence (C_i,C_j) does not have bad contact.
412    // n_i>n_j   : C_i stays with "less" E's than C_j does (i.e. with none) hence (C_i,C_j) has bad contact.
413    // n_i=n_j=0 : Not possible, since then both would stay with E_k-1.
414    // n_i=n_j=2 : Both separate from E_k-1 as well as from some E_l (l<k) - hence NO bad contact.
415    // n_i=n_j=1 : One stays with E_k-1 and one with E_l (l<k). Bad contact, if C_j stays with E_l,
416    //             i.e. if in the graph of C_i the point k is connected to l, and no bad contact otherwise.
417    if ((n_i>n_j) or ((n_i==1) and (n_j==1) and (connections_i[1]<contact[i,j]-1)))
418    {
419      bad_contact=1;
420      // Move the graph (etc.) of C_j into the position i.
421      newpos=insert(newpos,newpos[j],i-1);
422      newpos=delete(newpos,j+1);
423      // BE AWARE: after this reordering the graphs do not have the correct weight for the
424      //           strict transform any more; this will be adjusted further down
425      graphs=insert(graphs,graphs[j],i-1);
426      graphs=delete(graphs,j+1);
427      totmult=insert(totmult,totmult[j],i-1);
428      totmult=delete(totmult,j+1);
429      multipl=insert(multipl,multipl[j],i-1);
430      multipl=delete(multipl,j+1);
431      contact=move_row_col(contact,i,j);
432    }
433    if (j<r)  // There are still some C_j against which C_i has to be tested.
434    {
435      j++;
436    }
437    else      // Now C_i has been tested against all C_j, and we may continue with C_i+1.
438    {
439      j=i+2;
440      i=i+1;
441    }
442  }
443  // Here we adjust the weights of the strict transforms in the graphs!!!
444  for (i=1;i<=size(graphs);i++)
445  {
446    graphs[i][nrows(graphs[i]),ncols(graphs[i])]=-i;
447  }
448  /////////////////////////////////////////////////////////////////////////////////////
449  // Glue the graphs together.
450  //////////////////////////////////////////////////////////////////////////////
451  ///////////////////////////////////////////////////////////////////////////////////
452  intmat rgraph=graphs[1];                 // keeps the resolution graph
453  intmat rtm=intmat(totmult[1],nrows(rgraph),1); // keeps the tot.mult. at the vertices of the graph as rows
454  intmat rmt=intmat(multipl[1],nrows(rgraph),1); // keeps the mult. at the vertices of the graph as rows
455  intvec stricttransforms=0,ncols(rgraph);   // keeps the position of the ith strict
456                                             // transform in rgraph at position i+1 !!!
457  intvec k,kp,p,q,o;   // highest contact numbers, num. of branch with hgt contact, separation points
458  int maxc,maxcp;
459  for (i=2;i<=r;i++)
460  {
461    //////////////////////////////////////////////////////////////////////////////////
462    // Find j<i minimal s.t. contact[i,j] is maximal.
463    maxcp=i;
464    for (j=1;j<i;j++)
465    {
466      if (contact[i,j]>contact[i,maxcp]){maxcp=j;}
467    }
468    kp[i]=maxcp;            // the j such that C_i has its maximal contact to C_j
469    k[i]=contact[i,maxcp];  // the maximal contact of C_i with C_1,...,C_i-1
470    ///////////////////////////////////////////////////////////////////////////////////
471    // Find in the graph of C_1,...,C_i-1 the points p of wgt k and q of wgt k-1
472    // connected to C_maxcp.
473    // Since non of C_j for j<maxcp has contact k with C_i, the point p lies in
474    // the remaining part of the graph of C_maxcp.
475    s=rgraph[stricttransforms[maxcp]+1,stricttransforms[maxcp]+1];
476    p[i]=stricttransforms[maxcp]+1+k[i]-s; // pt. to which reduced subgraph of C_i is glued
477    // If s<k[i], then q also lies in this part, otherwise it lies in the remaining part
478    // of the graph of the C_j to which C_maxcp is connected, i.e. j=kp[maxcp], since
479    // the contact of C_i and of C_maxcp to this C_j is strictly less than k.
480    // If s=k[i]=1, then p=1 and there is no q! We may thus set q=0.
481    if ((s<k[i]) or ((s==k[i]) and (s==1)))  // i.e. q is on the same subgraph as p, or q does not exist
482    {
483      q[i]=p[i]-1;
484    }
485    else               // i.e. q is on the subgraph to which the subgraph of p has been glued
486    {
487      s=rgraph[stricttransforms[kp[maxcp]]+1,stricttransforms[kp[maxcp]]+1];
488      q[i]=stricttransforms[kp[maxcp]]+k[i]-s;
489    }
490    //////////////////////////////////////////////////////////////////////////////////////
491    // Reduce the graph of C_i and add it to the graph of C_1,...,C_i-1.
492    gr=graphs[i];
493    s=nrows(rgraph);
494    // Delete in the graph of C_i everything of weight <=k.
495    gr_red=intmat(intvec(gr[k[i]+1..nrows(gr),k[i]+1..ncols(gr)]),nrows(gr)-k[i],ncols(gr)-k[i]);
496    // Add this part to the graph of C_1,...,C_i-1.
497    rgraph=addmat(rgraph,gr_red);
498    /////////////////////////////////////////////////////////////////////////////////////
499    // Connect the two parts of the graph.
500    /////////////////////////////////////////////////////////////////////////////////////
501    // Connect the points connected to the point of wgt k in the graph of C_i to p[i].
502    for (j=k[i]+1;j<=ncols(gr);j++)
503    {
504      if(gr[k[i],j]==1)
505      {
506        rgraph[s+j-k[i],p[i]]=1;
507        rgraph[p[i],s+j-k[i]]=1;
508      }
509    }
510    // If pt. of wgt k is not connected to pt of wgt k-1 in graph of C_i, then points
511    // connected to the one of wgt k-1 have to be connected to q[i].
512    if (k[i]>1)
513    {
514      if (gr[k[i],k[i]-1]!=1)
515      {
516        for (j=k[i]+1;j<=ncols(gr);j++)
517        {
518          if(gr[k[i]-1,j]==1)
519          {
520            rgraph[s+j-k[i],q[i]]=1;
521            rgraph[q[i],s+j-k[i]]=1;
522          }
523        }
524        // Cut the connection from p[i] to q[i].
525        rgraph[p[i],q[i]]=0;
526        rgraph[q[i],p[i]]=0;
527      }
528    }
529    stricttransforms[i+1]=ncols(rgraph);
530    ////////////////////////////////////////////////////////////////////////////////
531    // Adjust the total multiplicities
532    ////////////////////////////////////////////////////////////////////////////////
533    // Add the total multiplicities for the added subgraph to rtm
534    tm=totmult[i];
535    mt=multipl[i];
536    if (k[i]<size(tm)) // if the reduced subgraph of C_i has more than one point
537    {
538      rtm=addmat(rtm,intmat(intvec(tm[k[i]+1..size(tm)]),nrows(gr_red),1));
539      rmt=addmat(rmt,intmat(intvec(mt[k[i]+1..size(mt)]),nrows(gr_red),1));
540    }
541    else // if the reduced subgraph of C_i consists only of the strict transform
542    {
543      rtm=addmat(rtm,0);
544      rmt=addmat(rmt,0);
545    }
546    // Adjust the total multiplicities at the places where the subgraph has been glued.
547    e=k[i];    // the highest weight of a point that has not yet been assigned its tot. mult.
548    while(e>=1)
549    {
550      s=stricttransforms[maxcp]+1;  // Line in the graph of the start. pt. of the subgraph of C_maxcp.
551      for (j=rgraph[s,s];j<=e;j++)  // Adjust the multiplicities.
552      {
553        rtm[s+j-rgraph[s,s],i]=tm[j];
554        rmt[s+j-rgraph[s,s],i]=mt[j];
555      }
556      maxcp=kp[maxcp];  // To which subgraph has the subgraph of C_maxcp been glued?
557      e=rgraph[s,s]-1;  // What is the highest weight of a pt. that has not yet been assigned its tot.mult.?
558    }
559    e=nrows(rtm);  // Number of rows in the matrix of totalmultiplicities.
560    // The total multiplicities of the C_s for s=1,...,i-1 along the exceptional divisors
561    // which are introduced after the strict transform of C_s has separated (i.e. the entries
562    // in rows stricttransform[i]+1,...,stricttransform[i+1]-1 in the s-th column of the matrix
563    // of total multiplicities still have to be calculated.
564    for (s=1;s<i;s++)
565    {
566      rtm[1..e,s]=adjust_tot_mult(intvec(rtm[1..e,i]),intvec(rtm[1..e,s]),intvec(rmt[1..e,i]),intvec(rmt[1..e,s]),p,q,stricttransforms,i);
567    }
568    // The total multiplicities of the C_i along the exceptional divisors
569    // which are introduced for the sake of C_s, s=1,...,i-1, after the strict transform
570    // of C_i has separated (i.e. the entries in rows stricttransform[s]+1,...,stricttransform[s+1]-1
571    // in the i-th column of the matrix of total multiplicities still have to be calculated.
572    for (s=1;s<i;s++)
573    {
574      rtm[1..e,i]=adjust_tot_mult(intvec(rtm[1..e,s]),intvec(rtm[1..e,i]),intvec(rmt[1..e,s]),intvec(rmt[1..e,i]),p,q,stricttransforms,s);
575    }
576  }
577  if (inputispoly==1) // if the input was a polynomial the ordering of the branches is fine
578  {
579    list result=rgraph,rtm,rmt;
580    return(result);
581  }
582  else // reorder the branches according to the ordering of the input
583  {
584    // reordered total multiplicities, multiplicities and resolution graph
585    intmat rtmro[nrows(rtm)][ncols(rtm)];
586    intmat rmtro[nrows(rmt)][ncols(rmt)];
587    intmat rgraphro=rgraph;
588    for (i=1;i<=r;i++)
589    {
590      rtmro[1..nrows(rtm),newpos[i]]=rtm[1..nrows(rtm),i];
591      rmtro[1..nrows(rmt),newpos[i]]=rmt[1..nrows(rmt),i];
592      for (j=1;j<=nrows(rgraph);j++)
593      {
594        if (rgraph[j,j]==-i)
595        {
596          rgraphro[j,j]=-newpos[i];
597        }
598      }
599    }
600    list result=rgraphro,rtmro,rmtro;
601    return(result);
602  }
603}
604example
605{
606  "EXAMPLE:";
607  echo=2;
608  ring r=0,(x,y),ls;
609  poly f1=(y2-x3)^2-4x5y-x7;
610  poly f2=y2-x3;
611  poly f3=y3-x2;
612  totalmultiplicities(f1*f2*f3);
613}
614
615
616
617proc alexanderpolynomial (def INPUT)
618"USAGE:  alexanderpolynomial(INPUT); INPUT poly or list
619ASSUME:  INPUT is either a REDUCED bivariate polynomial defining a plane curve singularity,
620         or the output of @code{hnexpansion(f[,\"ess\"])}, or the list @code{hne} in
621         the ring created by @code{hnexpansion(f[,\"ess\"])}, or the output of
622         @code{develop(f)} resp. of @code{extdevelop(f,n)}, or a list containing
623         the contact matrix and a list of integer vectors with the characteristic exponents
624         of the branches of a plane curve singularity, or an integer vector containing the
625         characteristic exponents of an irreducible plane curve singularity.
626CREATE:  a ring with variables t, t(1), ..., t(r) (where r is the number of branches of
627         the plane curve singularity f defined by INPUT) and ordering ls over the
628         ground field of the basering. @*
629         Moreover, the ring contains the Alexander polynomial of f in variables t(1), ..., t(r)
630         (@code{alexpoly}), the zeta function of the monodromy operator of f in the variable t
631         (@code{zeta_monodromy}), and a list containing the factors of the Alexander
632         polynomial with multiplicities (@code{alexfactors}).
633RETURN:  a list, say @code{ALEX}, where @code{ALEX[1]} is the created ring
634NOTE:    to use the ring type: @code{def ALEXring=ALEX[i]; setring ALEXring;}.
635         @*
636         Alternatively you may use the procedure sethnering and type: sethnering(ALEX,\"ALEXring\");
637         @*
638         To access the Alexander polynomial resp. the zeta function resp. the
639         factors of the Alexander polynomial type: @code{alexpoly} resp. @code{zeta_monodromy}
640         resp. @code{alexfactors}.@*
641         In case the Hamburger-Noether expansion of the curve f is needed
642         for other purposes as well it is better to calculate this first
643         with the aid of @code{hnexpansion} and use it as input instead of
644         the polynomial itself.
645         @*
646         If you are not sure whether the INPUT polynomial is reduced or not, use
647         @code{squarefree(INPUT)} as input instead.
648SEE ALSO: resolutiongraph, totalmultiplicities
649EXAMPLE: example alexanderpolynomial;  shows an example
650"
651{
652  // Get the resolution graph and the total multiplicities.
653  list gr_tm=totalmultiplicities(INPUT);
654  intmat gr=gr_tm[1];
655  intmat tm=gr_tm[2];
656  int r=ncols(tm);
657  int e=ncols(gr);
658  // Define the Ring for the Alexander Polynomial and the Zeta Function of the Monodromy.
659  execute("ring ALEXring=("+charstr(basering)+"),(t,t(1..r)),dp;");
660  poly hilfspoly=1;
661  poly alexnumerator=1;    // numerator of the Alexander polynomial
662  poly alexdenominator=1;  // denominator of the Alexander polynomial
663  list alexfactors;        // the factors of the Alexanderpolynomial with multiplicities
664  list alexfactor;
665  int chi=2;
666  int i,j,k;
667  int s=1;
668  // Consider every vertex of the resolution graph.
669  for (i=1;i<=e;i++)
670  {
671    if (gr[i,i]>0)  // If it belongs to an exceptional curve.
672    {
673      for (j=1;j<=e;j++)  // Calculate the Euler charateristik of the smooth locus of the exc. curve.
674      {
675        if ((gr[i,j]==1) and (i!=j))
676        {
677          chi=chi-1;
678        }
679      }
680      if (chi!=0)         // If the Euler characteristik is not zero, then it gives a factor in the AP.
681      {
682        for (k=1;k<=r;k++)
683        {
684          hilfspoly=hilfspoly*t(k)^tm[i,k];
685        }
686        hilfspoly=1-hilfspoly;
687        if (chi<0)       // ... either in the numerator ...
688        {
689          alexnumerator=alexnumerator * hilfspoly^-chi;
690        }
691        else             // ... or in the denominator.
692        {
693          alexdenominator=alexdenominator * hilfspoly^chi;
694        }
695        alexfactor=hilfspoly,-chi;
696        alexfactors[s]=alexfactor;
697        s++;
698      }
699      chi=2;
700      hilfspoly=1;
701    }
702  }
703  // Calculate the Alexander Polynomial.
704  if (ncols(tm)==1)  // If we have only one branch, then the numerator has to be multiplied by 1-t.
705  {
706    alexnumerator=alexnumerator*(1-t(1));
707    alexfactor=1-t(1),1;
708    alexfactors[size(alexfactors)+1]=alexfactor;
709  }
710  poly alexpoly=alexnumerator / alexdenominator;
711  // Calculate the Zeta Function of the Monodromy Operator.
712  poly zeta_monodromy=alexpoly;
713  for (i=1;i<=r;i++)
714  {
715    zeta_monodromy=subst(zeta_monodromy,t(i),t);
716  }
717  export zeta_monodromy;
718  export alexnumerator;
719  export alexdenominator;
720  export alexfactors;
721  export alexpoly;
722  list ALEX=ALEXring;
723  return(ALEX);
724}
725example
726{
727  "EXAMPLE:";
728  echo=2;
729  ring r=0,(x,y),ls;
730  poly f1=(y2-x3)^2-4x5y-x7;
731  poly f2=y2-x3;
732  poly f3=y3-x2;
733  list ALEX=alexanderpolynomial(f1*f2*f3);
734  def ALEXring=ALEX[1];
735  setring ALEXring;
736  alexfactors;
737  alexpoly;
738  zeta_monodromy;
739}
740
741proc semigroup (def INPUT)
742"USAGE:    semigroup(INPUT); INPUT poly or list
743ASSUME:   INPUT is either a REDUCED bivariate polynomial defining a plane curve singularity,
744          or the output of @code{hnexpansion(f[,\"ess\"])}, or the list @code{hne} in
745          the ring created by @code{hnexpansion(f[,\"ess\"])}, or the output of
746          @code{develop(f)} resp. of @code{extdevelop(f,n)}, or a list containing
747          the contact matrix and a list of integer vectors with the characteristic exponents
748          of the branches of a plane curve singularity, or an integer vector containing
749          the characteristic exponents of an irreducible plane curve singularity.
750RETURN:   a list with three entries. The first and the second are lists @code{v_1,...,v_s}
751          and @code{w_1,...,w_r} respectively of integer vectors such that the semigroup
752          of the plane curve defined by the INPUT is generated by the vectors
753          @code{v_1,...,v_s,w_1+k*e_1,...,w_r+k*e_r}, where e_i denotes the i-th standard
754          basis vector and k runs through all non-negative integers. The thrid entry is the conductor
755          of the plane curve singularity. Note that r is the number of branches of the plane curve
756          singularity and integer vectors thus have size r.
757NOTE:     If the output is zero this means that the curve has one branch and is regular.
758          In the reducible case the set of generators may not be minimal.
759          @*
760          If you are not sure whether the INPUT polynomial is reduced or not, use
761          @code{squarefree(INPUT)} as input instead.
762SEE ALSO: resolutiongraph, totalmultiplicities
763EXAMPLE:  example semigroup;  shows an example
764"
765{
766  ////////////////////////////////////////////////////////////////////////////////////////
767  // Uses the algorithm in [CDG99] A. Campillo, F. Delgado, S.M. Gusein-Zade, On the
768  // generators of the semigroup of a plane curve singularity,
769  // J. London Math. Soc. (2) 60 (1999), 420-430.
770  ////////////////////////////////////////////////////////////////////////////////////////
771  intvec conductor; // conductor of the singularity
772  list charexp;     // characteristic exponents of the singularity
773  int i,j;
774  /////////////////////////////////////////////////////////////////////////////////
775  // Decide, which kind of input we have, and define the contact matrix
776  /////////////////////////////////////////////////////////////////////////////////
777  // Input: a polynomial defining a plane curve singularity.
778  //////////////////////////////////////////////////////////////////////////////
779  if (typeof(INPUT)=="poly")
780  {
781    /*
782    poly FFF=squarefree(INPUT);
783    if ( deg(FFF)!=deg(INPUT) )
784    {
785      dbprint(printlevel-voice+3,"// input polynomial was not reduced");
786      dbprint(printlevel-voice+3,"// we continue with its reduction");
787    }
788    list I@N@V=invariants(FFF);
789    */
790    list I@N@V=invariants(INPUT);
791  }
792  else
793  {
794    ///////////////////////////////////////////////////////////////////////////////////
795    // Input: the vector of characteristic exponents of an irreducible plane curve
796    ///////////////////////////////////////////////////////////////////////////////////
797    if (typeof(INPUT)=="intvec")
798    {
799      // Calculate the semigroup and the conductor directly.
800      conductor[1]=charexp2conductor(INPUT);
801      intvec gener=charexp2generators(INPUT);
802      list genera;
803      for (i=1;i<=size(gener);i++)
804      {
805        genera[i]=gener[i];
806      }
807      return(list(genera,list(),conductor));
808    }
809    else
810    {
811      if (typeof(INPUT)=="list")
812      {
813        /////////////////////////////////////////////////////////////////////////////////
814        // Input: intersection-matrix and characteristic exponents.
815        //////////////////////////////////////////////////////////////////////////////
816        if (typeof(INPUT[1])=="intmat")
817        {
818          intmat contact=INPUT[1];
819          charexp=INPUT[2];
820          int n=ncols(contact); // to know how many branches we have
821          if (n==1) // Only one branch!
822          {
823            return(semigroup(charexp[1]));
824          }
825          intmat intersecmult=charexp2inter(contact,charexp);
826          for(i=1;i<=ncols(contact);i++)
827          {
828            conductor[i]=charexp2conductor(charexp[i]);//list with the characteristic exponents
829          }
830        }
831        else
832        {
833          /////////////////////////////////////////////////////////////////////////////////
834          // Input: output of hnexpansion or hne in the ring created by hnexpansion
835          //////////////////////////////////////////////////////////////////////////////
836          if ((typeof(INPUT[1])=="ring") or (typeof(INPUT[1])=="list"))
837          {
838            list I@N@V=invariants(INPUT);
839          }
840          else
841          {
842            ////////////////////////////////////////////////////////////////////////////////////
843            // Input: output of develop or extdevelop -- irreducible plane curve singularity
844            ////////////////////////////////////////////////////////////////////////////////////
845            if (typeof(INPUT[1])=="matrix")
846            {
847              return(semigroup(invariants(INPUT)[1]));
848            }
849            else
850            {
851              ERROR("The input is invalid!");
852            }
853          }
854        }
855      }
856      else
857      {
858        ERROR("The input is invalid!");
859      }
860    }
861  }
862  ///////////////////////////////////////////////////////////////////////////////////////////////////
863  // If the input was a poly or an HN-Expansion, then calculate the contact matrix and char.exponents.
864  ///////////////////////////////////////////////////////////////////////////////////////////////////
865  if (defined(I@N@V))
866  {
867    int n =size(I@N@V)-1;// number of branches
868    // If the singularity is irreducible, then we calculate the semigroup directly.
869    if (n==1)
870    {
871      return(semigroup(I@N@V[1][1]));
872    }
873    // If the singularity is not irreducible, then we go on.
874    intmat contact=I@N@V[size(I@N@V)][1];        // contact matrix
875    intmat intersecmult=I@N@V[size(I@N@V)][2];   // intersection multiplicities
876    for(i=1;i<=n;i++)
877    {
878      conductor[i]=I@N@V[i][5];
879      charexp[i]=I@N@V[i][1];
880    }
881  }
882  /////////////////////////////////////////////////////////////////////////////////////
883  // If we have come so far, the curve is reducible!
884  /////////////////////////////////////////////////////////////////////////////////////
885  // Compute the conductor of the curve.
886  /////////////////////////////////////////////////////////////////////////////////////
887  for(i=1;i<=size(conductor);i++)
888  {
889    for(j=1;j<=size(conductor);j++)
890    {
891      conductor[i]=conductor[i]+intersecmult[i,j];
892    }
893  }
894  /////////////////////////////////////////////////////////////////////////////////////
895  /// The total multiplicity vectors of the exceptional divisors generate the semigroup,
896  /// however, this system of generators is not minimal. Theorem 2 in [CDG99] leads
897  /// to the following algorithm for minimizing the set of generators.
898  /////////////////////////////////////////////////////////////////////////////////////
899  list resgr_totmult=totalmultiplicities(list(contact,charexp)); // resolution graph and tot. mult.
900  intmat resgr=resgr_totmult[1];    // resolution graph
901  intmat totmult=resgr_totmult[2];  // total multiplicities
902  list conpts;                      // ith entry = points to which i is connected and their weights
903  intvec series;                    // ith entry = row in totmult which corresponds to w_i
904  intvec deadarc;                   // Star point and the point connected to the star point of a dead arc.
905  list deadarcs;                    // Saves deadarc for all dead arcs.
906  int stop,ctp,ctpstop;
907  list ordinary_generators, series_generators; // the v_i and the w_i from the description
908  // Find for each branch of the curve all the points in the graph to which it is connected
909  // and save the numbers of the corresponding rows in the graph as well as the weight of the point.
910  for (i=1;i<=ncols(resgr);i++)
911  {
912    conpts[i]=find_connection_points(resgr,i);
913  }
914  //////////////////////////////////////////////////////////////////////////////////
915  // Check for each point in the graph, whether it contributes to the semigroup.
916  // If it does not contribute to the semigroup, then set the weight of the point
917  // to zero, i.e. resgr[i,i]=0. Note that the vertex 1 always contributes!
918  //////////////////////////////////////////////////////////////////////////////////
919  // Find first all the points corresponding to the branches and the end points of dead arcs.
920  // The points to which the branch k is connected contributes to w_k. The end points of
921  // dead arcs contribute to the v_i, while the remaining points of the dead arcs are to be removed.
922  j=1;      // Counter for dead arcs - the star points of dead arcs have to be saved for future use.
923  for (i=2;i<=ncols(resgr);i++)
924  {
925    // The end points of dead arcs and the end points corresponding to the branches are
926    // recognized by the fact that they are only connected to one other point.
927    if (size(conpts[i][1])==1)  // row i in the graph corresponds to  an end point
928    {
929      // For an end point corresponding to a branch k the last point E_alpha(k), to which it is
930      // connected, contributes to the generator w_k.
931      if (resgr[i,i]<0)
932      {
933        series[-resgr[i,i]]=conpts[i][1][1];  // Find E_alpha(k), where k=-resgr[i,i]
934        ctp=conpts[i][1][1];
935        resgr[ctp,ctp]=0;                     // So E_alph(k) does not contribute to the v_i.
936      }
937      // For an end point of a dead arc the end point contributes, but all the other points
938      // of the dead arc - including the star point = separation pt of the dead arc - do not contribute.
939      if (resgr[i,i]>0)
940      {
941        stop=0;  // Stop checks whether the star point of the dead arc has been reached.
942        ctp=conpts[i][1][1]; // The point to which the end point is connected.
943        // Set the weights of all the other points in the dead arc to zero.
944        while ((stop==0) and (ctp!=1)) // If the star point or the vertex 1 has been reached, stop.
945        {
946          deadarc[2]=i;          // i might be the point connected to the star point of the dead arc.
947          resgr[ctp,ctp]=0;
948          if (size(conpts[ctp][1])==2)  // If ctp was an ordinary vertex, we go on.
949          {
950            deadarc[2]=ctp; // ctp might be the point connectd to the star point of the dead arc.
951            ctp=conpts[ctp][1][2];  // This is the second point (of higher weight) to which ctp is connected.
952          }
953          else  // If ctp is the star point, we stop.
954          {
955            deadarc[1]=ctp;       // Star point of this dead arc.
956            deadarcs[j]=deadarc;  // Save the j-th dead arc.
957            j++;
958            stop=1;
959          }
960        }
961      }
962    }
963  }
964  //////////////////////////////////////////////////////////////////////////////////
965  // Points (!=1) which are on the geodesics of every branch don't contribute.
966  // (The geodesic of a branch is the shortest connection of the strict transform to 1 in the graph.)
967  stop=0;              // Checks whether the points on all geodesics have been found.
968  ctp=1;               // Point (=row in resgr) to be considered.
969  int prev_ctp;        // Previous point in the graph, to which ctp was connected.
970  int dead_arc_ctp;    // If ctp is the star pt of a dead arc, this is the connection pt of ctp in the d.a.
971  int dastarptcheck;   // Checks whether a point is a star point of a dead arc.
972  if (size(conpts[1][1])>=2) // The graphs separate already at point 1.
973  {
974    stop=1;
975  }
976  else  // The graphs do not separate at point 1.
977  {
978    prev_ctp=1;
979    ctp=conpts[1][1][1];  // Next point to be considered.
980  }
981  // Pass on along the graph until we reach the first point where some branches separate.
982  while (stop==0)
983  {
984    if (size(conpts[ctp][1])==2)  // Point ctp is connected to 2 other points, hence is a normal vertex.
985    {
986      resgr[ctp,ctp]=0;       // Point ctp is a normal vertex.
987      prev_ctp=ctp;           // Save the position of ctp for future use.
988      ctp=conpts[ctp][1][2];  // Next point to which ctp is connected.
989    }
990    if (size(conpts[ctp][1])>3)  // More than three points are connected to ctp.
991    {
992      resgr[ctp,ctp]=0;
993      stop=1;                    // The graphs separate at point ctp.
994    }
995    if (size(conpts[ctp][1])==3)  // At ctp a dead arc might depart or some branch(es)!
996    {                             // If a dead arc departs, then the branches stay together.
997      resgr[ctp,ctp]=0;
998      // Check if a dead arc departs at point ctp (i.e. if ctp is the star point of a dead arc),
999      // then the branches do not separate at ctp.
1000      dastarptcheck=0;
1001      i=1;
1002      while ((i<=size(deadarcs)) and (dastarptcheck==0))
1003      {
1004        if (ctp==deadarcs[i][1])  // ctp is the star point of a dead arc.
1005        {
1006          dastarptcheck=1;
1007          dead_arc_ctp=deadarcs[i][2];  // The point in the dead arc to which ctp is connected.
1008        }
1009        i++;
1010      }
1011      if (dastarptcheck==0)  // ctp is not the star point of a dead arc, hence the graphs separate at ctp.
1012      {
1013        stop=1;
1014      }
1015      else
1016      {
1017        // Set ctp to the point connected to ctp which is not in the dead arc and is not prev_ctp.
1018        i=1;
1019        ctpstop=0;
1020        while ((i<=3) and (ctpstop==0))
1021        {
1022          if ((conpts[ctp][1][i]!=prev_ctp) and (conpts[ctp][1][i]!=dead_arc_ctp))
1023          {
1024            prev_ctp=ctp;
1025            ctp=conpts[ctp][1][i];
1026            ctpstop=1;
1027          }
1028          i++;
1029        }
1030      }
1031    }
1032  }
1033  /////////////////////////////////////////////////////////////////////////////////////////////
1034  // Collect the generators v_j by checking which points in the graph still have
1035  // a positive weight! These points contribute their total multiplicity vector as
1036  // generator v_j.
1037  j=1;
1038  for (i=1;i<=ncols(resgr);i++)
1039  {
1040    if (resgr[i,i]>0)
1041    {
1042      ordinary_generators[j]=intvec(totmult[i,1..ncols(totmult)]);
1043      j++;
1044    }
1045  }
1046  // The "exceptional" generators w_i, for which we have to include w_i+ke_i (for all k)
1047  // are the total multiplicity vectors of the points saved in series.
1048  for (i=1;i<=ncols(totmult);i++)
1049  {
1050    series_generators[i]=intvec(totmult[series[i],1..ncols(totmult)]);
1051  }
1052  return(list(ordinary_generators,series_generators,conductor));
1053}
1054example
1055{
1056  "EXAMPLE:";
1057  echo=2;
1058  ring r=0,(x,y),ls;
1059  // Irreducible Case
1060  semigroup((x2-y3)^2-4x5y-x7);
1061  // In the irreducible case, invariants() also calculates a minimal set of
1062  // generators of the semigroup.
1063  invariants((x2-y3)^2-4x5y-x7)[1][2];
1064  // Reducible Case
1065  poly f=(y2-x3)*(y2+x3)*(y4-2x3y2-4x5y+x6-x7);
1066  semigroup(f);
1067}
1068
1069
1070
1071proc charexp2generators (intvec charexp)
1072"USAGE:      charexp2generators(v),  v intvec
1073ASSUME:      v contains the characteristic exponents of an irreducible plane
1074             curve singularity
1075RETURN:      intvec, the minimal set of generators of the semigroup of the plane curve singularity
1076SEE ALSO:    invariants, resolutiongraph, totalmultiplicities, alexanderpolynomial
1077KEYWORDS:    generators; semigroup; characteristic exponents; topological invariants
1078EXAMPLE:     example charexp2generators;   shows an example"
1079{
1080  int end=size(charexp);
1081  // If the singularity is smooth!
1082  if (end==1)
1083  {
1084    return(1);
1085  }
1086  int i,j;
1087  intvec gener;
1088  intvec GGT;
1089  for (i=1;i<=end;i++)
1090  {
1091    // Calculate the sequence of gcd's of the characteristic exponents.
1092    if (i==1)
1093    {
1094      GGT[1]=charexp[1];
1095    }
1096    else
1097    {
1098      GGT[i]=gcd(GGT[i-1],charexp[i]);
1099    }
1100    // Calculate the generators.
1101    gener[i]=charexp[i];
1102    for (j=2;j<=i-1;j++)
1103    {
1104      gener[i]=gener[i]+((GGT[j-1]-GGT[j]) div GGT[i-1])*charexp[j];
1105    }
1106  }
1107  return(gener);
1108}
1109example
1110{
1111  "EXAMPLE:";
1112  echo=2;
1113  charexp2generators(intvec(28,64,66,77));
1114}
1115
1116
1117proc charexp2multseq (intvec charexp)
1118"USAGE:      charexp2multseq(v),  v intvec
1119ASSUME:      v contains the characteristic exponents of an irreducible plane
1120             curve singularity
1121RETURN:      intvec, the multiplicity sequence of the plane curve singularity
1122NOTE:        If the curve singularity is smooth, then the multiplicity sequence is empty.
1123             This is expressed by returning zero.
1124SEE ALSO:    invariants, resolutiongraph, totalmultiplicities, alexanderpolynomial
1125KEYWORDS:    characteristic exponents; multiplicity sequence; topological invariants
1126EXAMPLE:     example charexp2multseq;   shows an example"
1127{
1128  int end=size(charexp);
1129  // If the singularity is smooth!
1130  if (end==1)
1131  {
1132    return(1); // ERROR: Should be 0, but for the time being, Singular returns 1.
1133  }
1134  intvec multseq=euclidseq(charexp[2],charexp[1]);
1135  for (int i=3;i<=end;i++)
1136  {
1137    multseq=multseq,euclidseq(charexp[i]-charexp[i-1],multseq[size(multseq)]);
1138  }
1139  return(multseq);
1140}
1141example
1142{
1143  "EXAMPLE:";
1144  echo=2;
1145  charexp2multseq(intvec(28,64,66,77));
1146}
1147
1148proc multseq2charexp(def v)   // Procedure written by Fernando.
1149"USAGE:  multseq2charexp(v), v intvec
1150ASSUME:  The input is an intvec, which contains the mutiplicity sequence
1151         of an irreducible plane curve singularity .
1152RETURN:  An intvec, which contains the sequence of characteristic
1153         exponents of the irreducible plane curve singularity defined by v.
1154EXAMPLE: example multseq2charexp; shows an example.
1155"
1156{
1157  ///////  Preamble which reduces the input of an intvec to  /////////////
1158  ///////  the originally assumed input of a list of intvecs /////////////
1159  ///////  and tests the input.                              /////////////
1160  if (typeof(v)=="intvec")
1161  {
1162    list RESULT=multseq2charexp(list(v));
1163    return(RESULT[1]);
1164  }
1165  if (typeof(v)!="list")
1166  {
1167    ERROR("Invalid Input!");
1168  }
1169  if (typeof(v)=="list")
1170  {
1171    int TESTV;
1172    for (int III=1;III<=size(v);III++)
1173    {
1174      if (typeof(v[III])!="intvec")
1175      {
1176        TESTV=1;
1177      }
1178    }
1179    if (TESTV==1)
1180    {
1181      ERROR("Invalid Input!");
1182    }
1183  }
1184  ///////////////////////////////////////////////////////////
1185  list L=v;
1186  int n =size(L);
1187  // ///////////////////////////////////////////////////////
1188  // we look the size of each vector
1189  intvec mm;
1190  for(int j=1;j<=n;j++)
1191  {
1192    mm[j]=size(L[j]);
1193  }
1194  // ///////////////////////////////////////////////////////
1195  // we define some variables
1196  list LL;
1197  int temp, temp1,temp2;
1198  int ind,r,l,boolean;
1199  int old,new;
1200  int contador;
1201  list EUCLI,EUCLI1;
1202  intvec exponent,exponentes1;
1203  int new1,old1;
1204  int contador1;
1205  int a,b,f;
1206  //with the for we round each branch.
1207  for(int k=1;k<=n;k++)
1208  {
1209    l=1;
1210    old=L[k][l];
1211    //if the vertor has more than one element
1212    if(mm[k]<>1)
1213    {
1214      // ///////////////////////////////////////////////////////////////////////////////
1215      // the first step is special because is easy to know the two first characteristic exponents
1216      new=L[k][l+1];
1217      contador=1;
1218      while(old==new)//we check how many consecutives elements are equal, starting in the first.
1219      {
1220        contador=contador+1;
1221        old=new;
1222        new=L[k][contador+1];
1223      }
1224      exponent=L[k][l],contador*L[k][l]+L[k][l+contador];// those are the first two characteristic exponents.
1225      LL[k]=exponent;// we insert them in the final matrix
1226      EUCLI=euclides(LL[k][2],LL[k][1]);// compute the euclides algorithm for the two first characteristic exponents.
1227      temp=size(EUCLI[1]);
1228      // measure how many elements of the multiplicity sequence belong to the first euclidean algorithm.
1229      for(ind=1;ind<=temp;ind=ind+1)
1230      {
1231        l=l+EUCLI[1][ind];
1232      }
1233      l=l-1;//this is the number we are looking for.
1234      ///////////////////////////////////////////////////////////////
1235      r=1;
1236      //repeat the same process until the end of the multiplicity sequence.
1237      if(mm[k]-1>l)
1238      {
1239        while( l<mm[k]-1)
1240        {
1241          r=r+1;
1242          old1=L[k][l];
1243          new1=L[k][l+1];
1244          contador1=0;
1245          boolean=1;
1246          if(old1==new1)
1247          {
1248            while(old1==new1 and boolean==1)
1249            {
1250              contador1=contador1+1;
1251              old1=new1;
1252              new1=L[k][l+contador1+1];
1253              if(size(L[k])<=l+contador1+1)
1254              {
1255                boolean =0;
1256              }
1257            }
1258          }
1259          temp1=size(LL[k]);
1260          exponentes1=LL[k],LL[k][temp1]+(contador1*L[k][l])+L[k][contador1+l+1];
1261          LL[k]=exponentes1;
1262          EUCLI1=euclides(LL[k][temp1+1]-LL[k][temp1],L[k][l]);
1263          temp2=size(EUCLI1[1]);
1264          for(ind=1;ind<=temp2;ind=ind+1)
1265          {
1266            l=l+EUCLI1[1][ind];
1267          }
1268        }
1269      }
1270    }
1271    // if the vector has only one element then the charexp is only 1.
1272    else
1273    {
1274      LL[k]=1;
1275    }
1276  }
1277  return(LL);
1278}
1279example
1280{
1281  "EXAMPLE:";echo=2;
1282  intvec v=2,1,1;
1283  multseq2charexp(v);
1284  intvec v1=4,2,2,1,1;
1285  multseq2charexp(v1);
1286}
1287
1288proc charexp2inter (intmat contact, list charexp)
1289"USAGE:      charexp2inter(contact,charexp),  contact matrix, charexp list
1290ASSUME:      charexp contains the integer vectors of characteristic exponents
1291             of the branches of a plane curve singularity, and contact is their
1292             contact matrix
1293RETURN:      intmat, the matrix intersection multiplicities of the branches
1294SEE ALSO:    invariants, resolutiongraph, totalmultiplicities, semigroup
1295KEYWORDS:    contact matrix; characteristic exponents; intersection multiplicity; topological invariants
1296EXAMPLE:     example charexp2inter;   shows an example"
1297{
1298  int n=ncols(contact);
1299  int i,j,k;
1300  list multpl;
1301  int max=0;
1302  intvec helpvect;
1303  intmat inters[n][n];
1304  // Calculate the multiplicity sequences of the branches.
1305  for (i=1;i<=n;i++)
1306  {
1307    multpl[i]=charexp2multseq(charexp[i]);
1308    // Find the maximal length of a multiplicity sequence.
1309    if (max<size(multpl[i]))
1310    {
1311      max=size(multpl[i]);
1312    }
1313  }
1314  // If the contact of certain branches is higher than the maximal length of the
1315  // multiplicity sequence, then max should be the maximal contact!
1316  helpvect=max,intvec(contact);
1317  max=max_in_intvec(helpvect)[1];
1318  // Prolong them by 1s, in order to take care of higher contact.
1319  for (i=1;i<=n;i++)
1320  {
1321    helpvect=multpl[i];
1322    for (j=size(multpl[i]+1);j<=max;j++)
1323    {
1324      helpvect[j]=1;
1325    }
1326    multpl[i]=helpvect;
1327  }
1328  // Calculate the intersection numbers of the branches: for two branches f_i and f_j
1329  // this is the sum over mult_k(f_i)*mult_k(f_j), where k runs over all infinitely
1330  // near points which f_i and f_j share, i.e. from 1 to contact[i,j].
1331  for (i=1;i<=n;i++)
1332  {
1333    for (j=i+1;j<=n;j++)
1334    {
1335      for (k=1;k<=contact[i,j];k++)
1336      {
1337        inters[i,j]=inters[i,j]+multpl[i][k]*multpl[j][k];
1338      }
1339      inters[j,i]=inters[i,j];
1340    }
1341  }
1342  return(inters);
1343}
1344example
1345{
1346  "EXAMPLE:";echo=2;
1347  ring r=0,(x,y),ds;
1348  list INV=invariants((x2-y3)*(x3-y2)*((x2-y3)^2-4x5y-x7));
1349  intmat contact=INV[4][1];
1350  list charexp=INV[1][1],INV[2][1],INV[3][1];
1351  // The intersection matrix is INV[4][2].
1352  print(INV[4][2]);
1353  // And it is calulated as ...
1354  print(charexp2inter(contact,charexp));
1355}
1356
1357
1358proc charexp2conductor(intvec B)  // Procedure written by Fernando
1359"USAGE:      charexp2conductor(v),  v intvec
1360ASSUME:      v contains the characteristic exponents of an irreducible plane
1361             curve singularity
1362RETURN:      int, the conductor of the plane curve singularity
1363NOTE:        If the curve singularity is smooth, the conductor is zero.
1364SEE ALSO:    invariants, resolutiongraph, totalmultiplicities, semigroup
1365KEYWORDS:    conductor; characteristic exponents; multiplicity sequence; topological invariants
1366EXAMPLE:     example charexp2conductor;   shows an example"
1367{
1368  intvec E;
1369  int i,conductor;
1370  E[1]=B[1];
1371  for(i=2;i<=size(B);i++)
1372    {
1373      E[i]=gcd(E[i-1],B[i]);
1374    }
1375  conductor=1-E[1];
1376  for(i=2;i<=size(B);i++)
1377    {
1378      conductor=conductor+(B[i]*(E[i-1]-E[i]));
1379    }
1380  return(conductor);
1381}
1382example
1383{
1384  "EXAMPLE:";
1385  echo=2;
1386  charexp2conductor(intvec(2,3));  // A1-Singularity
1387  charexp2conductor(intvec(28,64,66,77));
1388}
1389
1390
1391proc charexp2poly(intvec v, vector a)  // Procedure written by Fernando.
1392"USAGE:  charexp2poly(v,a); intvec v, vector a.
1393ASSUME:  v an intvec containing the characterictic exponents of an irreducible plane curve singularity.
1394         a a vector containing the coefficients of a parametrization given by x(t)=x^v[1],
1395         y(t)=a(1)t^v[2]+...+a[n-1]t^v[n], i.e. the entries of a are of type number.
1396RETURN:  A polynomial f in the first two variables of the basering, such that f defines an
1397         irreducible plane curve singularity with characteristic exponents v.
1398NOTE:    The entries in a should be of type number and the vector v should be the sequence of
1399         characteristic exponents of an irreducible plane curve singularity in order to
1400         get a sensible result,
1401SEE ALSO: charexp2multseq, multseq2charexp.
1402EXAMPLE: example charexp2poly;  shows an example
1403"
1404{
1405  int n=size(v);
1406  vector expo;
1407  int i,j,s;
1408  for(i=1;i<=v[1];i++)
1409  {
1410    expo[i]=0;//initialize to 0.
1411  }
1412  for(i=2;i<=n;i++)
1413  {
1414    s=v[i] mod v[1];//calculate the position.
1415    expo=expo-a[i-1]*var(1)^((v[i]-s) div v[1])*gen(s+1);//save in expo -var(1) to the power the corresponding
1416                                                     //but only in the right positions
1417  }
1418  matrix M[v[1]][v[1]];
1419  //construct the matrix that generates the polynomial
1420  for(i=1;i<=v[1];i++)
1421  {
1422    M[i,i]=var(2)+expo[1];//The  diagonal
1423    for(j=1;j<=v[1]-i;j++)
1424         {
1425           M[j,j+i]=expo[i+1];//over diagonal
1426         }
1427    for(j=1;j<=v[1]-i;j++)
1428         {
1429           M[j+i,j]=var(1)*expo[1+v[1]-i];//under diagonal
1430         }
1431  }
1432  //the poynomial is the determinant of the matrix
1433  poly irredpoly=det(M);
1434  return(irredpoly)
1435}
1436example
1437{
1438  "EXAMPLE:";echo=2;
1439  ring r=0,(x,y),dp;
1440  intvec v=8,12,14,17;
1441  vector a=[1,1,1];
1442  poly f=charexp2poly(v,a);
1443  f;
1444  invariants(f)[1][1];  // The characteristic exponents of f.
1445}
1446
1447proc tau_es2 (def INPUT, list #)
1448"USAGE:  tau_es2(INPUT); INPUT poly or list
1449ASSUME:  INPUT is either a REDUCED bivariate polynomial defining a plane curve singularity,
1450         or the output of @code{hnexpansion(f[,\"ess\"])}, or the list @code{hne} in
1451         the ring created by @code{hnexpansion(f[,\"ess\"])}, or the output of
1452         @code{develop(f)} resp. of @code{extdevelop(f,n)}, or a list containing
1453         the contact matrix and a list of integer vectors with the characteristic exponents
1454         of the branches of a plane curve singularity, or an integer vector containing the
1455         characteristic exponents of an irreducible plane curve singularity.
1456RETURN:  int, the equisingular Tjurina number of f, i. e. the codimension of the mu-constant
1457         stratum in the semiuniversal deformation of f, where mu is the Milnor number of f.
1458NOTE:    The equisingular Tjurina number is calculated with the aid of a Hamburger-Noether
1459         expansion, which is the hard part of the calculation.
1460         In case the Hamburger-Noether expansion of the curve f is needed
1461         for other purposes as well it is better to calculate this first
1462         with the aid of @code{hnexpansion} and use it as input instead of
1463         the polynomial itself.
1464         @*
1465         If you are not sure whether the INPUT polynomial is reduced or not, use
1466         @code{squarefree(INPUT)} as input instead.
1467SEE ALSO: tau_es, develop, hnexpansion, totalmultiplicities, equising_lib
1468EXAMPLE: example tau_es2;  shows an example
1469"
1470{
1471  // If the input is a weighted homogeneous polynomial, then use a direct algorithm to
1472  // calculate the equisingular Tjurina number, by caluclating a K-basis of the
1473  // Tjurina algebra and omitting those elements with weighted degree at least the
1474  // weighted degree of the polynomial. -- If an additional input # is given (which is
1475  // not just the number 1 !!!), the procedure always uses the recursive algorithm.
1476  if ((typeof(INPUT)=="poly") and (size(#)==0))
1477  {
1478    if (qhweight(INPUT)[1]!=0)
1479    {
1480      /*
1481      poly f=squarefree(INPUT);
1482      if ( deg(f)!=deg(INPUT) )
1483      {
1484        dbprint(printlevel-voice+3,"// input polynomial was not reduced");
1485        dbprint(printlevel-voice+3,"// we continue with its reduction");
1486      }
1487      return(tau_es_qh(f));
1488      */
1489      return(tau_es_qh(INPUT));
1490    }
1491  }
1492  // Else apply the recursive algorithm from Eugenii Shustin, On Manifolds of Singular
1493  // Algebraic Curves, Selecta Math. Sov. Vol 10, No. 1 (1991), p. 31.
1494  int i,j,k;                  // Laufvariablen
1495  int tau,tau_i;              // Variable for es-Tjurina no., multiplicitiy, and es-Tjurina at blow ups
1496  intmat contact;             // contact matrix
1497  list graphs, multipl;       // resolution graphs and multiplicity sequences
1498  list graphs_ed, multipl_ed; // res.graphs and mult.seq. of one curve on 1st ex. div.
1499  intmat contact_ed;          // contact matrix of one curve on 1st exceptional divisor
1500  int d_i;                    // correction term
1501  intvec connections;
1502  intmat graph;
1503  intvec multseq;
1504  int s,e;
1505  int multi;                  // multiplicity of the curve defined by the input.
1506  /////////////////////////////////////////////////////////
1507  // Check what type the input is, and act accordingly.
1508  if (typeof(INPUT)=="list")
1509  {
1510    if (size(INPUT)==3)
1511    {
1512      // If the INPUT is the output of totalmultiplicities(INPUT,"tau")
1513      if ((typeof(INPUT[1])=="list") and (typeof(INPUT[2])=="list") and (typeof(INPUT[3])=="intmat"))
1514      {
1515        graphs=INPUT[1];
1516        multipl=INPUT[2];
1517        contact=INPUT[3];
1518      }
1519      // Otherwise call the procedure with the output of totalmultiplicities(INPUT,"tau").
1520      else
1521      {
1522        return(tau_es2(totalmultiplicities(INPUT,"tau")));
1523      }
1524    }
1525    else
1526    {
1527      return(tau_es2(totalmultiplicities(INPUT,"tau")));
1528    }
1529  }
1530  // Otherwise call the procedure with the output of totalmultiplicities(INPUT,"tau").
1531  else
1532  {
1533    return(tau_es2(totalmultiplicities(INPUT,"tau")));
1534  }
1535  /// End of checking the input
1536  ///////////////////////////////////////////////////////
1537  // If the singularity is smooth, the equisingular Tjurina number is zero.
1538  if ((ncols(contact)==1) and (multipl[1][1]<=1))
1539  {
1540    return(0);
1541  }
1542  // Otherwise calculate the multiplicity of the singularity.
1543  for (i=1;i<=size(multipl);i++)
1544  {
1545    multi=multi+multipl[i][1];
1546  }
1547  // Find the branches which stay together after blowing up once, and group them together.
1548  k=0;
1549  intvec curves_on_first_ex_div=k;  // If this is 0=i_0,i_1,...i_s=ncols(contact), then the branches
1550  while (k<ncols(contact))          // (i_j)+1,...,i_(j+1) stay together after the first blowing up,
1551  {                                 // and s is the number of infinitely near points of first order.
1552    k=find_last_non_one(intvec(contact[k+1,1..ncols(contact)]),k+2);
1553    curves_on_first_ex_div=curves_on_first_ex_div,k;
1554  }
1555  // And then calculate the equisingular Tjurina numbers in the infinitely near points of
1556  // first order plus some correction term (= the number of blow ups needed to separate the
1557  // strict transform from the exceptional divisor in the corresponding infinitely near point)
1558  // and add them.
1559  for (i=1;i<=size(curves_on_first_ex_div)-1;i++)
1560  {
1561    s=curves_on_first_ex_div[i]+1;
1562    e=curves_on_first_ex_div[i+1];
1563    graphs_ed=list(graphs[s..e]);
1564    multipl_ed=list(multipl[s..e]);
1565    contact_ed=intmat_minus_one(intmat(intvec(contact[s..e,s..e]),e-s+1,e-s+1));
1566    connections=0;
1567    // Adjust the graphs and multiplicity sequences by cutting the first level.
1568    // And find in each graph the point to which the point 1 is connected = 1 + number of
1569    // blow ups needed to separate the strict transform from the first exceptional divisor.
1570    for (j=1;j<=size(graphs_ed);j++)
1571    {
1572      // Adjust the graphs and find the connection points.
1573      graph=graphs_ed[j];
1574      connections[j]=find_connection_point(intvec(graph[1,1..ncols(graph)]),1);
1575      graph=delete_row(delete_col(graph,1),1);
1576      graphs_ed[j]=graph;
1577      // Adjust the multiplicity sequences.
1578      multseq=multipl_ed[j];
1579      if (size(multseq)==1)  // If multseq has only one entry, then their is only
1580      {                      // one branch left and it is smooth! So set multipl_ed[j]=1.
1581        multipl_ed[j]=intvec(1);
1582      }
1583      else  // Otherwise just cut the first entry.
1584      {
1585        multipl_ed[j]=intvec(multseq[2..size(multseq)]);
1586      }
1587    }
1588    // Calculate the equisingular Tjurina number of the strict transform at the i-th
1589    // intersection point with the first exceptional divisor.
1590    tau_i=tau_es2(list(graphs_ed,multipl_ed,contact_ed));
1591    // Calculate the number no. of blow ups needed to separate the strict transform of
1592    // the curve defined by the input from the first exceptional divisor at their i-th
1593    // intersection point.
1594    d_i=max_in_intvec(connections)-1;
1595    // If d_i is negative, then there was only one branch left and it was smooth, so d_i should be 1.
1596    if (d_i<0)
1597    {
1598      d_i=1;
1599    }
1600    // If the curve defined by graphs_ed was smooth, then the summand has to be reduced by 1.
1601    if (tau_i==0)
1602    {
1603      tau_i=-1;
1604    }
1605    tau=tau+tau_i+d_i;
1606  }
1607  // The equisingular Tjurina number is then calculated by adding the following term.
1608  tau=tau+((multi*(multi+1)) div 2)-2;
1609  return(tau);
1610}
1611example
1612{
1613  "EXAMPLE:";
1614  echo=2;
1615  ring r=0,(x,y),ls;
1616  poly f1=y2-x3;
1617  poly f2=(y2-x3)^2-4x5y-x7;
1618  poly f3=y3-x2;
1619  tau_es2(f1);
1620  tau_es2(f2);
1621  tau_es2(f1*f2*f3);
1622}
1623
1624
1625///////////////////////////////////////////////////////////////////////////////////////////
1626// Static procedures.
1627///////////////////////////////////////////////////////////////////////////////////////////
1628
1629static proc euclidseq(int a,int b)
1630"USAGE:      euclidseq(a,b),  a,b integers
1631RETURN:      intvec,  the divisors in the euclidean alogrithm with multiplicities
1632KEYWORDS:    Euclidean algorithm; multiplicity sequence
1633NOTE :       This procedure is for internal use only; it is called by charexp2multseq.
1634"
1635{
1636  int i;
1637  // multseq saves in each step of the Euclidean algorithm q-times the divisor b
1638  intvec multseq;
1639  int q=a div b;
1640  int r=a mod b;
1641  for (i=1;i<=q;i++)
1642  {
1643    multseq[i]=b;
1644  }
1645  int s=q;        // size of multseq
1646  a=b;
1647  b=r;
1648  while(r<>0)
1649  {
1650        q=a div b;
1651        r=a mod b;
1652    for (i=1;i<=q;i++)
1653    {
1654      multseq[s+i]=b;
1655    }
1656    s=s+q;        // size of multseq
1657        a=b;
1658        b=r;
1659  }
1660  return(multseq);
1661}
1662
1663static proc puiseuxchainpart (int piij, int muij, intvec multpl, int initial_tm, int end_tm, int j)
1664"USAGE:   puiseuxchainpart(piij,muiij,multpl,initial_tm,end_tm,j);
1665RETURN:   list L, L[1] incidence matrix of a part of the Puiseux chain, L[2] the total
1666          multiplicities of this part of the Puiseux chain.
1667NOTE:     This procedure is only for internal use; it is called by puiseuxchain.
1668"
1669{
1670  int delta=1;
1671  if (j==1){delta=0;}                 // Delta measures whether j is 1 or not.
1672  intvec totalmultiplicity;           // Keeps the total multiplicities.
1673  intmat pcp[muij][muij];             // Keeps the incidence matrix of the Puiseuxchainpart S_i,j.
1674  // Calculate the total multiplicities and the Puiseuxchainpart S_i,j.
1675  totalmultiplicity[1]=initial_tm+end_tm+multpl[1];
1676  pcp[1,1]=piij+1;
1677  for (int k=2;k<=muij;k++)
1678  {
1679    pcp[k,k]=piij+k;
1680    pcp[k-1,k]=1;
1681    pcp[k,k-1]=1;
1682    totalmultiplicity[k]=totalmultiplicity[k-1]+delta*initial_tm+multpl[k];
1683  }
1684  list result=pcp,totalmultiplicity;
1685  return(result);
1686}
1687
1688static proc puiseuxchain (int initial, intvec divseq, intvec multpl, int initial_tm)
1689"USAGE:   puiseuxchain(initial,divseq,multpl,initial_tm); int initial, initial_tm, intvec divseq, multpl
1690RETURN:   list L, L[1] incidence matrix of a Puiseux chain, L[2] the weight of the point to which the
1691          previous Puiseux chain has to be connected, L[3] the sequence of total multiplicities of
1692          the points in this Puiseux chain.
1693NOTE:     This procedure is only for internal use; it is called by irred_resgraph_totmult.
1694"
1695{
1696  int j,k,l,connectpoint;
1697  intvec multpli;
1698  int pc_tm=initial_tm;       // Keeps the total multipl. of the endpoint of P_i-1.
1699  int end_tm=0;
1700  int start=1;
1701  int omega=size(divseq);
1702  // Keep the endpoints of the puiseuxchainparts (minus initial)  s_i,j in divseq_sum.
1703  intvec divseq_sum=divseq[1];
1704  for (j=2;j<=omega;j++)
1705    {
1706      divseq_sum[j]=divseq_sum[j-1]+divseq[j];
1707    }
1708  // Define the connecting point of the Puiseuxchain P_i-1 with P_i.
1709  if (divseq[1]==0)
1710  {
1711    // If divseq[1]=mu_i,1=0, then the Puiseuxchainpart S_i,1 is empty.
1712    // We may start building the Puiseuxchain with part 2, i.e. set start=2.
1713    start=2;
1714    if (omega>=3)
1715    {
1716      connectpoint=initial+divseq_sum[2]+1;  // startpoint of s_i+1,3
1717    }
1718    else
1719    {
1720      connectpoint=initial+divseq_sum[2];    // endpoint of s_i+1,2
1721    }
1722  }
1723  else
1724  {
1725    connectpoint=initial+1;
1726  }
1727  // Build the Puiseuxchainparts s_i,j and put them as blocks into pc=P_i.
1728  multpli=multpl[initial+1..initial+divseq_sum[start]];
1729  list pcp=puiseuxchainpart(initial,divseq[start],multpli,initial_tm,end_tm,start);
1730  intmat pc=pcp[1];
1731  intvec tm=pcp[2];
1732  for (j=start+1;j<=omega;j++)
1733    {
1734      // Keep the final total multipl. of the puiseuxchainpart S_i,j-2 resp. P_i-1, if S_i,1 empty.
1735      if (j>2){end_tm=initial_tm;}
1736      // Calculate the endpoint of S_i,j-1.
1737      initial=initial+divseq[j-1];
1738      // Keep the total multiplicity of the endpoint of S_i,j-1
1739      initial_tm=pcp[2][size(pcp[2])];
1740      // Build the new puiseuxchainpart S_i,j
1741      multpli=multpl[initial+1..initial+divseq[j]];
1742      pcp=puiseuxchainpart(initial,divseq[j],multpli,initial_tm,end_tm,j);
1743      pc=addmat(pc,pcp[1]);
1744      tm=tm,pcp[2];
1745    }
1746  // Connect the Puiseuxchainparts s_i,j.
1747  for (j=start;j<=omega-2;j++)
1748    {
1749      k=divseq_sum[j];          // endpoint of s_i,j
1750      l=divseq_sum[j+1]+1;      // startpoint of s_i,j+2
1751      pc[k,l]=1;            // connecting these
1752      pc[l,k]=1;
1753    }
1754  if (omega>=start+1)   // If there are at least two non-empty s_i,j.
1755    {
1756      k=divseq_sum[omega-1];    // endpoint of s_i,omega-1
1757      l=divseq_sum[omega];      // endpoint of s_i,omega
1758      pc[k,l]=1;            // connecting these
1759      pc[l,k]=1;
1760    }
1761  list ergebnis=pc,connectpoint,tm;
1762  return(ergebnis);
1763}
1764
1765static proc irred_resgraph_totmult (intvec charexp)
1766"USAGE:   irred_resgraph_totmult(charexp); charexp intvec
1767ASSUME:   charexp is an integer vector containg the characteristic exponents of
1768          an irreducible plane curve singularity
1769RETURN:   list L, L[1] is the incidence matrix of the resolution graph of the plane curve
1770          singularity defined by INPUT, and L[2] is its sequence of total multiplicities
1771NOTE:     This procedure is only for internal use; it is called by resgraph.
1772"
1773{
1774  int k,l;
1775  intvec multpl=charexp2multseq(charexp);  // multiplicity sequence of the singularity
1776  // Do first the case where the singularity is actually smooth.
1777  if (size(charexp)==1)
1778  {
1779    intmat resgraph[1][1]=0;
1780    intvec tm=1;   // there is no exceptional divisor in the resolution - ERROR: should be 0,
1781                   // but for the time being, Singular returns 1 as multiplicity of smooth curves
1782    list result=resgraph,tm,multpl;
1783    return(result);
1784  }
1785  // End of the smooth case
1786  int initial_tm=0;                  // total multipl. of the endpoint of Puiseux chain P_i-1
1787  int g=size(charexp);
1788  list es=divsequence(charexp[2],charexp[1]);   // keeps the lengths of the Puiseuxchainparts s_i,j
1789  intvec divseq=es[1];
1790  int r=es[2];
1791  int initial=0;
1792  // Build the Puiseuxchains P_i and put them as blocks into a matrix.
1793  list pc=puiseuxchain(initial,divseq,multpl,initial_tm);
1794  intmat resgraph=pc[1];
1795  intvec endpoints=resgraph[nrows(resgraph),ncols(resgraph)];
1796  intvec connectpoints=pc[2];
1797  intvec tm=pc[3];
1798  for (int i=3;i<=g;i++)
1799    {
1800      initial_tm=tm[size(tm)];
1801      es=divsequence(charexp[i]-charexp[i-1],r);
1802      divseq=es[1];
1803      r=es[2];
1804      initial=endpoints[size(endpoints)];
1805      pc=puiseuxchain(initial,divseq,multpl,initial_tm);
1806      resgraph=addmat(resgraph,pc[1]);
1807      endpoints=endpoints,resgraph[nrows(resgraph),ncols(resgraph)];
1808      connectpoints=connectpoints,pc[2];
1809      tm=tm,pc[3];
1810    }
1811  // Adding the * for the strict transform to the Graph.
1812  resgraph=addmat(resgraph,0);
1813  // The connecting point of the * with the graph.
1814  connectpoints=connectpoints,nrows(resgraph);
1815  // Connect the P_i with each other and with *.
1816  for (i=2;i<=g;i++)
1817  {
1818    k=endpoints[i-1];          // endpoint of P_i-1
1819    l=connectpoints[i];        // conncting point of P_i resp. of *
1820    resgraph[k,l]=1;          // connecting these
1821    resgraph[l,k]=1;
1822  }
1823  list result=resgraph,tm,multpl; //HIER GEAENDERT!!!!
1824  return(result);
1825}
1826
1827
1828static proc max_in_intvec (intvec v, list #)
1829"USAGE:   max_in_intvec(v); v intvec
1830RETURN:   int m, maximum of the integers in v
1831USAGE:    max_in_intvec(v,1); v intvec
1832RETURN:   intvec m, m[1] maximum of the integers in v, m[2] position of the
1833          last occurence of the maximum in v
1834NOTE:     This procedure is only for internal use; this procedure is called by
1835          totalmultiplicities and semigroup.
1836"
1837{
1838  int max=v[1];
1839  int maxpos=1;
1840  for (int i=2;i<=size(v);i++)
1841  {
1842    if (v[i]>max)
1843    {
1844      max=v[i];
1845      maxpos=i;
1846    }
1847  }
1848  if (size(#)==0)
1849  {
1850    return(max);
1851  }
1852  else
1853  {
1854    return(intvec(max,maxpos));
1855  }
1856}
1857
1858static proc addmat (intmat A,intmat B)
1859"USAGE:   max_in_intvec(A,B); A, B integer matrices
1860RETURN:   intmat C, block matrix with left-upper block A, right-lower block B
1861NOTE:     This procedure is only for internal use; this procedure is called several times.
1862"
1863{
1864  int nc=ncols(A);
1865  int nr=nrows(A);
1866  int mc=ncols(B);
1867  int mr=nrows(B);
1868  int i,j;
1869  intmat AB[nr+mr][nc+mc];
1870  for (i=1;i<=nr;i++)
1871    {
1872      for (j=1;j<=nc;j++)
1873        {
1874          AB[i,j]=A[i,j];
1875        }
1876    }
1877  for (i=1;i<=mr;i++)
1878    {
1879      for (j=1;j<=mc;j++)
1880        {
1881          AB[i+nr,j+nc]=B[i,j];
1882        }
1883    }
1884  return(AB);
1885}
1886
1887static proc divsequence(int a,int b)
1888"USAGE:   divsequence(a,b); a,b integers
1889RETURN:   list l, l[1] the multiplicities of the divisors in the Euclidean algorithm
1890          and l[2] the last non-zero remainder in the Euclidean algorithm
1891NOTE:     This procedure is only for internal use; it is called in irred_res_graph.
1892"
1893{
1894  int q=a div b;
1895  int r=a mod b;
1896  intvec divseq=q;
1897  while(r<>0)
1898  {
1899    a=b;
1900    b=r;
1901    q=a div b;
1902    r=a mod b;
1903    divseq = divseq,q;
1904  }
1905  list result=divseq,b;
1906  return(result);
1907}
1908
1909
1910
1911static proc adjust_tot_mult (intvec rtm_fix, intvec rtm_var, intvec rmt_fix, intvec rmt_var, def p, def q, def stricttransforms, int k)
1912"USAGE:   adjust_tot_mult(v1,v2,v3,v4,p,q,st,k); v1,...,st intvecs and k an integer
1913RETURN:   intvec rtm_var, adjusted total multiplicities
1914NOTE:     This procedure is only for internal use; it is called in totalmultiplicities.
1915"
1916{
1917  int j,l,store;  // Help variables.
1918  // Recalculate the entries in rtm_var from stricttransforms[k]+1,...,stricttransforms[k+1]-1.
1919  for (j=stricttransforms[k]+1;j<stricttransforms[k+1];j++)
1920  {
1921    if (rtm_var[j]==0) // If the entry is non-zero, we know that it is already correct.
1922    {
1923      // Check if the vertex in the fixed part is connected to one or to two vertices of lower weight.
1924      if (j==stricttransforms[k]+1)  // The vertex of weight 1 less is p[k], to which the subgraph is glued.
1925      {
1926        store=rtm_fix[j]-rmt_fix[j]-rtm_fix[p[k]];
1927      }
1928      else                           // The vertex of weight 1 less belongs to the subgraph.
1929      {
1930        store=rtm_fix[j]-rmt_fix[j]-rtm_fix[j-1];
1931      }
1932      // It is connected to two vertices V (which has weight one less) and W.
1933      if (store>0)
1934      {
1935        if (j==stricttransforms[k]+1)  // V is p[k] (to which the subgraph was glued) and W is q[k], the
1936        {                              // vertex of weight one less, to which p[k] is connected.
1937          rtm_var[j]=rtm_var[p[k]]+rtm_var[q[k]];  // In this case the subgraph separates p[k] and q[k]!
1938        }
1939        if (j==stricttransforms[k]+2)  // V belongs to the subgraph (it is the vertex considerd in the
1940        {  // previous case!), and W is p[k] or q[k]. In this case the subgraph separates p[k] and q[k].
1941          if (store==rtm_fix[p[k]])  // If W=p[k], ...
1942          {
1943            rtm_var[j]=rtm_var[j-1]+rtm_var[p[k]];
1944          }
1945          else                       // else W=q[k] ... .
1946          {
1947            rtm_var[j]=rtm_var[j-1]+rtm_var[q[k]];  // separates p[k] and q[k].
1948          }
1949        }
1950        if (j>stricttransforms[k]+2)  // V belongs to the subgraph and W either does as well or is p[k].
1951        {
1952          l=j-2;
1953          while (store<rtm_fix[l]) // Find the second vertex W which is connected to which it is
1954          {                        // connected. It has total multipl. = store!
1955            if (l>stricttransforms[k]+1) // If l-1 belongs to the graph, then reduce l.
1956            {
1957              l=l-1;
1958            }
1959            else // If l-1 is stricttransform[k], hence isn't in the graph, then reducing l gives p[k].
1960            {    // If l=p[k] and still store<rtm_fix[l], then j must be connected to q[k]!
1961              if (l==stricttransforms[k]+1)
1962              {
1963                l=p[k];
1964              }
1965              else
1966              {
1967                l=q[k];
1968              }
1969            }
1970          }
1971          rtm_var[j]=rtm_var[j-1]+rtm_var[l];
1972        }
1973      }
1974      // It is only connected to one vertex V, which then must be the one of weight one less.
1975      else
1976      {
1977        if (j==stricttransforms[k]+1) // V is p[k], the vertex, to which the subgraph was glued.
1978        {
1979          rtm_var[j]=rtm_var[p[k]];
1980        }
1981        else
1982        {
1983          rtm_var[j]=rtm_var[j-1];  // V is belongs already to the subgraph.
1984        }
1985      }
1986    }
1987  }
1988  return(rtm_var);
1989}
1990
1991
1992static proc find_connection_point (intvec v, int k)
1993"USAGE:   find_connection_point(v,c); where v is an intvec, and k is an integer
1994RETURN:   The largest integer i>k, such that v[i]=1, or 0 if no such i exists.
1995NOTE:     This procedure is only for internal use; it is called in totalmultiplicities.
1996"
1997{
1998  for (int i=size(v)-1;i>=k+1;i--)
1999  {
2000    if (v[i]==1)
2001    {
2002      return(i);
2003    }
2004  }
2005  return(0);
2006}
2007
2008static proc find_connection_points (intmat resgr, int k)
2009"USAGE:   find_connection_points(resgr,k); where resgr is an intmat, and k is an integer
2010RETURN:   list of two intvecs ctps and ctpswts, where ctps contains all integers i!=k, such
2011          that resgr[k,i]=1, and ctpswts contains for each such i the weight resgr[i,i].
2012NOTE:     This procedure is only for internal use; it is called in totalmultiplicities.
2013"
2014{
2015  intvec ctps;
2016  intvec ctpswts;
2017  int j=1;
2018  for (int i=1;i<=ncols(resgr);i++)
2019  {
2020    if ((resgr[k,i]==1) and (i!=k))
2021    {
2022      ctps[j]=i;
2023      ctpswts[j]=resgr[i,i];
2024      j++;
2025    }
2026  }
2027  return(list(ctps,ctpswts));
2028}
2029
2030static proc find_lower_connection_points (intmat resgr, int k)
2031"USAGE:   find_lower_connection_points(resgr,k); where resgr is an intmat, and k is an integer
2032ASSUME:   resgr is the resolutiongraph of an IRREDUCIBLE curve singularity and k<ncols(resgr).
2033RETURN:   intvec, which contains the weights of points of lower weight than k, to which
2034          the point of weight k in resgr is connected, and 0 if no such point exists.
2035NOTE:     This procedure is only for internal use; it is called in totalmultiplicities.
2036"
2037{
2038  intvec ctps=find_connection_points(resgr,k)[2];
2039  intvec lower_ctps;
2040  int i=1;
2041  while ((ctps[i]<k) and (ctps[i]>0))
2042  {
2043    lower_ctps[i]=ctps[i];
2044    i++;
2045  }
2046  return(lower_ctps);
2047}
2048
2049
2050static proc euclides(int a,int b)  // Procedure of Fernando.
2051"USAGE:   euclides(m,n);where m,n are integers.
2052RETURN:   The divisor, the quotients and the remainders of the euclidean algorithm performing for m and n.
2053NOTE:     This procedure is only for internal use; it is called in multseq2charexp.
2054"
2055{
2056 int c=a div b;//we compute in c the integer division between a and b.
2057 int r=a mod b;//in r the remainer of the division between a and b
2058 intvec dividendo=c;// we define the intvec of the dividens and we initialize it to c
2059 intvec remain=r;// we define the intvec of the remainders and we initialize it to r
2060 a=b;//change a to b
2061 b=r;// and b to r
2062
2063 while(r<>0)// while the current remainder is diferent to 0 we make the same af before
2064  {
2065    c=a div b;
2066    r=a mod b;
2067    dividendo =dividendo,c;
2068    if(r<>0)
2069      {
2070        remain=remain,r;
2071      }
2072       a=b;
2073       b=r;
2074     }
2075   list L=dividendo,remain;//we put in a list all the dividens and all the remainders
2076   return(L);// and return the list
2077}
2078
2079
2080
2081static proc tau_es_qh (poly f)
2082"USAGE:    tau_es_qh(f), poly f
2083RETURN:   int, equisingular Tjurina number
2084NOTE:     This procedure is only for internal use; it is called in Tau_es.
2085"
2086{
2087  intvec qh=qhweight(f);
2088  if (qh[1]==0)
2089  {
2090    ERROR("Input is not quasi-homogenous.");
2091  }
2092  else
2093  {
2094    int d_f = deg(f,qh);
2095    list Tj=Tjurina(f,1);
2096    ideal tj=Tj[2];
2097    int Taues=size(tj);
2098    for (int i=1;i<=size(tj);i++)
2099    {
2100      if (deg(tj[i],qh)>=d_f)
2101      {
2102        Taues--;
2103      }
2104    }
2105  }
2106  return(Taues);
2107}
2108
2109
2110static proc move_row (intmat M, int i,int j)
2111"USAGE:    move_row(M,i,j), intmat M, int i,j
2112RETURN:   intmat, the matrix M with j-th row now i-th row and the remaining rows moved accordingly.
2113NOTE:     This procedure is only for internal use; it is called in move_row_col.
2114"
2115{
2116  if ((i>nrows(M)) or (j>nrows(M)))
2117  {
2118    ERROR("The matrix has not enough rows.");
2119  }
2120  if (i==j)
2121  {
2122    return(M);
2123  }
2124  if (i>1)
2125  {
2126    intmat N[nrows(M)+1][ncols(M)]=intvec(M[1..i-1,1..ncols(M)]),intvec(M[j,1..ncols(M)]),intvec(M[i..nrows(M),1..ncols(M)]);
2127  }
2128  if (i==1)
2129  {
2130    intmat N[nrows(M)+1][ncols(M)]=intvec(M[j,1..ncols(M)]),intvec(M[i..nrows(M),1..ncols(M)]);
2131  }
2132  if (i<j)
2133  {
2134    N=delete_row(N,j+1);
2135  }
2136  if (i>j)
2137  {
2138    N=delete_row(N,j);
2139  }
2140  return(N);
2141}
2142
2143static proc move_col (intmat M, int i,int j)
2144"USAGE:    move_col(M,i,j), intmat M, int i,j
2145RETURN:   intmat, the matrix M with j-th column now i-th column and the remaining columns moved accordingly.
2146NOTE:     This procedure is only for internal use; it is called in move_row_col.
2147"
2148{
2149  return(transpose(move_row(transpose(M),i,j)));
2150}
2151
2152static proc move_row_col (intmat M,int i,int j)
2153"USAGE:    move_row(M,i,j), intmat M, int i,j
2154RETURN:   intmat, the matrix M with j-th row/column now i-th row/column and the remaining
2155          rows and columns moved accordingly.
2156NOTE:     This procedure is only for internal use; it is called in totalmultiplicities.
2157"
2158{
2159  return(move_col(move_row(M,i,j),i,j));
2160}
2161
2162
2163static proc delete_row (intmat M,int i)
2164"USAGE:    delete_row(M,i); M intmat, i int
2165RETURN:   intmat, which is derived from M by removing the ith row
2166NOTE:     This procedure is only for internal use; it is called in move_row and tau_es2.
2167"
2168{
2169  if ((i!=1) and (i!=nrows(M)))
2170  {
2171    return(intmat(intvec(M[1..i-1,1..ncols(M)],M[i+1..nrows(M),1..ncols(M)]),nrows(M)-1,ncols(M)));
2172  }
2173  if (i==1)
2174  {
2175    return(intmat(intvec(M[2..nrows(M),1..ncols(M)]),nrows(M)-1,ncols(M)));
2176  }
2177  else
2178  {
2179    return(intmat(intvec(M[1..nrows(M)-1,1..ncols(M)]),nrows(M)-1,ncols(M)));
2180  }
2181}
2182
2183static proc delete_col (intmat M, int i)
2184"USAGE:    delete_col(M,i); M intmat, i int
2185RETURN:   intmat, which is derived from M by removing the ith column
2186NOTE:     This procedure is only for internal use; it is called in tau_es.
2187"
2188{
2189  return(transpose(delete_row(transpose(M),i)));
2190}
2191
2192
2193
2194static proc sort_branches (intmat contact, list graphs, list totmult, list multpl, int k,int l)
2195"USAGE:    sort_branches(K,L,M,N,k,l); K intmat, L,M,N lists, k,l integers
2196ASSUME:   K = contact matrix of the branches of a curve, L = their resolutiongraphs,
2197          M = their totalmultiplicities, N = their multiplicities
2198RETURN:   list LL, LL[1] transformed K, LL[2..4] transformed L,M,N.
2199          The procedure sorts the branches from k+1 to l according to descending contact with
2200          with the branch k.
2201NOTE:     This procedure is only for internal use; it is called in totalmultiplicities.
2202"
2203{
2204  intvec max;
2205  for (int i=k+1;i<=l;i++)
2206  {
2207    // Find the last graph max between i and l which has maximal contact with k.
2208    max=max_in_intvec(intvec(contact[k,i..l]),1);
2209    max[2]=max[2]+i-1;
2210    if (i!=max[2])  // If max is not i, then move max to position i!
2211    {
2212      graphs=insert(graphs,graphs[max[2]],i-1);
2213      graphs=delete(graphs,max[2]+1);
2214      totmult=insert(totmult,totmult[max[2]],i-1);
2215      totmult=delete(totmult,max[2]+1);
2216      multpl=insert(multpl,multpl[max[2]],i-1);
2217      multpl=delete(multpl,max[2]+1);
2218      contact=move_row_col(contact,i,max[2]);
2219    }
2220  }
2221  return(list(contact,graphs,totmult,multpl));
2222}
2223
2224
2225static proc find_last_non_one (intvec v,int k)
2226"USAGE:    find_last_non_one (v,k); intvec v, int k
2227RETURN:   int i, the last index i>=k such that v[i]!=1, or k-1 if no such i exists.
2228NOTE:     This procedure is only for internal use; it is called in tau_es2.
2229"
2230{
2231  int i=size(v);
2232  while (i>=k)
2233  {
2234    if (v[i]!=1)
2235    {
2236      return(i);
2237    }
2238    else
2239    {
2240      i--;
2241    }
2242  }
2243  return(i);
2244}
2245
2246static proc intmat_minus_one (intmat M)
2247"USAGE:    intmat_minus_one(M);  intmat M
2248RETURN:   intmat, all non-zero entries of M deminuished by 1.
2249NOTE:     This procedure is only for internal use; it is called in tau_es2.
2250"
2251{
2252  int i,j;
2253  for (i=1;i<=nrows(M);i++)
2254  {
2255    for (j=1;j<=ncols(M);j++)
2256    {
2257      if (M[i,j]!=0)
2258      {
2259        M[i,j]=M[i,j]-1;
2260      }
2261    }
2262  }
2263  return(M);
2264}
2265
2266proc proximitymatrix (def INPUT)
2267"USAGE:  proximitymatrix(INPUT); INPUT poly or list or intmat
2268ASSUME:  INPUT is either a REDUCED bivariate polynomial defining a plane curve singularity,
2269         or the output of @code{hnexpansion(f[,\"ess\"])}, or the list @code{hne} in
2270         the ring created by @code{hnexpansion(f[,\"ess\"])}, or the output of
2271         @code{develop(f)} resp. of @code{extdevelop(f,n)}, or a list containing
2272         the contact matrix and a list of integer vectors with the characteristic exponents
2273         of the branches of a plane curve singularity, or an integer vector containing the
2274         characteristic exponents of an irreducible plane curve singularity, or the resolution
2275         graph of a plane curve singularity (i.e. the output of resolutiongraph or
2276         the first entry in the output of totalmultiplicities).
2277RETURN:  list, of three integer matrices. The first one is the proximity matrix of
2278         the plane curve defined by the INPUT, i.e. the entry i,j is 1 if the
2279         infinitely near point corresponding to row i is proximate to the infinitely
2280         near point corresponding to row j. The second integer matrix is the incidence matrix of the
2281         resolution graph of the plane curve. The entry on the diagonal in row i is -s-1
2282         if s is the number of points proximate to the infinitely near point corresponding
2283         to the ith row in the matrix. The third integer matrix is the incidence matrix of
2284         the Enriques diagram of the plane curve singularity, i.e. each row corresponds to
2285         an infinitely near point in the minimal standard resolution, including the
2286         strict transforms of the branches, the diagonal element gives
2287         the level of the point, and the entry i,j is -1 if row i is proximate to row j.
2288NOTE:    In case the Hamburger-Noether expansion of the curve f is needed
2289         for other purposes as well it is better to calculate this first
2290         with the aid of @code{hnexpansion} and use it as input instead of
2291         the polynomial itself.
2292         @*
2293         If you are not sure whether the INPUT polynomial is reduced or not, use
2294         @code{squarefree(INPUT)} as input instead.
2295         @*
2296         If the input is a smooth curve, then the output will consist of
2297         three one-by-one zero matrices.
2298         @*
2299         For the definitions of the computed objects see e.g. the book
2300         Eduardo Casas-Alvero, Singularities of Plane Curves.
2301SEE ALSO: develop, hnexpansion, totalmultiplicities, alexanderpolynomial
2302EXAMPLE: example proximitymatrix;  shows an example
2303"
2304{
2305  ///////// Decide on the type of input. //////////
2306  if (typeof(INPUT)=="intmat")
2307  {
2308    intmat resgr=INPUT;
2309  }
2310  else
2311  {
2312    intmat resgr=totalmultiplicities(INPUT)[1];
2313  }
2314  ////////  Deal with the case of a smooth curve ////////////////
2315  if (size(resgr)==1)
2316  {
2317    return(list(intmat(intvec(1),1,1),intmat(intvec(-1),1,1),intmat(intvec(0),1,1)));
2318  }
2319  ////////  Calculate the proximity resolution graph ////////////
2320  int i,j;
2321  int n=nrows(resgr);
2322  intvec diag; // Diagonal of the Enriques diagram.
2323  int si; // number of points proximate to the point corresponding to the ith row
2324  // Adjust the weights of the nodes corresponding to strict transforms so
2325  // as if there had been one additional blow up.
2326  for (i=1;i<=n;i++)
2327  {
2328    // Check if the row corresponds to an exceptional divisor ...
2329    if (resgr[i,i]<0)
2330    {
2331      j=1;
2332      while ((resgr[i,j]==0) or (i==j))
2333      {
2334        j++;
2335      }
2336      resgr[i,i]=resgr[j,j]+1;
2337    }
2338  }
2339  // Set the weights in the resolution graph to the blowing up level in the resolution.
2340  for (i=1;i<=n;i++)
2341  {
2342    resgr[i,i]=resgr[i,i]-1;
2343    diag[i]=resgr[i,i]; // The level of the corresponding infinitely near point.
2344  }
2345  // Replace the weights in the resolution graph by
2346  // -s-1, where s is the number of points which are proximate to the point.
2347  for (i=1;i<=n;i++)
2348  {
2349    si=-1;
2350    // Find the points of higher weight which are connected to the ith row.
2351    for (j=i+1;j<=n;j++)
2352    {
2353      // If the point in row j is connected to the ith row, then all the points of
2354      // weight resgr[i,i]+1 to weight resgr[j,j] in the corresponding subgraph
2355      // are proximate to the point of the ith row. This number is just resgr[j,j]-resgr[i,i].
2356      if ((resgr[i,j]!=0) and (resgr[j,j]>0))
2357      {
2358        si=si-(resgr[j,j]-resgr[i,i]);
2359      }
2360    }
2361    resgr[i,i]=si;
2362  }
2363  ///////////////  Calculate the proximity matrix  ///////////////////
2364  intmat proximity=proxgauss(resgr);
2365  intmat enriques=proximity;
2366  for (i=1;i<=nrows(enriques);i++)
2367  {
2368    enriques[i,i]=diag[i];
2369  }
2370  return(list(proximity,resgr,enriques));
2371}
2372example
2373{
2374  "EXAMPLE:";
2375  echo=2;
2376  ring r=0,(x,y),ls;
2377  poly f1=(y2-x3)^2-4x5y-x7;
2378  poly f2=y2-x3;
2379  poly f3=y3-x2;
2380  list proximity=proximitymatrix(f1*f2*f3);
2381  /// The proximity matrix P ///
2382  print(proximity[1]);
2383  /// The proximity resolution graph N ///
2384  print(proximity[2]);
2385  /// They satisfy N=-transpose(P)*P ///
2386  print(-transpose(proximity[1])*proximity[1]);
2387  /// The incidence matrix of the Enriques diagram ///
2388  print(proximity[3]);
2389  /// If M is the matrix of multiplicities and TM the matrix of total
2390  /// multiplicities of the singularity, then  M=P*TM.
2391  /// We therefore calculate the (total) multiplicities. Note that
2392  /// they have to be slightly extended.
2393  list MULT=extend_multiplicities(totalmultiplicities(f1*f2*f3));
2394  intmat TM=MULT[1];  // Total multiplicites.
2395  intmat M=MULT[2];   // Multiplicities.
2396  /// Check: M-P*TM=0.
2397  M-proximity[1]*TM;
2398  /// Check: inverse(P)*M-TM=0.
2399  intmat_inverse(proximity[1])*M-TM;
2400}
2401
2402static proc addmultiplrows (intmat M, int i, int j, int ki, int kj)
2403"USAGE:   addmultiplrows(M,i,j,ki,kj);  intmat M, int i,j,ki,kj
2404RETURN:   intmat, replaces the j-th row in M by ki-times the i-th row plus
2405                  kj times the j-th
2406NOTE:     This procedure is only for internal use; it is called in intmat_inverse
2407          and proxgauss.
2408"
2409{
2410  int k=ncols(M);
2411  M[j,1..k]=kj*M[j,1..k]+ki*M[i,1..k];
2412  return(M);
2413}
2414
2415
2416static proc proxgauss (intmat M)
2417"USAGE:   proxgauss(M);  intmat M
2418ASSUME:   M is the output of proximity_resgr
2419RETURN:   intmat, replaces the j-th row in M by ki-times the i-th row plus
2420                  kj times the j-th
2421NOTE:     This procedure is only for internal use; it is called in intmat_inverse.
2422"
2423{
2424  int i;
2425  int n=nrows(M);
2426  if (n==1)
2427  {
2428    M[1,1]=1;
2429    return(M);
2430  }
2431  else
2432  {
2433    if (M[n,n]<0)
2434    {
2435      M=addmultiplrows(M,n,n,-1,0);
2436    }
2437    for (i=n-1;i>=1;i--)
2438    {
2439      if (M[i,n]!=0)
2440      {
2441        M=addmultiplrows(M,n,i,-M[i,n],M[n,n]);
2442      }
2443    }
2444    intmat N[n-1][n-1]=M[1..n-1,1..n-1];
2445    N=proxgauss(N);
2446    M[1..n-1,1..n-1]=N[1..n-1,1..n-1];
2447    return(M);
2448  }
2449}
2450
2451proc extend_multiplicities (list rg)
2452"USAGE:      extend_multiplicities(rg); list rg
2453ASSUME:      rg is the output of the procedure totalmultiplicities
2454RETURN:      list, the first entry is an integer matrix containing the total
2455             multiplicities and the second entry is an integer matrix containing
2456             the multiplicies of the resolution given by rg, where the zeros
2457             corresponding to the strict transforms of the branches of the curve
2458             have been replaced by the (total) multiplicities of the infinitely near
2459             point corresponding to one further blow up for each branch.
2460KEYWORDS:    total multiplicities; multiplicity sequence; resolution graph
2461EXAMPLE:     example extend_multiplicities;   shows an example
2462"
2463{
2464  intmat resgr,tm,mt=rg[1],rg[2],rg[3];
2465  int i,j;
2466  for (i=1;i<=nrows(resgr);i++)
2467  {
2468    if (resgr[i,i]<0)
2469    {
2470      j=1;
2471      while ((resgr[i,j]==0) or (i==j))
2472      {
2473        j++;
2474      }
2475      tm[i,1..ncols(tm)]=tm[j,1..ncols(tm)];
2476      tm[i,-resgr[i,i]]=tm[i,-resgr[i,i]]+1;
2477      mt[i,-resgr[i,i]]=1;
2478    }
2479  }
2480  return(list(tm,mt));
2481}
2482example
2483{
2484  "EXAMPLE:";
2485  echo=2;
2486  ring r=0,(x,y),ls;
2487  poly f1=(y2-x3)^2-4x5y-x7;
2488  poly f2=y2-x3;
2489  poly f3=y3-x2;
2490  // Calculate the resolution graph and the (total) multiplicities of f1*f2*f3.
2491  list RESGR=totalmultiplicities(f1*f2*f3);
2492  // Extend the (total) multiplicities.
2493  list MULT=extend_multiplicities(RESGR);
2494  // Compare the total multiplicities.
2495  RESGR[2];
2496  MULT[1];
2497  // Compare the multiplicities.
2498  RESGR[3];
2499  MULT[2];
2500}
2501
2502proc intmat_inverse (intmat M)
2503"USAGE:      intmat_inverse(M); intmat M
2504ASSUME:      M is a lower triangular integer matrix with diagonal entries 1 or -1
2505RETURN:      intmat, the inverse of M
2506KEYWORDS:    integer matrix, inverse
2507EXAMPLE:     example intmat_inverse;   shows an example
2508"
2509{
2510  int i,j,k;
2511  int n=nrows(M);
2512  intmat U[n][n];
2513  U=U+1;
2514  for (i=1;i<=n;i++)
2515  {
2516    if (M[i,i]==-1)
2517    {
2518      M=addmultiplrows(M,i,i,-1,0);
2519      U=addmultiplrows(U,i,i,-1,0);
2520    }
2521    for (j=i+1;j<=n;j++)
2522    {
2523      U=addmultiplrows(U,i,j,-M[j,i],M[i,i]);
2524      M=addmultiplrows(M,i,j,-M[j,i],M[i,i]);
2525    }
2526  }
2527  return(U);
2528}
2529example
2530{
2531  "EXAMPLE:";echo=2;
2532  intmat M[5][5]=1,0,0,0,0,1,1,0,0,0,2,1,1,0,0,3,1,1,1,0,4,1,1,1,1 ;
2533  intmat U=intmat_inverse(M);
2534  print(U);
2535  print(U*M);
2536}
Note: See TracBrowser for help on using the repository browser.