########################################################################## #We implement a class in Sage for piecewise polynomial functions, using a #newly developed canonical form. # # # # # # # # #First of all, some tools ########################################################################## from sage.rings.polynomial.real_roots import * def IsGreaterRoot(P,i,intP,Q,j,intQ): """ True if the only root in intP is grater than the only root in intQ and isolating intervals THIS IS A SUBROUTINE FOR THE MAIN METHODS OF THE PACKAGE, WHERE PRECONDITIONS ARE CONTROLLED. USE IT ALONE AT YOUR OWN RISK. """ # print [P,i,intP,Q,j,intQ] if intP[0]>=intQ[1]: return [True,intP,intQ] if intQ[0]>=intP[1]: return [False,intP,intQ] if intP[0]==intP[1]: if sign(Q.__call__(intP[0]))*sign(Q.__call__(intQ[1]))>0: return [True,intP,[intQ[0],intP[0]]] else: return [False, intP, [intP[0],intQ[1]]] intersInterv=[max(intP[0],intQ[0]),min(intP[1],intQ[1])] if sign(P.__call__(intersInterv[0]))*sign(P.__call__(intersInterv[1]))>0: if sign(P.__call__(intersInterv[1]))==sign(P.__call__(intP[1])): #This means that the root of P is to the left of the intersection interval, so is lesser return [False ,[intP[0],intersInterv[0]],intQ] else: #This means that the root of P is to the right of the intersection interval, so is greater return [True, [intersInterv[1],intP[1]],intQ] while not Q.__call__(intersInterv[0])*Q.__call__(intersInterv[1])>0: #Now we will always keep the root of P in the shrinking intersInterv #It is easy to see that, if the interval has length=0, we will not enter this loop midpt=(intersInterv[0]+intersInterv[1])/2 if sign(P.__call__(intersInterv[1]))==sign(P.__call__(midpt)): #the root is in the first half of the interval intersInterv[1]=midpt else: intersInterv[0]=midpt if sign(Q.__call__(intersInterv[1]))==sign(Q.__call__(intQ[1])): #This means that the root of Q is to the left of the intersection interval, so is lesser return [True, intersInterv, [intQ[0],intersInterv[0]] ] else: #This means that the root of Q is to the right of the intersection interval, so is greater return [False, intersInterv, [intersInterv[1],intQ[1]] ] ########################################################################## #Now, the classes # ########################################################################## class CanonicalPiecewisePolynomialFunction(): """ Piecewise polynomial functions with rational coefficients in canonical form. """ def __init__(self,v): if not v.is_symbol(): print 'Argument is supposed to be a variable' return self.var=v self.ring=PolynomialRing(QQ,v) self.Polys=[] self.indices=[] self.coeffs=[] self.interv=[] self.FullPol=self.ring(0) def __repr__(self): result=self.FullPol.__repr__() for i in range(len(self.Polys)): result+='\n+('+self.coeffs[i].__repr__()+')*C_'+str(self.indices[i])+'('+self.Polys[i].__repr__()+')' return result def __add__(self,other): if other in self.ring: result=CanonicalPiecewisePolynomialFunction(self.var) p=self.ring(other) result.FullPol=self.FullPol+p result.Polys=deepcopy(self.Polys) result.indices=deepcopy(self.indices) result.coeffs=deepcopy(self.coeffs) result.interv=deepcopy(self.interv) return result if not self.ring is other.ring: print 'Semipolynomials on different variables' return # result=deepcopy(self) result=CanonicalPiecewisePolynomialFunction(self.var) result.Polys=deepcopy(self.Polys) result.indices=deepcopy(self.indices) result.coeffs=deepcopy(self.coeffs) result.interv=deepcopy(self.interv) result.FullPol=self.FullPol+other.FullPol for i in range(len(other.Polys)): j=0 contin=(jself.interv[i][1]: result+=self.Polys[i].__call__(number)*cffcnt elif number>self.interv[i][0]: if sign(self.Polys[i].__call__(number))==(-1)^(self.indices[i]+self.Polys[i].degree()): result+=self.Polys[i].__call__(number)*cffcnt return result class CiP(CanonicalPiecewisePolynomialFunction): """ This class is for C_i(P) """ def __init__(self,i,P,v): if not v.is_symbol(): print 'Third argument is supposed to be a variable' return if not P in PolynomialRing(QQ,v): print 'Second argument is expected to be an univariate polynomial in the third argument with rational coefficients' return if not i in NN: print 'First argument is expected to be a nonnegative integer' return self.var=v self.ring=PolynomialRing(QQ,self.var) p=self.ring(P) #Since we want this to be done soon, we do not factor the polynomial P yet #Maybe for the next version... if not p.is_irreducible(): # print 'second argument is supposed to be an irreducible polynomial' interv=real_roots(p) if i>len(interv): #We have zero self.Polys=[] self.indices=[] self.coeffs=[] self.interv=[] self.FullPol=0 return elif i==0: self.Polys=[] self.indices=[] self.coeffs=[] self.interv=[] self.FullPol=p return fac=p.factor()[:] for l in range(len(interv)): interv[l]=deepcopy(interv[l][0]) # print p,fac,i,interv for k in range(len(fac)): # print k, interv[i-1] if fac[k][0].__call__(interv[i-1][0])*fac[k][0].__call__(interv[i-1][1])<0: l=k inew=1 for k in range(i-1): if fac[l][0].__call__(interv[k][0])*fac[l][0].__call__(interv[k][1])<0: inew+=1 # print p.quo_rem(fac[l][0])[0]*CiP(inew,fac[l][0],self.var) aux=p.quo_rem(fac[l][0])[0]*CiP(inew,fac[l][0],self.var) self.Polys=aux.Polys self.indices=aux.indices self.coeffs=aux.coeffs self.interv=aux.interv self.FullPol=aux.FullPol return #p.quo_rem(fac[l][0])[0]*CiP(inew,fac[l][0],self.var) #der=P.diff(self.var) #g=gcd(P,der) #q=P.quo_rem(g)[0] lc=p.leading_coefficient() interv=real_roots(p) for l in range(len(interv)): interv[l]=deepcopy(interv[l][0]) if i>len(interv): #We have zero self.Polys=[] self.indices=[] self.coeffs=[] self.interv=[] self.FullPol=0 elif i==0: self.Polys=[] self.indices=[] self.coeffs=[] self.interv=[] self.FullPol=p else: self.Polys=[p/lc] self.indices=[i] self.coeffs=[self.ring(lc)] self.interv=[[interv[i-1][0],interv[i-1][1]]] self.FullPol=0 print 'Introduce CiP(i=integer,p=polynomial,x=variable) to create a piecewise polynomial funtion' print 'valued 0 before the i-th root of p(x) and as p after such root' print 'Before, you need to have the variable defined, and p must be irreducible' print 'One can sum, multiply and compose this kind of objects'