source: git/Singular/LIB/alexpoly.lib @ e009ef

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