1 /* ------------------------------------------------------------------- */
3 /* by Fabrizio Caruso modified by Alexandre Le Meur and Marie-Françoise Roy */
7 SARAG_POINT_STYLE_GENERIC : 3;
8 SARAG_POINT_STYLE_CRITICAL : 2;
9 SARAG_POINT_STYLE_NONCRITICAL : 1;
11 signAtRoot(pol,x,polyInX,rootInX) :=
12 signsAtRoots([rootInX],polyInX,pol,x)[1][2];
14 bivariateSignChanges(seq,x,polyInX,rootInX) :=
15 signChanges(map(lambda([arg],signAtRoot(arg,x,polyInX,rootInX)),seq));
19 upperBoundWithSignAt(polyInX,interval,x,sgnAtRoot) :=
20 block([signFound,bound,lhsBound,rhsBound],
22 while(not(signFound)) do
24 bound : upperBoundAt(polyInX,interval,x),
27 if sgn(lhsBound)=sgnAtRoot and sgn(rhsBound)=sgnAtRoot then
30 interval : refineRoot(interval,polyInX,x)
32 return([interval,[lhsBound,rhsBound]])
37 bivariateSSubResSignChanges(seq,x,polyInX,rootInX) :=
38 genPermMVar(map(lambda([arg],signAtRoot(arg,x,polyInX,rootInX)),seq));
40 bivariateSSubResTarskiQuery(q,p,var,x,polyInX,rootInX) :=
41 block([degQ, degP, sSRRes, sSR, seq, coeffSeq, j, b1, b0, Rbar],
50 coeffSeq : sSubResCoeff(p,diff(p,var),var),
51 return(signAtRoot(leadCoeff(q,var),x,polyInX,rootInX)*
52 bivariateSSubResSignChanges(coeffSeq,x,polyInX,rootInX))
60 Rbar : expand(diff(p,var)*q-degP*b1*p),
62 coeffSeq : sSubResCoeff(p,Rbar,var), /* SR(p b1 P - P' Q) */
64 return(bivariateSSubResSignChanges(coeffSeq,x,polyInX,rootInX))
69 coeffSeq : sSubResCoeff(expand(-diff(p,var)*q,p,var)), /* SR(-P'Q,P) */
71 return(bivariateSSubResSignChanges(coeffSeq,x,polyInX,rootInX) + signAtRoot(leadCoeff(q,var),x,polyInX,rootInX))
73 return(bivariateSSubResSignChanges(coeffSeq,x,polyInX,rootInX))
78 multiplicity(sol,pol,var) :=
81 while(expand(factor(subst(sol,var,pol)))=0) do
89 bivariateMultiplicity(sol,pol,var,x,polyInX,rootInX) :=
92 while(signAtRoot(expand(factor(subst(sol,var,pol))),x,polyInX,rootInX)=0) do
102 archimedeanTopology(pol,isolAlg,x,y) :=
103 block([sRes,sSR,sSRCoeff,discr,isolDiscr,i,j,jList,epsList,flag,rootSign,degP,
104 numOfRoots,rootsAtDiscr,numAbove,rootsAtDiscrAboveCr,taQ,
105 numBetween,rootsBetween,res,
106 coSys,generic,critY,multi,aboveCr],
110 if constantp(pol) then
115 while(not(degree(leadCoeff(pol,y),x)=0)) do
120 print("topology) WARNING: the function is not quasi-monomial in ", y),
121 print("topology) WARNING: new curve is : ", expand(subst(x+y,x,pol)))
123 pol : expand(subst(x+y,x,pol))
129 while (not(generic)) do
132 sSR : sSubResPol(pol,diff(pol,y),y),
133 sSRCoeff : sSubResCoeff(pol,diff(pol,y),y),
134 discr : last(sSRCoeff),
137 isolDiscr : isListSort(isolAlg(discr,x)),
142 rootsAtDiscrAboveCr : [],
145 degP : degree(expand(pol),y),
148 generic : true, /* It "hopes" the curve is in generic position but it will check during computation */
149 for i : 1 thru length(isolDiscr) do /* should insert check on generic position */
154 if length(isolDiscr[i]) = 1 then
160 rootSign : sgn(subst(isolDiscr[i][1],x,sSRCoeff[degP+1-j])),
162 if not(rootSign=0) then
168 jList : endcons(j,jList),
169 epsList : endcons(rootSign,epsList),
171 if not(ASSUME_GENERIC_POSITION) then
173 critY : -1/j * coeff(subst(isolDiscr[i][1],x,sSR[degP+1-j]),y,j-1)/
174 subst(isolDiscr[i][1],x,sSRCoeff[degP+1-j]),
177 multi : multiplicity(critY,subst(isolDiscr[i][1],x,sSR[degP+1-j]),y),
184 print("topology) WARNING : Non-generic position --- multiplicity : ",
186 print("topology) WARNING: new curve is : ", expand(subst(x+y,x,pol)))
188 pol : expand(subst(x+y,x,pol)),
190 while(not(degree(leadCoeff(pol,y),x)=0)) do
195 print("topology) WARNING: the function is not quasi-monomial in ", y),
196 print("topology) WARNING: new curve is : ", expand(subst(x+y,x,pol)))
198 pol : expand(subst(x+y,x,pol))
206 numOfRoots : genPermMVar(subst(isolDiscr[i][1],x,sSRCoeff)),
208 rootsAtDiscr : endcons(numOfRoots,rootsAtDiscr),
209 taQ : sSubResTarskiQuery(
210 expand(subst(isolDiscr[i][1],x,
211 rootSign*(j*sSRCoeff[degP+1-j]*y+coeff(sSR[degP+1-j],y,j-1)))),
212 expand(subst(isolDiscr[i][1],x,pol)),y),
214 numAbove : (numOfRoots+taQ-1)/2,
216 rootsAtDiscrAboveCr : endcons(numAbove,rootsAtDiscrAboveCr)
220 else /* case when the root of the dicriminant is described by an open interval */
225 while(not(flag)and j <= degP+1) do
228 rootSign : signAtRoot(sSRCoeff[degP+1-j],
229 x,discr,isolDiscr[i]),
231 if not(rootSign=0) then
237 jList : endcons(j,jList),
238 epsList : endcons(rootSign,epsList),
240 if not(ASSUME_GENERIC_POSITION) then
242 critY : -1/j * coeff(sSR[degP+1-j],y,j-1)/sSRCoeff[degP+1-j],
246 multi : bivariateMultiplicity(critY,sSR[degP+1-j],y,x,discr,isolDiscr[i]),
254 print("topology) WARNING : Non-generic position --- multiplicity : ",
257 print("topology) WARNING: new curve is : ", expand(subst(x+y,x,pol)))
259 pol : expand(subst(x+y,x,pol)),
261 while(not(degree(leadCoeff(pol,y),x)=0)) do
266 print("topology) WARNING: the function is not quasi-monomial in ", y),
267 print("topology) WARNING: new curve is : ", expand(subst(x+y,x,pol)))
269 pol : expand(subst(x+y,x,pol))
276 numOfRoots : bivariateSSubResSignChanges(sSRCoeff,x,discr,isolDiscr[i]),
277 rootsAtDiscr : endcons(numOfRoots,rootsAtDiscr),
279 taQ : bivariateSSubResTarskiQuery(
280 rootSign*(j*sSRCoeff[degP+1-j]*y+coeff(sSR[degP+1-j],y,j-1)),
281 pol,y,x,expand(squareFree(discr,x)),isolDiscr[i]),
283 numAbove : (numOfRoots+taQ-1)/2,
285 rootsAtDiscrAboveCr : endcons(numAbove,rootsAtDiscrAboveCr)
292 if length(isolDiscr)>0 then
295 rootsBetween : [genPermMVar(subst(isolDiscr[1][1]-1,x,sSRCoeff))],
297 for i : 1 thru length(isolDiscr)-1 do
301 rootsBetween : endcons(genPermMVar(
302 subst(intermidiatePoint(isolDiscr[i],isolDiscr[i+1],discr,x),
308 rootsBetween : endcons(genPermMVar(subst(last(last(isolDiscr))+1,x,sSRCoeff)),rootsBetween),
310 res : [rootsBetween[1] ],
311 while i<=length(isolDiscr) do
313 res : append(res,[[rootsAtDiscr[i],rootsAtDiscr[i]-rootsAtDiscrAboveCr[i]],rootsBetween[i+1]]),
316 if DRAW_TOPOLOGY then
322 res : [sSubResTarskiQuery(1,subst(0,x,pol),y)],
323 if DRAW_TOPOLOGY then
331 /* ----------------------------------------------------------- */
332 /* Plotting of the topological graph of a planar curve */
333 /* Very preliminary */
336 getPointsOnProj(num,projX,height):=makelist([projX,i*height/(num+1)],i,1,num);
339 drawPoints(ptList) :=
340 plot2d([discrete,float(ptList)],
341 ['style,[points, SARAG_POINT_STYLE_GENERIC]],
342 [gnuplot_preamble, "set grid; set xrange[-25:25]; set yrange[-10:10]; unset key"]);
347 drawPointsOnProj(num,projX,height) :=
348 drawPoints(getPointsOnProj(num,projX,height));
352 getPointsOnCrit(num,pos,projX,height):=
353 block([i,crit,nonCritBelow,nonCritAbove],
356 for i : 1 thru num do
358 crit : [projX,i*height/(num+1)]
361 nonCritBelow : append(nonCritBelow,[[projX,i*height/(num+1)]])
363 nonCritAbove : append(nonCritAbove,[[projX,i*height/(num+1)]]),
364 return([crit,nonCritBelow,nonCritAbove])
368 getTopologyPoints(tpg) :=
369 block([i,j,nonCritPts,critPts,ptsOnCritProj,previous,jump,newNonCritPts,lastCritPts,lastNonCritPts,
370 correct,newPtsAtInd,ptsAtInf,lineSegsAtInf, lineSegs, newPtsAtInf],
372 lastCritPts : [0,[],[]],
375 ptsOnCritProj : [0,[],[]],
379 /* It checks the form of the input */
382 while correct and i<= length(tpg) do
387 if not(listp(tpg[i])) then
392 if not(length(tpg[i])=2) or
393 not(numberp(first(tpg[i]))) or
394 not(numberp(second(tpg[i]))) then
402 if not(numberp(tpg[i])) then
407 ), /* end of check of the input format */
417 if PLOT_AT_INFINITY then
419 newPtsAtInf : getPointsOnProj(tpg[1],0,PLOT_HEIGHT),
420 ptsAtInf : append(ptsAtInf,newPtsAtInf),
421 newNonCritPts : getPointsOnProj(tpg[1],1*PLOT_SPACING,PLOT_HEIGHT),
422 for j : 1 thru tpg[1] do
423 lineSegsAtInf : append(lineSegsAtInf,[[discrete,
424 float([newPtsAtInf[j],
425 newNonCritPts[j] ])]])
429 for i : 1 thru length(tpg) do
431 if oddp(i) then /* non critical points */
434 newNonCritPts : getPointsOnProj(tpg[i],i*PLOT_SPACING,PLOT_HEIGHT),
435 nonCritPts : append(nonCritPts,newNonCritPts),
437 if not(ptsOnCritProj = [0,[],[]]) then
440 jump : length(newNonCritPts)-length(ptsOnCritProj[2])-length(ptsOnCritProj[3]),
443 for j : 1 thru length(ptsOnCritProj[2]) do
444 lineSegs : append(lineSegs,[[discrete,
445 float([ptsOnCritProj[2][j],
446 newNonCritPts[j]])]]),
448 for j : 1 thru length(ptsOnCritProj[3]) do
449 lineSegs : append(lineSegs,[[discrete,
450 float([ptsOnCritProj[3][j],
451 newNonCritPts[j+jump+length(ptsOnCritProj[2])]])]]),
453 for j : 1 thru jump do
454 lineSegs : append(lineSegs,[[discrete,
455 float([ptsOnCritProj[1],newNonCritPts[j+length(ptsOnCritProj[2])]])]])
461 else /* critical points */
465 ptsOnCritProj : getPointsOnCrit(tpg[i][1],tpg[i][2],i*PLOT_SPACING,PLOT_HEIGHT),
466 jump : length(newNonCritPts)-(tpg[i][1]-1),
470 for j : 1 thru length(ptsOnCritProj[3]) do
472 lineSegs : append(lineSegs,[[discrete,
473 float([newNonCritPts[j+jump+length(ptsOnCritProj[2])],
474 ptsOnCritProj[3][j]])]])
478 for j : 1 thru length(ptsOnCritProj[2]) do
479 lineSegs : append(lineSegs, [[discrete,
480 float([newNonCritPts[j],ptsOnCritProj[2][j]])]]),
482 for j : 1 thru jump do
483 lineSegs : append(lineSegs,[[discrete,
484 float([newNonCritPts[j+length(ptsOnCritProj[2])],
485 ptsOnCritProj[1]])]]),
488 critPts : append(critPts,[ptsOnCritProj[1]]),
489 nonCritPts : append(nonCritPts,ptsOnCritProj[2],ptsOnCritProj[3])
492 if PLOT_AT_INFINITY then
494 newPtsAtInf : getPointsOnProj(tpg[length(tpg)],(length(tpg)+1)*PLOT_SPACING,PLOT_HEIGHT),
495 ptsAtInf : append(ptsAtInf,newPtsAtInf),
497 newNonCritPts : getPointsOnProj(tpg[length(tpg)],length(tpg)*PLOT_SPACING,PLOT_HEIGHT),
498 for j : 1 thru tpg[length(tpg)] do
499 lineSegsAtInf : append(lineSegsAtInf,[[discrete,
500 float([newPtsAtInf[j],
501 newNonCritPts[j] ])]])
507 return([nonCritPts,critPts,lineSegs,ptsAtInf,lineSegsAtInf])
510 getCritPoint(critLine,projX,height) :=
511 [projX,critLine[2]*height/critLine[1]];
514 block([nonCritPoints,critPoints,firstAttemptToGetPoints,secondAttemptToGetPoints, topologyPoints,style,preamble,i,
515 leftMost,rightMost,top,bottom,ptsAtInf,fixedTpg, lineSegs],
517 firstAttemptToGetPoints: getTopologyPoints(tpg),
518 if not firstAttemptToGetPoints=false then
520 topologyPoints : firstAttemptToGetPoints,
525 secondAttemptToGetPoints: getTopologyPoints(second(tpg)),
526 if not secondAttemptToGetPoints=false then
528 topologyPoints : secondAttemptToGetPoints,
529 fixedTpg : second(tpg)
532 if topologyPoints=false then
534 print("Wrong input format!"),
539 nonCritPoints : topologyPoints[1],
540 critPoints : topologyPoints[2],
541 lineSegs : topologyPoints[3],
543 lineSegs : append(lineSegs,topologyPoints[5]),
545 ptsAtInf : topologyPoints[4],
548 rightMost : PLOT_SPACING*length(fixedTpg)+3,
551 preamble : concat(PLOT_STYLE, "set xrange[-1:",rightMost,
552 "]; set yrange[-1:",PLOT_HEIGHT,"];"),
555 for i : 1 thru length(lineSegs) do
556 style : cons([lines, 1, SARAG_LINE_COLOR],style),
558 if not(PS_OUTPUT) then
559 if critPoints=[] then
560 plot2d(append([[discrete,float(nonCritPoints)]],
562 cons('style,cons([points, SARAG_POINT_SIZE, SARAG_POINT_STYLE_NONCRITICAL],style)),
563 [gnuplot_preamble, preamble])
565 if nonCritPoints = [] then
566 plot2d(append([[discrete,float(critPoints)]],
568 cons('style,cons([points, SARAG_POINT_SIZE, SARAG_POINT_STYLE_CRITICAL],style)),
569 [gnuplot_preamble,preamble])
571 plot2d(append([[discrete,float(nonCritPoints)],
572 [discrete,float(critPoints)]],
574 cons('style,append([[points, SARAG_POINT_SIZE, SARAG_POINT_STYLE_NONCRITICAL],
575 [points, SARAG_POINT_SIZE, SARAG_POINT_STYLE_CRITICAL]],style)),
576 [gnuplot_preamble,preamble])
578 if critPoints=[] then
579 plot2d(append([[discrete,float(nonCritPoints)]],
581 cons('style,cons([points, SARAG_POINT_SIZE, SARAG_POINT_STYLE_NONCRITICAL],style)),
582 [gnuplot_preamble, preamble],
583 [gnuplot_term, ps], [gnuplot_out_file, PS_OUTPUT_FILE_NAME])
585 if nonCritPoints = [] then
586 plot2d(append([[discrete,float(critPoints)]],
588 cons('style,cons([points, SARAG_POINT_SIZE, SARAG_POINT_STYLE_CRITICAL],style)),
589 [gnuplot_preamble,preamble],
590 [gnuplot_term, ps], [gnuplot_out_file, PS_OUTPUT_FILE_NAME])
592 plot2d(append([[discrete,float(nonCritPoints)],
593 [discrete,float(critPoints)]],
595 cons('style,append([[points, SARAG_POINT_SIZE, SARAG_POINT_STYLE_NONCRITICAL],
596 [points, SARAG_POINT_SIZE, SARAG_POINT_STYLE_CRITICAL]],style)),
597 [gnuplot_preamble,preamble],
598 [gnuplot_term, ps], [gnuplot_out_file, PS_OUTPUT_FILE_NAME])