1 /*-------------------------------------
3 Package : Certificates of positivity in the simplicial Bernstein basis
7 First version : 07/01/07
11 Updated again: 01/02/2017 (fix on standard_mid global m in standard_mid)
12 --------------------------------------*/
14 /*-------------------------------------
18 Input: List L of the Bernstein expansion of a polynomial P of degree d in k variables
20 Output: True if all the Bernstein coefficients are nonnegative, else false.
22 --------------------------------------*/
27 for i:1 thru length(L) do
29 if L[i]<0 then bool:false
34 /*-------------------------------------
38 Input: List L of the Bernstein expansion of a polynomial P of degree d in k variables
40 Output: True if the Bernstein coefficients satisfy the certificates of positivity, else false.
42 Reminder: the certificate of positivy says that all the Bernstein coefficients are nonnegative,
43 and the coefficients corresponding to the vertices of the simplex are positive.
45 ---------------------------------------*/
51 for i:1 thru length(L) do
53 if L[i]<0 then bool:false
55 for i:1 thru length(som) do
57 if L[som[i]]<=0 then bool:false
62 /*-------------------------------------
68 Output: the minimum of L, together with a corresponding index.
70 --------------------------------------*/
76 for i:2 thru length(L) do
85 /*-------------------------------------
87 Procedure: compositions_leq
89 Input: multiindex gamm
91 Output: list of all the (weak) compositions of the same size as alpha
92 that are lower or equal to gamm componentwise (wrt lexicographic order).
94 --------------------------------------*/
96 compositions_leq(gamm):=
99 if k = 1 then return(makelist([i],i,0,gamm[1])) else
101 l:compositions_leq(rest(gamm,1)),
102 return(create_list(cons(i,l[j]),i,0,gamm[1],j,1,length(l)))
106 /*-------------------------------------
108 Procedure: compositions
110 Input: nonnegative integers n,k
112 Output: list of all the (weak) compositions of n in k nonnegative integers (wrt lexicographic order).
114 --------------------------------------*/
118 if k=1 then return([[n]]) else
122 par:makelist(cons(i,l),l,compositions(n-i,k-1)),
128 /*-------------------------------------
132 Input: a polynomial pol in the variables vars, and a multiindex alpha.
134 Output: coefficient of pol corresponding to the monomial of degree alpha
136 --------------------------------------*/
138 mulcoeff(pol,vars,alpha):=
140 if length(vars)=1 then return(coeff(pol,vars[1],alpha[1])) else
142 return(mulcoeff(coeff(pol,vars[1],alpha[1]),rest(vars,1),rest(alpha,1)))
146 /*-------------------------------------
148 Procedure: simplex2bar
150 Input: a simplex simpl, given as an ordered list of vertices, and a list a variables vars
152 Output: list of the barycentric coordinates associated to simpl (expressed in the variables vars).
154 --------------------------------------*/
156 simplex2bar(simpl,vars):=
157 block([i,j,len,res,l,eq],
159 len: length(simpl[1]),
160 for i : 1 thru len do
162 eq:sum(l[j]*simpl[j+1][i],j,0,len)-vars[i],
165 res:endcons(sum(l[j],j,0,len)-1,res),
166 res:linsolve(res,makelist(l[j],j,0,len)),
167 return(makelist(second(res[j]),j,1,len+1))
170 /*-------------------------------------
174 Input: polynomial P in the variables vars
176 Output: degree (given as a multiindex) of the dominant coefficient of P wrt lexicographic order on the variables vars
178 --------------------------------------*/
181 block([i,l,expo,c,d],
188 c:coeff(c,vars[i],d),
194 /*-------------------------------------
196 Procedure: sparse_pol
198 Input: a polynomial P in the variables vars
200 Output: list of all the monomials that appear in P with a nonzero coefficient
202 --------------------------------------*/
205 block([i,k,reste,d,mon,c,expo],
209 while not(reste=0) do
211 d:dominant(reste,vars),
212 c:mulcoeff(reste,vars,d),
213 reste:reste-c*product(vars[i]**d[i],i,1,k),
219 /*-------------------------------------
221 Procedure: sparse_standard2bern
223 Input: a polynomial P in the variables vars, a nonnegative integer d
225 Output: Bernstein expansion of degree d of P wrt the standard simplex (uses the previous procedure)
227 --------------------------------------*/
229 sparse_standard2bern(P,vars,d):=
230 block([alph,bet,gamm,i,deg,coeff,res,k,mon,multg,multa,expo],
233 expo:sparse_pol(P,vars),
234 for gamm in compositions(d,k+1) do
236 multg:apply(multinomial_coeff,gamm),
240 bet:gamm-cons(0,alph),
241 if apply(min,bet) >= 0 then
243 deg:sum(alph[a],a,1,length(alph)),
244 multa:apply(multinomial_coeff,bet),
245 coeff:coeff+mulcoeff(P,vars,alph)*multa/multg
248 res:endcons(coeff,res)
253 /*-------------------------------------
255 Procedure: monom2bern
257 Input: a polynomial P in the variables vars, a nonnegative integer d and a simplex V (given as the list of its vertices)
259 Output: Bernstein expansion of degree d of P wrt the simplex V (uses the previous procedure)
261 --------------------------------------*/
263 monom2bern(P,V,vars,d):=
264 block([i,j,k,aff,g,varbis,vc],
266 varbis:makelist(concat(vc,i),i,1,k),
267 aff:transpose(apply(matrix,rest(V,1)))-transpose(apply(matrix,makelist(V[1],i,1,k))),
269 g:expand(subst(makelist(vars[i]=aff[i,1],i,1,k),P)),
270 return(sparse_standard2bern(g,varbis,d))
273 /*-------------------------------------
275 Procedure: bern2monom
277 Input: the list L of the Bernstein expansion of degree d of a polynomial P (expressed in the variables vars) wrt a simplex V
279 Output: expression of P in the monomial basis
281 --------------------------------------*/
283 bern2monom(L,V,vars,d):=
286 /*D:concat(makelist(0,i,0,k),makelist(flatten([makelist(0,i,0,j-1),[1],makelist(0,i,j+1,k)]),j,0,k)),*/
287 P:deCasteljau(V,L,d,vars),
291 /*-------------------------------------
293 Procedure: deCasteljau
295 Input: the Bernstein expansion ber of degree deg of a polynomial P wrt to a simplex simpl, and an point M.
297 Output: list of all the items [V,B] where V is a subsimplex of simpl and B the corresponding Bernstein expansion of P,
298 for all subsimplices V of simpl defined by the point M.
300 --------------------------------------*/
302 deCasteljau(simpl,ber,deg,M):=
303 block([i,j,k,alpha,bet,var,l,cmp,res],local(bcastel),
306 bet:subst( makelist( var[j]=M[j],j,1,k), simplex2bar(simpl,var)),
308 for alpha in compositions(deg,k+1) do
310 bcastel[alpha]:ber[j],
315 cmp:compositions(deg-l,k+1),
318 bcastel[alpha]:sum(bet[i+1]*
319 bcastel[append(rest(alpha,-length(alpha)+i),[alpha[i+1]+1],
320 rest(alpha,i+1))],i,0,k)
323 res:makelist([subst([simpl[j+1]=M],simpl),makelist(bcastel[append(makelist(alpha[i],i,1,j),[0],makelist(alpha[i],i,j+2,k+1))],alpha,compositions(deg,k+1))],j,0,k),
327 /*-------------------------------------
329 Procedure: deCasteljauarete
331 Input: the Bernstein expansion ber of degree deg of a polynomial P wrt a simplex simpl = [V_0,...,V_k], indices i,j corresponding to two vertices M_i, M_j of simpl, and a real 0<x<1.
333 Output: list of the Bernstein expansion of degree deg of P wrt the two simplices resulted from the subdivision of simpl at the point M = (1-x)*M_i + x*M_j.
335 --------------------------------------*/
337 deCasteljauarete(simpl,ber,deg,i,j,x):=
338 block([k,alpha,bet,gamm,l,cmp,res,M,p,L,dprime,indi,resi,resj,C],local(bcastel),
340 M:(1-x)*simpl[i]+x*simpl[j],
341 if k<2 then return(deCasteljau(simpl,ber,deg,M)),
343 cmp:compositions(deg,k+1),
346 bcastel[alpha]:ber[p],
349 cmp:compositions(deg,k),
351 cmp:append(cmp,compositions(deg-l,k-1)),
354 dprime:deg-sum(bet[l],l,1,length(bet)),
356 for gamm:0 thru dprime do
358 indi:append(makelist(bet[p],p,1,i-1),[dprime-gamm],makelist(bet[p],p,i,j-2),[gamm],makelist(bet[p],p,j-1,k-1)),
359 L:append(L,[bcastel[indi]])
361 C:deCasteljau([[0],[1]],L,dprime,[x]),
362 for gamm:0 thru dprime do
364 indi:append(makelist(bet[p],p,1,i-1),[dprime-gamm],makelist(bet[p],p,i,j-2),[gamm],makelist(bet[p],p,j-1,k-1)),
365 resi[indi]:C[1][2][gamm+1],
366 resj[indi]:C[2][2][gamm+1]
369 res:[[subst([simpl[i]=M],simpl),makelist(resi[alpha],alpha,compositions(deg,k+1))],[subst([simpl[j]=M],simpl),makelist(resj[alpha],alpha,compositions(deg,k+1))]],
373 /*-------------------------------------
377 Input: two nonnegative integers d and k
379 Output: list of the multiindices labelling the Bernstein coefficients corresponding to the vertices of a simplex
380 among the Bernstein expansion of degree d of a polynomial in k variables (wrt the lexicographic order)
382 --------------------------------------*/
385 block([i,j,som,indii],
390 indii:indii+sum(binomial(d-i+k-1-j,k-1-j),i,1,d-1)+1,
391 som:endcons(indii,som)
396 /*-------------------------------------
400 Input: vector u of IR^k
402 Output: the square of the Euclidean norm of u: ||u||^2
404 --------------------------------------*/
408 return(sum(u[i]^2,i,1,length(u)))
411 /*-------------------------------------
417 Output: indices of two vertices of V that realize the diameter of V
419 --------------------------------------*/
422 block([i,j,k,m,L,indi,r,q],
424 L:create_list(norm(V[i]-V[j]), i, 1, k+1, j, 1, k+1),
427 for i:2 thru length(L) do
436 q:quotient(indi,k+1),
437 if r = 0 then return([min(k+1,q),max(k+1,q)]) else return([min(r,q+1),max(r,q+1)])
440 /*-------------------------------------
444 Input: a polynomial P of degree d in the variables var
446 Output: theoritical lower bound on the minimum of P over the standard simplex, if P is positive on it.
448 --------------------------------------*/
454 tau:length(num2list(max(apply(max,c),-apply(min,c)),2)),
455 return(2^(-(tau+1)*d^(k+1))*d^(-(k+1)*d^k)*binomial(d+k,k+1)^(-d^k*(d-1)))
458 /*-------------------------------------
462 Input: a polynomial P of degree D in variables var
464 Output: list of all the coefficients of P (wrt the lexicographic order on the variables).
466 --------------------------------------*/
471 apply(append,makelist(makelist(subst(makelist(v=0,v,var),ratcoeff(P,product(var[i]^(a[i]),i,1,k))),a,compositions(D-j,k)),j,0,D)
474 /*-------------------------------------
476 Procedure: multiCertificate
478 Input: a polynomial P in the variables vars, a simplex V, a nonnegative integer d, a subdivision method sub (e.g. bisection, bisection_castel, standard_triang2),
479 and a choice for the certificate (pos for a certificate of positivity, nonneg for a certificate of nonnegativity).
483 - if P is positive on the standard simplex :a certificate of positivity for P expressed as a list of items [V,B],
484 where the collection of subsimplices V covers the standard simplex,
485 and B is the corresponding Berstein expansion of degree d of P on each W
487 - if not, an item [M,v] where M is a point of the standard simplex and v is a the value of P at M that is lower than the theoritical bound
488 on the minimum of a positive polynomial
490 Warning: if P is nonnegative but not positive, the computation can take a very long time, due to the theoritical bound, which can be very small.
492 --------------------------------------*/
494 multiCertificate(P,V,vars,d,sub,cert):=
495 block([k,bool,actif,passif,alpha,a,v,arete,w,Delta,m,N0,L,s,res,value,value_new,N,W,l],
498 L:monom2bern(P,V,vars,d),
502 if cert=pos then m:bound(P,vars,d) else m:0,
504 while length(actif)>0 and value[2]>=m do
509 if apply(cert,[v[2],d,k]) then passif:endcons(v,passif)
515 if not(apply(cert,[[l],0,0])) then
521 if length(res)>0 then
525 W:apply(sub,[v[1],v[2],d]),
529 alpha:monmin2(w[2])[2],
530 alpha:compositions(d,k+1)[alpha],
531 N:sum(alpha[i]*w[1][i],i,1,k+1)/d,
532 value_new:subst(makelist(vars[i]=N[i],i,1,k),P),
533 if value_new<value[2] then value:[N,value_new]
541 if length(res)>0 then
543 if length(actif)=0 then
549 /*-------------------------------------
551 Procedure: bisection_castel
553 Input: the Bernstein expansion L of degree d of a polynomial P wrt a simplex V
555 Output: list of the items [W,B] where B is the Bernstein expansion of degree d of P wrt the simplex W,
556 for all the subsimplices W of V generated by the bisection of V at the control point corresponding to
557 the multiindex associated to a minimal Berstein coefficient among L.
559 --------------------------------------*/
561 bisection_castel(V,L,d):=
562 block([arete,w,k,c,j,alpha,N,W,w,res,C],
565 c:compositions(d,k+1),
569 for l:1 thru length(alpha) do
571 if not(alpha[l]=0) then j:endcons([l,alpha[l]],j)
573 if length(j)=2 then return(deCasteljauarete(V,L,d,j[1][1],j[2][1],j[1][2]/d))
576 N:sum(alpha[i]*V[i],i,1,k+1)/d,
577 return(deCasteljau(V,L,d,N))
581 /*-------------------------------------
585 Input: the Bernstein expansion L of degree d of a polynomial P wrt a simplex V
587 Output: list of the items [W,B] where B is the Bernstein expansion of degree d of P wrt the simplex W,
588 for the two subsimplices W of V generated by the bisection of V at the midpoint of a diameter of V.
590 --------------------------------------*/
595 return(deCasteljauarete(V,L,d,min(arete[1],arete[2]),max(arete[1],arete[2]),1/2))
598 /*-------------------------------------
600 Procedure: bisection_max
602 Input: the Bernstein expansion L of degree d of a polynomial P wrt a simplex V
604 Output: list of the items [W,B] where B is the Bernstein expansion of degree d of P wrt the simplex W,
605 for the two subsimplices W of V generated by the bisection of V at a point of a diameter of V
606 "maximizing" the volume of one subsimplex satisfying the certificate of positivity (cert= pos) or nonnegativity (cert=nonneg)
608 --------------------------------------*/
610 bisection_max(V,L,d,cert):=
611 block([arete,W,i,n,k,bool,res],
617 bool:apply(cert,[L,d,k]),
618 while ((not bool) and i<n/2) do
620 W:deCasteljauarete(V,L,d,min(arete[1],arete[2]),max(arete[1],arete[2]),i/n),
621 if (apply(cert,[W[1][2],d,k])) then
627 W:deCasteljauarete(V,L,d,min(arete[1],arete[2]),max(arete[1],arete[2]),(n-i)/n),
628 if (apply(cert,[W[2][2],d,k])) then
635 if i>=n/2 then return(deCasteljauarete(V,L,d,min(arete[1],arete[2]),max(arete[1],arete[2]),1/2)) else return(res)
638 bisection_max_pos(V,L,d):=
640 return(bisection_max(V,L,d,pos))
644 bisection_max_nonneg(V,L,d):=
646 return(bisection_max(V,L,d,nonneg))
650 /*-------------------------------------
654 Input: two nonnegative integers n and b
656 Output: the expression of n in base b.
658 --------------------------------------*/
660 num2list(n,b):=block([lst:[],a:n],
661 for i:1 while a#0 do (
662 lst:cons(?mod(a,b),lst),
668 /*-------------------------------------
670 Procedure: standard_triang2
672 Input: list L of the Bernstein expansion of degree d of a polynomial P wrt to a simplex V
674 Output: list of all the items [W,B] where W is a subsimplex of V and B the corresponding Bernstein expansion of degree d of P,
675 for all the subsimplices W of the standard triangulation of degree 2 of V.
677 --------------------------------------*/
680 block([M,m:make_array('any,d,k+1),n,y,i,j,color,t,s],
682 s:matrix(makelist(1/d,i,1,d)),
683 for n:0 thru d^k-1 do
686 y:append(makelist(0,i,1,k-length(y)),y),
693 (if y[j]=i then color:color+1),
697 t:cons(apply(matrix,makelist(makelist(m[i,j],j,0,k),i,0,d-1)),t)
706 return(makelist(makelist(sum(V[t[i,j]+1],i,1,d)/2,j,1,k+1),t,T))
709 standard_triang(V,P,vars,d,l):=
710 block([i,j,k,T,L,res,t],
716 i:monom2bern(P,t,vars,d),
722 standard_triang2(V,L,d):=
723 block([P,k,varbis,vc],
725 varbis::makelist(concat(vc,i),i,1,k),
726 P:bern2monom(L,V,varbis,d),
727 return(standard_triang(V,P,varbis,d,2))
730 /*-------------------------------------
734 Input: Bernstein expansion B of degree d of a polynomial P wrt a simplex V
736 Output: List of all the second differences of P.
738 --------------------------------------*/
741 block([i,j,k,alpha,bet,gam,var,l,cmp,res,e],local(bcastel),
748 e[i+1]:append(makelist(0,j,0,i-1),[1],makelist(0,j,i+1,k))
750 for alpha in compositions(d,k+1) do
755 for gam in compositions(d-2,k+1) do
759 res:endcons(bcastel[gam+e[1]+e[j]]+bcastel[gam+e[k+1]+e[j+1]]-bcastel[gam+e[k+1]+e[j]]-bcastel[gam+e[1]+e[j+1]],res)
765 res:endcons(bcastel[gam+e[i+1]+e[j]]+bcastel[gam+e[i]+e[j+1]]-bcastel[gam+e[i]+e[j]]-bcastel[gam+e[i+1]+e[j+1]],res)
769 res:max(apply(max,res),-apply(min,res)),
773 /*-------------------------------------
775 Procedure: random_color
779 Output: code of a random color
781 --------------------------------------*/
785 randcol:['1,'2,'3,'4,'5,'6,'7,'8,'9,'0,'A,'B,'C,'D,'E,'F],
786 concat("#",randcol[random(16)+1],randcol[random(16)+1],randcol[random(16)+1],randcol[random(16)+1],randcol[random(16)+1],randcol[random(16)+1])
789 /*-------------------------------------
791 Procedure: drawMultiCerticificate
793 Input: Output L of multiCertificate in dimension 2 when a polynomial P has been proven to be positive, and an integer s
795 Output: Vizualization of the subsimplices generated by multiCertificate.
796 The size of the image is defined by s (usually 500).
798 --------------------------------------*/
802 drawMultiCertificate(L,s):=
804 t:concat(length(L)," subsimplices"),
805 if length(L[1]) = 2 then
807 gone:append([dimensions=[s,s],xtics=false,ytics=false,axis_bottom=false,axis_left=false,axis_top=false,axis_right=false,colorbox=false,title=t],flatten(makelist([fill_color=random_color(),polygon(L[i][1])],i,1,length(L))))
811 gone:append([dimensions=[s,s],xtics=false,ytics=false,axis_bottom=false,axis_left=false,axis_top=false,axis_right=false,colorbox=false,fill_color=red, title=t],flatten(makelist([polygon(L[i])],i,1,length(L))))
816 /*-------------------------------------
818 Procedure: wxdrawMultiCerticificate
820 Same procedure as drawMultiCertificate, except that the vizualization is generated inside wxMaxima
822 --------------------------------------*/
824 wxdrawMultiCertificate(L,s):=
826 t:concat(length(L)," subsimplices"),
827 if length(L[1]) = 2 then
829 gone:append([dimensions=[s,s],xtics=false,ytics=false,axis_bottom=false,axis_left=false,axis_top=false,axis_right=false,colorbox=false,color=black],flatten(makelist([fill_color=white,polygon(L[i][1])],i,1,length(L))))
833 gone:append([dimensions=[s,s],xtics=false,ytics=false,axis_bottom=false,axis_left=false,axis_top=false,axis_right=false,colorbox=false,fill_color=white,color=black],flatten(makelist([polygon(L[i])],i,1,length(L))))
835 apply(wxdraw2d,gone),