/usr/share/axiom-20170501/src/algebra/INTALG.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 | )abbrev package INTALG AlgebraicIntegrate
++ Author: Manuel Bronstein
++ Date Created: 1987
++ Date Last Updated: 19 May 1993
++ Description:
++ This package provides functions for integrating a function
++ on an algebraic curve.
AlgebraicIntegrate(R0, F, UP, UPUP, R) : SIG == CODE where
R0 : Join(OrderedSet, IntegralDomain, RetractableTo Integer)
F : Join(AlgebraicallyClosedField, FunctionSpace R0)
UP : UnivariatePolynomialCategory F
UPUP : UnivariatePolynomialCategory Fraction UP
R : FunctionFieldCategory(F, UP, UPUP)
SE ==> Symbol
Z ==> Integer
Q ==> Fraction Z
SUP ==> SparseUnivariatePolynomial F
QF ==> Fraction UP
GP ==> LaurentPolynomial(F, UP)
K ==> Kernel F
IR ==> IntegrationResult R
UPQ ==> SparseUnivariatePolynomial Q
UPR ==> SparseUnivariatePolynomial R
FRQ ==> Factored UPQ
FD ==> FiniteDivisor(F, UP, UPUP, R)
FAC ==> Record(factor:UPQ, exponent:Z)
LOG ==> Record(scalar:Q, coeff:UPR, logand:UPR)
DIV ==> Record(num:R, den:UP, derivden:UP, gd:UP)
FAIL0 ==> error "integrate: implementation incomplete (constant residues)"
FAIL1==> error "integrate: implementation incomplete (non-algebraic residues)"
FAIL2 ==> error "integrate: implementation incomplete (residue poly has multiple non-linear factors)"
FAIL3 ==> error "integrate: implementation incomplete (has polynomial part)"
NOTI ==> error "Not integrable (provided residues have no relations)"
SIG ==> with
algintegrate : (R, UP -> UP) -> IR
++ algintegrate(f, d) integrates f with respect to the derivation d.
palgintegrate : (R, UP -> UP) -> IR
++ palgintegrate(f, d) integrates f with respect to the derivation d.
++ Argument f must be a pure algebraic function.
palginfieldint : (R, UP -> UP) -> Union(R, "failed")
++ palginfieldint(f, d) returns an algebraic function g
++ such that \spad{dg = f} if such a g exists, "failed" otherwise.
++ Argument f must be a pure algebraic function.
CODE ==> add
import FD
import DoubleResultantPackage(F, UP, UPUP, R)
import PointsOfFiniteOrder(R0, F, UP, UPUP, R)
import AlgebraicHermiteIntegration(F, UP, UPUP, R)
import InnerCommonDenominator(Z, Q, List Z, List Q)
import FunctionSpaceUnivariatePolynomialFactor(R0, F, UP)
import PolynomialCategoryQuotientFunctions(IndexedExponents K,
K, R0, SparseMultivariatePolynomial(R0, K), F)
F2R : F -> R
F2UPR : F -> UPR
UP2SUP : UP -> SUP
SUP2UP : SUP -> UP
UPQ2F : UPQ -> UP
univ : (F, K) -> QF
pLogDeriv : (LOG, R -> R) -> R
nonLinear : List FAC -> Union(FAC, "failed")
mkLog : (UP, Q, R, F) -> List LOG
R2UP : (R, K) -> UPR
alglogint : (R, UP -> UP) -> Union(List LOG, "failed")
palglogint : (R, UP -> UP) -> Union(List LOG, "failed")
trace00 : (DIV, UP, List LOG) -> Union(List LOG,"failed")
trace0 : (DIV, UP, Q, FD) -> Union(List LOG, "failed")
trace1 : (DIV, UP, List Q, List FD, Q) -> Union(List LOG, "failed")
nonQ : (DIV, UP) -> Union(List LOG, "failed")
rlift : (F, K, K) -> R
varRoot? : (UP, F -> F) -> Boolean
algintexp : (R, UP -> UP) -> IR
algintprim : (R, UP -> UP) -> IR
dummy:R := 0
dumx := kernel(new()$SE)$K
dumy := kernel(new()$SE)$K
F2UPR f == F2R(f)::UPR
F2R f == f::UP::QF::R
algintexp(f, derivation) ==
d := (c := integralCoordinates f).den
v := c.num
vp:Vector(GP) := new(n := #v, 0)
vf:Vector(QF) := new(n, 0)
for i in minIndex v .. maxIndex v repeat
r := separate(qelt(v, i) / d)$GP
qsetelt_!(vf, i, r.fracPart)
qsetelt_!(vp, i, r.polyPart)
ff := represents(vf, w := integralBasis())
h := HermiteIntegrate(ff, derivation)
p := represents(
map((x1:GP):QF+->convert(x1)@QF, vp)$VectorFunctions2(GP, QF), w)
zero?(h.logpart) and zero? p => h.answer::IR
(u := alglogint(h.logpart, derivation)) case "failed" =>
mkAnswer(h.answer, empty(), [[p + h.logpart, dummy]])
zero? p => mkAnswer(h.answer, u::List(LOG), empty())
FAIL3
algintprim(f, derivation) ==
h := HermiteIntegrate(f, derivation)
zero?(h.logpart) => h.answer::IR
(u := alglogint(h.logpart, derivation)) case "failed" =>
mkAnswer(h.answer, empty(), [[h.logpart, dummy]])
mkAnswer(h.answer, u::List(LOG), empty())
-- checks whether f = +/[ci (ui)'/(ui)]
-- f dx must have no pole at infinity
palglogint(f, derivation) ==
rec := algSplitSimple(f, derivation)
ground?(r := doubleResultant(f, derivation)) => "failed"
-- r(z) has roots which are the residues of f at all its poles
(u := qfactor r) case "failed" => nonQ(rec, r)
(fc := nonLinear(lf := factors(u::FRQ))) case "failed" => FAIL2
-- at this point r(z) = fc(z) (z - b1)^e1 .. (z - bk)^ek
-- where the ri's are rational numbers, and fc(z) is arbitrary
-- (fc can be linear too)
-- la = [b1....,bk] (all rational residues)
la := [- coefficient(q.factor, 0) for q in remove_!(fc::FAC, lf)]
-- ld = [D1,...,Dk] where Di is the sum of places where f has residue bi
ld := [divisor(rec.num, rec.den, rec.derivden, rec.gd, b::F) for b in la]
pp := UPQ2F(fc.factor)
-- bb = - sum of all the roots of fc (the other residues)
zero?(bb := coefficient(fc.factor,
(degree(fc.factor) - 1)::NonNegativeInteger)) =>
-- cd = [[a1,...,ak], d] such that bi = ai/d
cd := splitDenominator la
-- g = gcd(a1,...,ak), so bi = (g/d) ci with ci = bi / g
-- so [g/d] is a basis for [a1,...,ak] over the integers
g := gcd(cd.num)
-- dv0 is the divisor +/[ci Di] corresponding to all the residues
-- of f except the ones which are root of fc(z)
dv0 := +/[(a quo g) * dv for a in cd.num for dv in ld]
trace0(rec, pp, g / cd.den, dv0)
trace1(rec, pp, la, ld, bb)
UPQ2F p ==
map((x:Q):F+->x::F,p)$UnivariatePolynomialCategoryFunctions2(Q,UPQ,F,UP)
UP2SUP p ==
map((x:F):F+->x,p)$UnivariatePolynomialCategoryFunctions2(F, UP, F, SUP)
SUP2UP p ==
map((x:F):F+->x,p)$UnivariatePolynomialCategoryFunctions2(F, SUP, F, UP)
varRoot?(p, derivation) ==
for c in coefficients primitivePart p repeat
derivation(c) ^= 0 => return true
false
pLogDeriv(log, derivation) ==
map(derivation, log.coeff) ^= 0 =>
error "can only handle logs with constant coefficients"
((n := degree(log.coeff)) = 1) =>
c := - (leadingCoefficient reductum log.coeff)
/ (leadingCoefficient log.coeff)
ans := (log.logand) c
(log.scalar)::R * c * derivation(ans) / ans
numlog := map(derivation, log.logand)
(diflog := extendedEuclidean(log.logand, log.coeff, numlog)) case
"failed" => error "this shouldn't happen"
algans := diflog.coef1
ans:R := 0
for i in 0..n-1 repeat
algans := (algans * monomial(1, 1)) rem log.coeff
ans := ans + coefficient(algans, i)
(log.scalar)::R * ans
R2UP(f, k) ==
x := dumx :: F
g :=
(map((f1:QF):F+->f1(x), lift f)_
$UnivariatePolynomialCategoryFunctions2(QF,UPUP,F,UP))
(y := dumy::F)
map((x1:F):R+->rlift(x1, dumx, dumy), univariate(g, k, minPoly k))_
$UnivariatePolynomialCategoryFunctions2(F,SUP,R,UPR)
univ(f, k) ==
g := univariate(f, k)
(SUP2UP numer g) / (SUP2UP denom g)
rlift(f, kx, ky) ==
reduce map(x1+->univ(x1, kx), retract(univariate(f, ky))@SUP)_
$UnivariatePolynomialCategoryFunctions2(F,SUP,QF,UPUP)
nonQ(rec, p) ==
empty? rest(lf := factors ffactor primitivePart p) =>
trace00(rec, first(lf).factor, empty()$List(LOG))
FAIL1
-- case when the irreducible factor p has roots which sum to 0
-- p is assumed doubly transitive for now
trace0(rec, q, r, dv0) ==
lg:List(LOG) :=
zero? dv0 => empty()
(rc0 := torsionIfCan dv0) case "failed" => NOTI
mkLog(1, r / (rc0.order::Q), rc0.function, 1)
trace00(rec, q, lg)
trace00(rec, pp, lg) ==
p0 := divisor(rec.num, rec.den, rec.derivden, rec.gd,
alpha0 := zeroOf UP2SUP pp)
q := (pp exquo (monomial(1, 1)$UP - alpha0::UP))::UP
alpha := rootOf UP2SUP q
dvr := divisor(rec.num, rec.den, rec.derivden, rec.gd, alpha) - p0
(rc := torsionIfCan dvr) case "failed" =>
degree(pp) <= 2 => "failed"
NOTI
concat(lg, mkLog(q, inv(rc.order::Q), rc.function, alpha))
-- case when the irreducible factor p has roots which sum <> 0
-- the residues of f are of the form [a1,...,ak] rational numbers
-- plus all the roots of q(z), which is squarefree
-- la is the list of residues la := [a1,...,ak]
-- ld is the list of divisors [D1,...Dk] where Di is the sum of all the
-- places where f has residue ai
-- q(z) is assumed doubly transitive for now.
-- let [alpha_1,...,alpha_m] be the roots of q(z)
-- in this function, b = - alpha_1 - ... - alpha_m is <> 0
-- which implies only one generic log term
trace1(rec, q, la, ld, b) ==
-- cd = [[b1,...,bk], d] such that ai / b = bi / d
cd := splitDenominator [a / b for a in la]
-- then, a basis for all the residues of f over the integers is
-- [beta_1 = - alpha_1 / d,..., beta_m = - alpha_m / d], since:
-- alpha_i = - d beta_i
-- ai = (ai / b) * b = (bi / d) * b = b1 * beta_1 + ... + bm * beta_m
-- linear independence is a consequence of the
-- doubly transitive assumption
-- v0 is the divisor +/[bi Di] corresponding to the residues [a1,...,ak]
v0 := +/[a * dv for a in cd.num for dv in ld]
-- alpha is a generic root of q(z)
alpha := rootOf UP2SUP q
-- v is the divisor corresponding to all the residues
v := v0 - cd.den * divisor(rec.num, rec.den, rec.derivden, rec.gd, alpha)
(rc := torsionIfCan v) case "failed" => -- non-torsion case
degree(q) <= 2 => "failed" -- guaranteed doubly-transitive
NOTI -- maybe doubly-transitive
mkLog(q, inv((- rc.order * cd.den)::Q), rc.function, alpha)
mkLog(q, scalr, lgd, alpha) ==
degree(q) <= 1 =>
[[scalr, monomial(1, 1)$UPR - F2UPR alpha, lgd::UPR]]
[[scalr,
map(F2R, q)$UnivariatePolynomialCategoryFunctions2(F,UP,R,UPR),
R2UP(lgd, retract(alpha)@K)]]
-- return the non-linear factor, if unique
-- or any linear factor if they are all linear
nonLinear l ==
found:Boolean := false
ans := first l
for q in l repeat
if degree(q.factor) > 1 then
found => return "failed"
found := true
ans := q
ans
-- f dx must be locally integral at infinity
palginfieldint(f, derivation) ==
h := HermiteIntegrate(f, derivation)
zero?(h.logpart) => h.answer
"failed"
-- f dx must be locally integral at infinity
palgintegrate(f, derivation) ==
h := HermiteIntegrate(f, derivation)
zero?(h.logpart) => h.answer::IR
(not integralAtInfinity?(h.logpart)) or
((u := palglogint(h.logpart, derivation)) case "failed") =>
mkAnswer(h.answer, empty(), [[h.logpart, dummy]])
zero?(difFirstKind := h.logpart - +/[pLogDeriv(lg,
x1+->differentiate(x1, derivation)) for lg in u::List(LOG)]) =>
mkAnswer(h.answer, u::List(LOG), empty())
mkAnswer(h.answer, u::List(LOG), [[difFirstKind, dummy]])
-- for mixed functions. f dx not assumed locally integral at infinity
algintegrate(f, derivation) ==
zero? degree(x' := derivation(x := monomial(1, 1)$UP)) =>
algintprim(f, derivation)
((xx := x' exquo x) case UP) and
(retractIfCan(xx::UP)@Union(F, "failed") case F) =>
algintexp(f, derivation)
error "should not happen"
alglogint(f, derivation) ==
varRoot?(doubleResultant(f, derivation),
x1+->retract(derivation(x1::UP))@F) => "failed"
FAIL0
|