1 /* ------------------------------------------------------------------- */
2 /* SARAG - Root Isolation */
3 /* by Fabrizio Caruso modified by Alexandre Le Meur and Marie-Françoise Roy */
6 /* i-th Bernstein polynomial of degree p for c and d */
7 bernstein(p,i,c,d,var) :=
8 binomial(p,i) * (var-c)^i * (d-var)^(p-i) / (d-c)^p;
11 /* -------------------------------------- */
12 /* Bounds on real roots */
14 /* Cauchy Root Upper Bound */
16 /* (Defined for non-zero polynomials) */
17 cauchyRootUpperBound(pol,var) :=
22 while coeff(pol,var,q)=0 do
24 den : abs(coeff(pol,var,p)),
26 return(sum(abs(coeff(pol,var,i)),i,q,p)/den)
30 /* Cauchy Root Lower Bound for non-zero roots */
31 cauchyRootLowerBound(pol,var) :=
36 while coeff(pol,var,q)=0 do
38 den : abs(coeff(pol,var,q)),
39 return((sum(abs(coeff(pol,var,i)),i,q,p)/den)^(-1))
44 /* Prime Cauchy Root Upper Bound */
46 primeCauchyRootUpperBound(pol,var) :=
51 while coeff(pol,var,q)=0 do
53 den : coeff(pol,var,p)^2,
54 return((p+1)* sum(coeff(pol,var,i)^2,i,q,p)/den)
58 /* Prime Cauchy Root Lower Bound for non-zero roots */
59 primeCauchyRootLowerBound(pol,var) :=
64 while coeff(pol,var,q)=0 do
66 den : coeff(pol,var,q)^2,
67 return(((p+1)* sum(coeff(pol,var,i)^2,i,q,p)/den)^(-1))
71 /* ----------------------------------------- */
72 /* Auxiliary routines for sign determination */
74 /* It determines the sign */
75 /* to the right of the left end of open interval */
76 signToTheLeft(bern) :=
79 while(sgn(bern[i])=0) do
85 /* It determines the sign */
86 /* to the left of the right end of open interval */
87 signToTheLeft(bern) :=
90 while(sgn(bern[i])=0) do
98 /* ------------------------------------- */
99 /* Splitting of Bezier curves */
102 bernsteinSplit(coeffList, c, d,e) :=
103 block([p : length(coeffList)-1,
104 b : make_array('any),
110 b : make_array('any,p+1),
112 b[i] : coeffList[i+1],
120 for j : 0 thru p-i do
121 b[j] : alpha * b[j] + beta * b[j+1],
122 bern_ce : endcons(b[0],bern_ce),
124 bern_ed : cons(b[p-i],bern_ed)
127 return([bern_ce,bern_ed])
131 /* Algorithm 10.34 */
132 specialBernsteinSplit(coeffList,c,d) :=
133 block([p : length(coeffList)-1,
136 b : make_array('any),
139 b : make_array('any,p+1),
141 b[i] : coeffList[i+1],
143 bern_first : [2^p * b[0]],
144 bern_second : [2^p * b[p]],
148 for j : 0 thru p-i do
149 b[j] : b[j] + b[j+1],
151 bern_first : endcons(2^(p-i) * b[0],bern_first),
153 bern_second : cons(2^(p-i)*b[p-i],bern_second)
157 return([bern_first,bern_second])
162 /* Square free part of a polynomial */
163 squareFree(pol,var) := gcdFreePartWithZ(pol,diff(pol,var),var)[2];
165 /* ---------------------------------------------- */
166 /* Auxiliary routines for polynomial manipulation */
168 translated(pol,var,c) := subst(var-c,var,pol);
170 reciprocal(pol,var,p) := var^p * subst(1/var,var,pol);
173 /* (defined for l different from zero) */
174 contracted(pol,var,l) := subst(var*l,var,pol);
176 /* auxiliary coefficients as defined in page 340 */
177 /* (in the book notation: a_(c,k)) */
178 specialCoeff(l,c,k) :=
179 (-2^(l+k) + c*2^(l+1))/(2^k);
183 /* Generic base logarithm */
184 logInBase(val,base) :=
187 discreteLogInBaseTwo(val) :=
195 bernsteinCoeffList(pol,var,c,d) :=
196 convert2Bernstein(pol,degree(pol,var),var,c,d);
198 /* Bernstein coefficients */
199 /* computed by using Proposition 10.24 */
200 convert2Bernstein(p,polDeg,var,c,d) :=
201 block([pol,auxPol,transMinusC, conDMinusC, recP, transMinusOne,res,i],
205 if polDeg<degree(pol,var) then ( print("bad degree, d must be more than degree(P)"),
211 polDeg : max(degree(pol,var),polDeg),
213 transMinusC : expand(translated(pol,var,-c)),
214 conDMinusC : expand(contracted(transMinusC,var,d-c)),
216 recP : expand(reciprocal(conDMinusC,var,polDeg)),
218 transMinusOne : expand(translated(recP,var,-1)),
220 auxPol : translated(reciprocal(
221 contracted(translated(
222 pol,var,-c),var,d-c),var,polDeg),var,-1),
223 auxPol : ratsimp(auxPol,var),
225 res : makelist(ratcoeff(auxPol,var,polDeg-i)/
226 binomial(polDeg,i),i,0,polDeg),
231 /* For a given squarefree polynonial SFP of degree p */
232 /* Bernstein coefficients of the polynomial */
233 /* 2^(k*p)*SFP in the Bernstein basis */
234 /* (specialCoeff(l,c,k),specialCoeff(l,c+1,k))) */
235 bernsteinSpecialCoeffList(pol,var,leftEnd,rightEnd) :=
236 bernsteinCoeffList(pol,var,leftEnd,rightEnd);
242 /* --------------------------------------------------- */
243 /* Real root isolation */
245 isListLess(lhs,rhs) :=
246 if length(lhs) = 1 then
247 if length(rhs) = 1 then
252 if length(rhs) = 1 then
258 /* Order Isolating List */
259 isListSort(isList) :=
260 sort(isList,isListLess);
263 isListWithSignsLess(lhs,rhs) :=
264 isListLess(first(lhs),first(rhs));
266 /* Order Isolating list with signs */
267 isListWithSignsSort(isListWithSigns) :=
268 sort(isListWithSigns,isListWithSignsLess);
272 /* Real root isolation in an archimedean real closed field */
273 /* the output is a list of elements of the following form: */
274 /* single point : [p] */
275 /* interval : [[a,b],[c,k]], where c, k are the coeffs in a_{c,k} */
277 /* Aliases for "deCasteljauIsolateRoots..." */
279 /* Aliases for "deCasteljauIsolateRootsGeneral" */
281 deCasteljauIsolateRootsWithARCF(pol,var) := /* ARCF stands for Archimedean Real Closed Field */
282 deCasteljauIsolateRootsGenStruct(pol,var,false);
284 deCasteljauIsolateRootsWithZ(pol,var) :=
285 deCasteljauIsolateRootsGenStruct(pol,var,true);
287 /* Aliases for "deCasteljauIsolateRootsGenStructVerbose" */
289 deCasteljauIsolateRootsGenStruct(pol,var,integer_flag) :=
290 deCasteljauFindRootsGenStruct(pol,var,inf,integer_flag);
292 deCasteljauIsolateRootsBetweenWithARCF(pol,var,a,b) :=
293 deCasteljauFindRootsGenIntGenStructCert(pol,var,inf,a,b,false,false)[1];
295 deCasteljauIsolateRootsBetweenWithZ(pol,var,a,b) :=
296 deCasteljauFindRootsGenIntGenStructCert(pol,var,inf,a,b,true,false)[1];
298 deCasteljauIsolateRootsBetweenWithZCert(pol,var,a,b) :=
299 deCasteljauFindRootsGenIntGenStructCert(pol,var,inf,a,b,true,true);
302 /* Aliases for "deCasteljauFindRootsGeneral..." */
304 /* Aliases for "deCasteljauFindRootsGeneral" */
306 deCasteljauFindRootsWithARCF(pol,var,threshold) :=
307 deCasteljauFindRootsGenStruct(pol,var,threshold,false);
309 deCasteljauFindRootsWithZ(pol,var,threshold) :=
310 deCasteljauFindRootsGenStruct(pol,var,threshold,true);
312 /* Aliases for "deCasteljauFindRootsGenStruct" */
314 deCasteljauFindRootsBetweenWithZ(pol,var,threshold,a,b) :=
315 deCasteljauFindRootsGenIntGenStructCert(pol,var,threshold,a,b,true,false)[1];
317 deCasteljauFindRootsWithZ(pol,var,threshold) :=
318 deCasteljauFindRootsGenStruct(pol,var,threshold,true);
320 deCasteljauFindRootsGenStruct(pol,var,threshold,integer_flag) :=
321 deCasteljauFindRootsGenIntGenStructCert(pol,var,threshold,false,0,integer_flag,false)[1];
323 deCasteljauFindRootsGenStructCert(pol,var,threshold,integer_flag) :=
324 deCasteljauFindRootsGenIntGenStructCert(pol,var,threshold,false,0,integer_flag,true)[1];
326 /* definition de deCasteljauFindRootsGenIntGenStructCert */
328 deCasteljauFindRootsGenIntGenStructCert(pol,var,threshold,a,b,integer_flag,modifCert) :=
329 block([leftEnd,rightEnd,midPoint,n,sqPol,bCoeff,pos,deg,
330 resList,item,sgnCh,splitRes,c,k,count,gcdTest,normFact,searchLeftEnd, searchRightEnd,mod,sg,certificate,P,resCert,bernIntSet,bsplit,lhsSplit, rhsSplit,bernInt],
339 n : discreteLogInBaseTwo(cauchyRootUpperBound(P,var)),
340 searchLeftEnd : -(2^n),
349 sqPol : expand(factor(squareFree(P,var))),
354 bCoeff : bernsteinCoeffList(P,var,searchLeftEnd,searchRightEnd)
358 bCoeff : bernsteinCoeffList(sqPol,var,searchLeftEnd,searchRightEnd)
363 /* normFact is the multiplicative coefficient which makes the berstein coefficients integers*/
367 normFact : apply(lcm,map(denom,bCoeff)),
368 bCoeff : normFact*bCoeff
372 bernIntSet : [[[searchLeftEnd,searchRightEnd],normFact,bCoeff]],
374 while not(bernIntSet=[]) and certificate do
376 item : first(bernIntSet),
377 bernIntSet : rest(bernIntSet),
379 bernInt : first(item),
380 bCoeff : third(item),
382 leftEnd : first(bernInt),
383 rightEnd : second(bernInt),
387 if first(bCoeff)=0 then
390 resCert:[false,[[leftEnd],sqPol],true,false]
394 if last(bCoeff)=0 then
397 resCert:[false,[[rightEnd],sqPol],true,false]
401 sgnCh : signChanges(bCoeff),
402 if (sgnCh = 1) and (rightEnd-leftEnd)<threshold then
404 (if modifCert then /* Loop which is useful for the function in the certificate file */
405 ((certificate : false),
406 resCert : [false,[[leftEnd,rightEnd],sqPol],true,false]
409 resList : endcons([leftEnd,rightEnd],resList)
415 midPoint : (leftEnd+rightEnd)/2,
418 if subst(midPoint,var,pol)=0 then
420 resList : endcons([midPoint],resList)
423 bsplit : bernsteinSplitWithZ(bCoeff,leftEnd,rightEnd,midPoint),
424 lhsSplit : first(bsplit),
426 rhsSplit : second(bsplit),
428 bernIntSet : endcons([[leftEnd,midPoint],
429 normFact,lhsSplit],bernIntSet),
430 bernIntSet : endcons([[midPoint,rightEnd],
431 normFact,rhsSplit],bernIntSet),
433 if rightEnd-midPoint<1 then
435 ( normFact : normFact*2^deg ) /* end if */
440 else ( if modifCert then
441 resCert : endcons([[leftEnd,rightEnd],normFact,bCoeff],resCert)
446 if certificate then (
448 if isListCertSort(resCert)[1][3][1]>0 then
449 return([positive,compressCertificate(isListCertSort(resCert)),0,false,true])
451 return([negative,compressCertificate(isListCertSort(resCert)),0,false,true])
453 return([isListSort(resList),sqPol,false,false])
461 deCasteljauNumberOfRoots(pol,var) :=
462 length(deCasteljauIsolateRoots(pol,var));
464 deCasteljauNumberOfRootsBetween(pol,var,a,b) :=
465 length(deCasteljauIsolateRootsBetween(pol,var,a,b));
467 /* Refine an open interval describing a unique real root */
468 refineRoot(rootInterval,pol,var) :=
469 block([leftEnd,rightEnd,midPoint,n,sqPol,bCoeffList,pos,
470 resList,item,sgnCh,splitRes,c,k,count,gcdTest,
472 leftEnd : rootInterval[1],
473 rightEnd : rootInterval[2],
474 midPoint : (leftEnd+rightEnd)/2,
475 if subst(midPoint,var,pol)=0 then
480 sqPol : expand(factor(squareFree(pol,var))),
483 bCoeffList : bernsteinCoeffList(sqPol,var,leftEnd,rightEnd),
485 splitRes : specialBernsteinSplit(bCoeffList,leftEnd,rightEnd),
488 if signChanges(lhs)=1 then
489 return([leftEnd,midPoint])
491 return([midPoint,rightEnd])
497 /* Finds an intermediate point (already in the right order) */
498 intermidiatePoint(lhs,rhs,poly,var) :=
499 if length(lhs)=1 then
500 if length(rhs) = 1 then
503 if not(lhs[1]=rhs[1]) then
506 intermidiatePoint(lhs,refineRoot(rhs,poly,var),poly,var)
508 if length(rhs)=1 then
509 if not(lhs[2]=rhs[1]) then
512 intermidiatePoint(refineRoot(lhs,poly,var),rhs,poly,var)
514 if not(lhs[2]=rhs[1]) then
520 /* -------------------------------------------------------- */
521 /* Sign or real roots */
523 /* Sign of real roots */
524 /* in an archimedean real closed field */
526 deCasteljauRootsSign(isolListForP,p,q,var) :=
527 block([sfP,sfQ,g,commonPtList,nonCommonPtList,commonInList,nonCommonInList,
528 candList,nCom,sfPCoeffList,gCoeffList,
530 leftEnd,rightEnd,midPt,item,bernG, bernSfP, bernQ,
531 sgnM,sgnL,sgnR, bernSplitSfP, bernSplitG],
535 sfP : expand(factor(squareFree(p,var))),
538 commonPtList : [], /* In the book's notation : N(P) */
540 nonCommonPtList : [],
541 nonCommonInList : [],
542 candList : [], /* In the book's notation : Pos */
544 for i : 1 thru length(isolListForP) do
547 if length(isolListForP[i])=1 then
549 sgnM : sgn(subst(isolListForP[i][1],var,q)),
551 commonPtList : endcons([isolListForP[i],sgnM],commonPtList)
553 nonCommonPtList : endcons([isolListForP[i],sgnM],nonCommonPtList)
558 leftEnd : isolListForP[i][1],
559 rightEnd : isolListForP[i][2],
561 candList : endcons([[bernsteinCoeffList(sfP,var,leftEnd,rightEnd),
562 bernsteinCoeffList(g,var,leftEnd,rightEnd)],
568 while not(candList=[]) do
570 item : first(candList),
572 candList : rest(candList),
574 bernSfP : item[1][1],
575 leftEnd : item[2][1],
576 rightEnd : item[2][2],
578 if signChanges(bernG) = 1 then
579 commonInList : endcons([item[2],0],commonInList)
581 if signChanges(bernG) = 0 then
582 nCom : endcons([bernSfP,[leftEnd,rightEnd]],nCom)
585 midPt : (leftEnd+rightEnd)/2,
586 sgnL : subst(leftEnd,var,sqP),
587 sgnM : subst(midPt,var,sqP),
588 sgnR : subst(rightEnd,var,sqP),
592 if sgn(subst(midPt,var,q)) = 0 then
593 commonPtList : endcons([[midPt],0],commonPtList)
595 nonCommonPtList : endcons([[midPt],sgn(subst(midPt,var,q))],nonPtCommonList)
599 bernSplitSfP : specialBernsteinSplit(bernSfP,leftEnd,rightEnd),
600 bernSplitG : specialBernsteinSplit(bernG,leftEnd,rightEnd),
602 candList : endcons([[bernSplitSfP[1],bernSplitG[1]],
607 candList : endcons([[bernSplitSfP[2],bernSplitG[2]],
618 while not(candList=[]) do
620 item : first(candList),
621 candList : rest(candList),
622 leftEnd : item[2][1],
623 rightEnd : item[2][2],
627 bernQ : bernsteinCoeffList(q,var,leftEnd,rightEnd),
629 if signChanges(bernQ)=0 then
637 nonCommonInList : endcons([[leftEnd,rightEnd],
638 sgn(bernQ[i])],nonCommonInList)
642 midPt : (leftEnd+rightEnd)/2,
643 sgnM : sgn(subst(midPt,var,sfP)),
646 while(bernSfP[i]=0) do
648 sgnL : sgn(bernSfP[i]),
651 while(bernSfP[i]=0) do
653 sgnR : sgn(bernSfP[i]),
657 nonCommonPtList : endcons([[midPt],sgn(subst(midPt,var,q))],nonCommonPtList)
661 candList : endcons([bernsteinCoeffList(sfP,var,leftEnd,midPt),
665 candList : endcons([bernsteinCoeffList(sfP,var,midPt,rightEnd),
672 return([[nonCommonPtList,nonCommonInList],[commonPtList,commonInList]])
676 deCasteljauSignsAtRoots(isolListForP,p,q,var) :=
677 isListWithSignsSort(lambda([l],append(l[1][1],l[1][2],
679 deCasteljauRootsSign(isolListForP,p,q,var)));
682 /* --------------------------------------- */
683 /* Sign Comparison of real roots */
687 /* Rewrite a set of isolating points with signs as intervals and removes the sign */
689 if length(ptList)=0 then
692 cons([ptList[1][1][1],ptList[1][1][1]],makeAsIn(rest(ptList)));
694 /* Rewrite dummy intervals as points */
696 if length(inList)=0 then
699 if inList[1][1]=inList[1][2] then
700 cons([inList[1][1]],makeAsPt(rest(inList)))
702 cons(inList[1],makeAsPt(rest(inList)));
705 /* Removes the sign */
706 removeSign(inList) :=
707 if length(inList)=0 then
710 cons(first(first(inList)),removeSign(rest(inList)));
712 /* Interval Intersection */
713 intersectIn(inList1,inList2) :=
714 block([i,len1,len2, leftEnd1,rightEnd1,leftEnd2,rightEnd2,res],
716 len1 : length(inList1),
717 len2 : length(inList2),
731 leftEnd1 : inList1[i][1],
732 leftEnd2 : inList2[i][1],
733 rightEnd1 : inList1[i][2],
734 rightEnd2 : inList2[i][2],
736 if (leftEnd1<=leftEnd2) and
737 (leftEnd2<=rightEnd1) then
739 res : endcons([leftEnd2,min(rightEnd1,rightEnd2)],res),
743 if (leftEnd2<=leftEnd1) and
744 (leftEnd1<=rightEnd2) then
746 res : endcons([leftEnd1,min(rightEnd1,rightEnd2)],res),
751 print("impossible configuration"),
762 /* Evaluation of the signs of two polynomials at their roots */
763 /* in an archimedean real closed field */
765 deCasteljauEvaluateSignsAtRoots(p,q,var):=
766 block([l,isolP,isolQ,
767 signComPtP,signComInP,signComPtQ,signComInQ,
768 signNComPtP,signNComInP,signNComPtQ,signNComInQ,
769 signP,signQ,signComP,signNComP,signComQ,signNComQ,
770 signComAsInP,signComAsInQ,comIn],
775 isolP : deCasteljauIsolateRoots(p,var),
777 isolQ : deCasteljauIsolateRoots(q,var),
778 signP : deCasteljauRootsSign(isolP,p,q,var),
779 signComP : second(signP),
781 signComPtP : first(signComP),
782 signComInP : second(signComP),
783 signNComP : first(signP),
784 signNComP : sort(append(first(signNComP),second(signNComP))),
786 signQ : deCasteljauRootsSign(isolQ,q,p,var),
787 signComQ : second(signQ),
789 signComPtQ : signComQ[1],
790 signComInQ : signComQ[2],
791 signNComQ : first(signQ),
792 signNComQ : sort(append(first(signNComQ),second(signNComQ))),
794 signComAsInP : sort(append(makeAsIn(signComPtP),removeSign(signComInP))),
795 signComAsInQ : sort(append(makeAsIn(signComPtQ),removeSign(signComInQ))),
797 comIn : makeAsPt(intersectIn(signComAsInP,signComAsInQ)),
798 return([comIn,signNComP,signNComQ])
802 /* Real root sample points */
803 /* for an archimedean real closed field */
804 realSamplePointsARCF(polList) :=
805 block([i,j,listSize,compRes],
806 listSize : length(polList),
807 for i : 1 thru listSize do
808 for j : 1 thru listSize do
809 compRes : realRootComparisonARCF(p,q,var),