/usr/share/axiom-20170501/src/algebra/SHP.spad is in axiom-source 20170501-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | )abbrev package SHP SturmHabichtPackage
++ Author: Lalo Gonzalez-Vega
++ Date Created: 1994?
++ Date Last Updated: 30 January 1996
++ Description:
++ This package produces functions for counting etc. real roots of univariate
++ polynomials in x over R, which must be an OrderedIntegralDomain
SturmHabichtPackage(R,x) : SIG == CODE where
R: OrderedIntegralDomain
x: Symbol
UP ==> UnivariatePolynomial
L ==> List
INT ==> Integer
NNI ==> NonNegativeInteger
SIG ==> with
subresultantSequence : (UP(x,R),UP(x,R)) -> L UP(x,R)
++ subresultantSequence(p1,p2) computes the (standard)
++ subresultant sequence of p1 and p2
SturmHabichtSequence : (UP(x,R),UP(x,R)) -> L UP(x,R)
++ SturmHabichtSequence(p1,p2) computes the Sturm-Habicht
++ sequence of p1 and p2
SturmHabichtCoefficients : (UP(x,R),UP(x,R)) -> L R
++ SturmHabichtCoefficients(p1,p2) computes the principal
++ Sturm-Habicht coefficients of p1 and p2
SturmHabicht : (UP(x,R),UP(x,R)) -> INT
++ SturmHabicht(p1,p2) computes c_{+}-c_{-} where
++ c_{+} is the number of real roots of p1 with p2>0 and c_{-}
++ is the number of real roots of p1 with p2<0. If p2=1 what
++ you get is the number of real roots of p1.
countRealRoots:(UP(x,R)) -> INT
++ countRealRoots(p) says how many real roots p has
if R has GcdDomain then
SturmHabichtMultiple : (UP(x,R),UP(x,R)) -> INT
++ SturmHabichtMultiple(p1,p2) computes c_{+}-c_{-} where
++ c_{+} is the number of real roots of p1 with p2>0 and c_{-}
++ is the number of real roots of p1 with p2<0. If p2=1 what
++ you get is the number of real roots of p1.
countRealRootsMultiple : (UP(x,R)) -> INT
++ countRealRootsMultiple(p) says how many real roots p has,
++ counted with multiplicity
CODE ==> add
p1,p2: UP(x,R)
Ex ==> OutputForm
import OutputForm
subresultantSequenceBegin(p1,p2):L UP(x,R) ==
d1:NNI:=degree(p1)
d2:NNI:=degree(p2)
n:NNI:=(d1-1)::NNI
d2 = n =>
Pr:UP(x,R):=pseudoRemainder(p1,p2)
append([p1,p2]::L UP(x,R),[Pr]::L UP(x,R))
d2 = (n-1)::NNI =>
Lc1:UP(x,R):=leadingCoefficient(p1)*leadingCoefficient(p2)*p2
Lc2:UP(x,R):=-leadingCoefficient(p1)*pseudoRemainder(p1,p2)
append([p1,p2]::L UP(x,R),[Lc1,Lc2]::L UP(x,R))
LSubr:L UP(x,R):=[p1,p2]
in1:INT:=(d2+1)::INT
in2:INT:=(n-1)::INT
for i in in1..in2 repeat
LSubr:L UP(x,R):=append(LSubr::L UP(x,R),[0]::L UP(x,R))
c1:R:=(leadingCoefficient(p1)*leadingCoefficient(p2))**((n-d2)::NNI)
Lc1:UP(x,R):=monomial(c1,0)*p2
Lc2:UP(x,R):=
(-leadingCoefficient(p1))**((n-d2)::NNI)*pseudoRemainder(p1,p2)
append(LSubr::L UP(x,R),[Lc1,Lc2]::L UP(x,R))
subresultantSequenceNext(LcsI:L UP(x,R)):L UP(x,R) ==
p2:UP(x,R):=last LcsI
p1:UP(x,R):=first rest reverse LcsI
d1:NNI:=degree(p1)
d2:NNI:=degree(p2)
in1:NNI:=(d1-1)::NNI
d2 = in1 =>
pr1:UP(x,R):=
(pseudoRemainder(p1,p2) exquo (leadingCoefficient(p1))**2)::UP(x,R)
append(LcsI:L UP(x,R),[pr1]:L UP(x,R))
d2 < in1 =>
c1:R:=leadingCoefficient(p1)
pr1:UP(x,R):=
(leadingCoefficient(p2)**((in1-d2)::NNI)*p2 exquo
c1**((in1-d2)::NNI))::UP(x,R)
pr2:UP(x,R):=
(pseudoRemainder(p1,p2) exquo (-c1)**((in1-d2+2)::NNI))::UP(x,R)
LSub:L UP(x,R):=[pr1,pr2]
for k in ((d2+1)::INT)..((in1-1)::INT) repeat
LSub:L UP(x,R):=append([0]:L UP(x,R),LSub:L UP(x,R))
append(LcsI:L UP(x,R),LSub:L UP(x,R))
subresultantSequenceInner(p1,p2):L UP(x,R) ==
Lin:L UP(x,R):=subresultantSequenceBegin(p1:UP(x,R),p2:UP(x,R))
indf:NNI:= if not(Lin.last::UP(x,R) = 0) then degree(Lin.last::UP(x,R))
else 0
while not(indf = 0) repeat
Lin:L UP(x,R):=subresultantSequenceNext(Lin:L UP(x,R))
indf:NNI:= if not(Lin.last::UP(x,R)=0) then degree(Lin.last::UP(x,R))
else 0
for j in #(Lin:L UP(x,R))..degree(p1) repeat
Lin:L UP(x,R):=append(Lin:L UP(x,R),[0]:L UP(x,R))
Lin
-- Computation of the subresultant sequence Sres(j)(P,p,Q,q) when:
-- deg(P) = p and deg(Q) = q and p > q
subresultantSequence(p1,p2):L UP(x,R) ==
p:NNI:=degree(p1)
q:NNI:=degree(p2)
List1:L UP(x,R):=subresultantSequenceInner(p1,p2)
List2:L UP(x,R):=[p1,p2]
c1:R:=leadingCoefficient(p1)
for j in 3..#(List1) repeat
Pr0:UP(x,R):=List1.j
Pr1:UP(x,R):=(Pr0 exquo c1**((p-q-1)::NNI))::UP(x,R)
List2:L UP(x,R):=append(List2:L UP(x,R),[Pr1]:L UP(x,R))
List2
-- Computation of the delta function:
delta(int1:NNI):R ==
(-1)**((int1*(int1+1) exquo 2)::NNI)
-- Computation of the Sturm-Habicht sequence of two polynomials P and Q
-- in R[x] where R is an ordered integral domaine
polsth1(p1,p:NNI,p2,q:NNI,c1:R):L UP(x,R) ==
sc1:R:=(sign(c1))::R
Pr1:UP(x,R):=pseudoRemainder(differentiate(p1)*p2,p1)
Pr2:UP(x,R):=(Pr1 exquo c1**(q::NNI))::UP(x,R)
c2:R:=leadingCoefficient(Pr2)
r:NNI:=degree(Pr2)
Pr3:UP(x,R):=monomial(sc1**((p-r-1)::NNI),0)*p1
Pr4:UP(x,R):=monomial(sc1**((p-r-1)::NNI),0)*Pr2
Listf:L UP(x,R):=[Pr3,Pr4]
if r < p-1 then
Pr5:UP(x,R):=monomial(delta((p-r-1)::NNI)*c2**((p-r-1)::NNI),0)*Pr2
for j in ((r+1)::INT)..((p-2)::INT) repeat
Listf:L UP(x,R):=append(Listf:L UP(x,R),[0]:L UP(x,R))
Listf:L UP(x,R):=append(Listf:L UP(x,R),[Pr5]:L UP(x,R))
if Pr1=0 then List1:L UP(x,R):=Listf
else List1:L UP(x,R):=subresultantSequence(p1,Pr2)
List2:L UP(x,R):=[]
for j in 0..((r-1)::INT) repeat
Pr6:UP(x,R):=monomial(delta((p-j-1)::NNI),0)*List1.((p-j+1)::NNI)
List2:L UP(x,R):=append([Pr6]:L UP(x,R),List2:L UP(x,R))
append(Listf:L UP(x,R),List2:L UP(x,R))
polsth2(p1,p:NNI,p2,q:NNI,c1:R):L UP(x,R) ==
sc1:R:=(sign(c1))::R
Pr1:UP(x,R):=monomial(sc1,0)*p1
Pr2:UP(x,R):=differentiate(p1)*p2
Pr3:UP(x,R):=monomial(sc1,0)*Pr2
Listf:L UP(x,R):=[Pr1,Pr3]
List1:L UP(x,R):=subresultantSequence(p1,Pr2)
List2:L UP(x,R):=[]
for j in 0..((p-2)::INT) repeat
Pr4:UP(x,R):=monomial(delta((p-j-1)::NNI),0)*List1.((p-j+1)::NNI)
Pr5:UP(x,R):=(Pr4 exquo c1)::UP(x,R)
List2:L UP(x,R):=append([Pr5]:L UP(x,R),List2:L UP(x,R))
append(Listf:L UP(x,R),List2:L UP(x,R))
polsth3(p1,p:NNI,p2,q:NNI,c1:R):L UP(x,R) ==
sc1:R:=(sign(c1))::R
q1:NNI:=(q-1)::NNI
v:NNI:=(p+q1)::NNI
Pr1:UP(x,R):=monomial(delta(q1::NNI)*sc1**((q+1)::NNI),0)*p1
Listf:L UP(x,R):=[Pr1]
List1:L UP(x,R):=subresultantSequence(differentiate(p1)*p2,p1)
List2:L UP(x,R):=[]
for j in 0..((p-1)::NNI) repeat
Pr2:UP(x,R):=monomial(delta((v-j)::NNI),0)*List1.((v-j+1)::NNI)
Pr3:UP(x,R):=(Pr2 exquo c1)::UP(x,R)
List2:L UP(x,R):=append([Pr3]:L UP(x,R),List2:L UP(x,R))
append(Listf:L UP(x,R),List2:L UP(x,R))
SturmHabichtSequence(p1,p2):L UP(x,R) ==
p:NNI:=degree(p1)
q:NNI:=degree(p2)
c1:R:=leadingCoefficient(p1)
c1 = 1 or q = 1 => polsth1(p1,p,p2,q,c1)
q = 0 => polsth2(p1,p,p2,q,c1)
polsth3(p1,p,p2,q,c1)
-- Computation of the Sturm-Habicht principal coefficients of two
-- polynomials P and Q in R[x] where R is an ordered integral domain
SturmHabichtCoefficients(p1,p2):L R ==
List1:L UP(x,R):=SturmHabichtSequence(p1,p2)
qp:NNI:=#(List1)::NNI
[coefficient(p,(qp-j)::NNI) for p in List1 for j in 1..qp]
-- Computation of the number of sign variations of a list of non zero
-- elements in an ordered integral domain
variation(Lsig:L R):INT ==
size?(Lsig,1) => 0
elt1:R:=first Lsig
elt2:R:=Lsig.2
sig1:R:=(sign(elt1*elt2))::R
List1:L R:=rest Lsig
sig1 = 1 => variation List1
1+variation List1
-- Computation of the number of sign permanences of a list of non zero
-- elements in an ordered integral domain
permanence(Lsig:L R):INT ==
size?(Lsig,1) => 0
elt1:R:=first Lsig
elt2:R:=Lsig.2
sig1:R:=(sign(elt1*elt2))::R
List1:L R:=rest Lsig
sig1 = -1 => permanence List1
1+permanence List1
-- Computation of the functional W which works over a list of elements
-- in an ordered integral domain, with non zero first element
qzeros(Lsig:L R):L R ==
while last Lsig = 0 repeat
Lsig:L R:=reverse rest reverse Lsig
Lsig
epsil(int1:NNI,elt1:R,elt2:R):INT ==
int1 = 0 => 0
odd? int1 => 0
ct1:INT:=if elt1 > 0 then 1 else -1
ct2:INT:=if elt2 > 0 then 1 else -1
ct3:NNI:=(int1 exquo 2)::NNI
ct4:INT:=(ct1*ct2)::INT
((-1)**(ct3::NNI))*ct4
numbnce(Lsig:L R):NNI ==
null Lsig => 0
eltp:R:=Lsig.1
eltp = 0 => 0
1 + numbnce(rest Lsig)
numbce(Lsig:L R):NNI ==
null Lsig => 0
eltp:R:=Lsig.1
not(eltp = 0) => 0
1 + numbce(rest Lsig)
wfunctaux(Lsig:L R):INT ==
null Lsig => 0
List2:L R:=[]
List1:L R:=Lsig:L R
cont1:NNI:=numbnce(List1:L R)
for j in 1..cont1 repeat
List2:L R:=append(List2:L R,[first List1]:L R)
List1:L R:=rest List1
ind2:INT:=0
cont2:NNI:=numbce(List1:L R)
for j in 1..cont2 repeat
List1:L R:=rest List1
ind2:INT:=epsil(cont2:NNI,last List2,first List1)
ind3:INT:=permanence(List2:L R)-variation(List2:L R)
ind4:INT:=ind2+ind3
ind4+wfunctaux(List1:L R)
wfunct(Lsig:L R):INT ==
List1:L R:=qzeros(Lsig:L R)
wfunctaux(List1:L R)
-- Computation of the integer number:
-- #[{a in Rc(R)/P(a)=0 Q(a)>0}] - #[{a in Rc(R)/P(a)=0 Q(a)<0}]
-- where:
-- - R is an ordered integral domain,
-- - Rc(R) is the real clousure of R,
-- - P and Q are polynomials in R[x],
-- - by #[A] we note the cardinal of the set A
-- In particular:
-- - SturmHabicht(P,1) is the number of "real" roots of P,
-- - SturmHabicht(P,Q**2) is the number of "real" roots of P making Q neq 0
SturmHabicht(p1,p2):INT ==
p2 = 0 => 0
degree(p1:UP(x,R)) = 0 => 0
List1:L UP(x,R):=SturmHabichtSequence(p1,p2)
qp:NNI:=#(List1)::NNI
wfunct [coefficient(p,(qp-j)::NNI) for p in List1 for j in 1..qp]
countRealRoots(p1):INT == SturmHabicht(p1,1)
if R has GcdDomain then
SturmHabichtMultiple(p1,p2):INT ==
p2 = 0 => 0
degree(p1:UP(x,R)) = 0 => 0
SH:L UP(x,R):=SturmHabichtSequence(p1,p2)
qp:NNI:=#(SH)::NNI
ans:= wfunct [coefficient(p,(qp-j)::NNI) for p in SH for j in 1..qp]
SH:=reverse SH
while first SH = 0 repeat SH:=rest SH
degree first SH = 0 => ans
-- OK: it probably wasn't square free, so this item is probably the
-- gcd of p1 and p1'
-- unless p1 and p2 have a factor in common (naughty!)
differentiate(p1) exquo first SH case UP(x,R) =>
-- it was the gcd of p1 and p1'
ans+SturmHabichtMultiple(first SH,p2)
sqfr:=factorList squareFree p1
#sqfr = 1 and sqfr.first.xpnt=1 => ans
reduce("+",[f.xpnt*SturmHabicht(f.fctr,p2) for f in sqfr])
countRealRootsMultiple(p1):INT == SturmHabichtMultiple(p1,1)
|