)abbrev package AF AlgebraicFunction
++ Author: Manuel Bronstein
++ Date Created: 21 March 1988
++ Date Last Updated: 11 November 1993
++ Description:
++ This package provides algebraic functions over an integral domain.
++ Keywords: algebraic, function.
AlgebraicFunction(R, F): Exports == Implementation where
R: IntegralDomain
F: FunctionSpace R
SE ==> Symbol
Z ==> Integer
Q ==> Fraction Z
OP ==> BasicOperator
K ==> Kernel F
P ==> SparseMultivariatePolynomial(R, K)
UP ==> SparseUnivariatePolynomial F
UPR ==> SparseUnivariatePolynomial R
Exports ==> with
rootOf : (UP, SE) -> F
++ rootOf(p, y) returns y such that \spad{p(y) = 0}.
++ The object returned displays as \spad{'y}.
operator: OP -> OP
++ operator(op) returns a copy of \spad{op} with the domain-dependent
++ properties appropriate for \spad{F}.
++ Error: if op is not an algebraic operator, that is,
++ an nth root or implicit algebraic operator.
belong? : OP -> Boolean
++ belong?(op) is true if \spad{op} is an algebraic operator, that is,
++ an nth root or implicit algebraic operator.
inrootof: (UP, F) -> F
++ inrootof(p, x) should be a non-exported function.
-- un-export when the compiler accepts conditional local functions!
droot : List F -> OutputForm
++ droot(l) should be a non-exported function.
-- un-export when the compiler accepts conditional local functions!
if R has RetractableTo Integer then
** : (F, Q) -> F
++ x ** q is \spad{x} raised to the rational power \spad{q}.
minPoly: K -> UP
++ minPoly(k) returns the defining polynomial of \spad{k}.
definingPolynomial: F -> F
++ definingPolynomial(f) returns the defining polynomial of \spad{f}
++ as an element of \spad{F}.
++ Error: if f is not a kernel.
iroot : (R, Z) -> F
++ iroot(p, n) should be a non-exported function.
-- un-export when the compiler accepts conditional local functions!
Implementation ==> add
macro ALGOP == '%alg
macro SPECIALDISP == '%specialDisp
macro SPECIALDIFF == '%specialDiff
ialg : List F -> F
dvalg: (List F, SE) -> F
dalg : List F -> OutputForm
opalg := operator('rootOf)$CommonOperators
oproot := operator('nthRoot)$CommonOperators
belong? op == has?(op, ALGOP)
dalg l == second(l)::OutputForm
rootOf(p, x) ==
k := kernel(x)$K
(r := retractIfCan(p)@Union(F, "failed")) case "failed" =>
inrootof(p, k::F)
n := numer(f := univariate(r::F, k))
positive? degree denom f => error "roofOf: variable appears in denom"
inrootof(n, k::F)
dvalg(l, x) ==
p := numer univariate(first l, retract(second l)@K)
alpha := kernel(opalg, l)
- (map(differentiate(#1, x), p) alpha) / ((differentiate p) alpha)
ialg l ==
f := univariate(p := first l, retract(x := second l)@K)
positive? degree denom f => error "roofOf: variable appears in denom"
inrootof(numer f, x)
operator op ==
is?(op,'rootOf) => opalg
is?(op,'nthRoot) => oproot
error "Unknown operator"
if R has AlgebraicallyClosedField then
UP2R: UP -> Union(UPR, "failed")
inrootof(q, x) ==
monomial? q => 0
(d := degree q) <= 0 => error "rootOf: constant polynomial"
one? d=> - leadingCoefficient(reductum q) / leadingCoefficient q
((rx := retractIfCan(x)@Union(SE, "failed")) case SE) and
((r := UP2R q) case UPR) => rootOf(r::UPR, rx::SE)::F
kernel(opalg, [q x, x])
UP2R p ==
ans:UPR := 0
while p ~= 0 repeat
(r := retractIfCan(leadingCoefficient p)@Union(R, "failed"))
case "failed" => return "failed"
ans := ans + monomial(r::R, degree p)
p := reductum p
ans
else
inrootof(q, x) ==
monomial? q => 0
(d := degree q) <= 0 => error "rootOf: constant polynomial"
one? d => - leadingCoefficient(reductum q) /leadingCoefficient q
kernel(opalg, [q x, x])
evaluate(opalg, ialg)$BasicOperatorFunctions1(F)
setProperty(opalg, SPECIALDIFF,
dvalg@((List F, SE) -> F) pretend None)
setProperty(opalg, SPECIALDISP,
dalg@(List F -> OutputForm) pretend None)
if R has RetractableTo Integer then
import PolynomialRoots(IndexedExponents K, K, R, P, F)
dumvar := '%%var::F
lzero : List F -> F
dvroot : List F -> F
inroot : List F -> F
hackroot: (F, Z) -> F
inroot0 : (F, Z, Boolean, Boolean) -> F
lzero l == 0
droot l ==
x := first(l)::OutputForm
(n := retract(second l)@Z) = 2 => root x
root(x, n::OutputForm)
dvroot l ==
n := retract(second l)@Z
(first(l) ** ((1 - n) / n)) / (n::F)
x ** q ==
qr := divide(numer q, denom q)
x ** qr.quotient * inroot([x, (denom q)::F]) ** qr.remainder
hackroot(x, n) ==
(n = 1) or (x = 1) => x
(not one?(dx := denom x) and
((rx := retractIfCan(dx)@Union(Integer,"failed")) case Integer) and
positive?(rx))
=> hackroot((numer x)::F, n)/hackroot(rx::Integer::F, n)
(x = -1) and n = 4 =>
((-1::F) ** (1::Q / 2::Q) + 1) / ((2::F) ** (1::Q / 2::Q))
kernel(oproot, [x, n::F])
inroot l ==
zero?(n := retract(second l)@Z) => error "root: exponent = 0"
one?(x := first l) or one? n => x
(r := retractIfCan(x)@Union(R,"failed")) case R => iroot(r::R,n)
(u := isExpt(x)) case Record(var:K, exponent:Z) =>
pr := u::Record(var:K, exponent:Z)
is?(pr.var,oproot) and #argument(pr.var) = 2 =>
(first argument(pr.var)) **
(pr.exponent /$Fraction(Z)
(n * retract(second argument(pr.var))@Z))
inroot0(x, n, false, false)
inroot0(x, n, false, false)
-- removes powers of positive integers from numer and denom
-- num? or den? is true if numer or denom already processed
inroot0(x, n, num?, den?) ==
rn:Union(Z, "failed") := (num? => "failed"; retractIfCan numer x)
rd:Union(Z, "failed") := (den? => "failed"; retractIfCan denom x)
(rn case Z) and (rd case Z) =>
rec := qroot(rn::Z / rd::Z, n::NonNegativeInteger)
rec.coef * hackroot(rec.radicand, rec.exponent)
rn case Z =>
rec := qroot(rn::Z::Fraction(Z), n::NonNegativeInteger)
rec.coef * inroot0((rec.radicand**(n exquo rec.exponent)::Z)
/ (denom(x)::F), n, true, den?)
rd case Z =>
rec := qroot(rd::Z::Fraction(Z), n::NonNegativeInteger)
inroot0((numer(x)::F) /
(rec.radicand ** (n exquo rec.exponent)::Z),
n, num?, true) / rec.coef
hackroot(x, n)
if R has AlgebraicallyClosedField then iroot(r, n) == nthRoot(r, n)::F
else
iroot0: (R, Z) -> F
if R has RadicalCategory then
if R has imaginary:() -> R then iroot(r, n) == nthRoot(r, n)::F
else
iroot(r, n) ==
odd? n or not before?(r,0) => nthRoot(r, n)::F
iroot0(r, n)
else iroot(r, n) == iroot0(r, n)
iroot0(r, n) ==
rec := rroot(r, n::NonNegativeInteger)
rec.coef * hackroot(rec.radicand, rec.exponent)
definingPolynomial x ==
(r := retractIfCan(x)@Union(K, "failed")) case K =>
is?(k := r::K, opalg) => first argument k
is?(k, oproot) =>
dumvar ** retract(second argument k)@Z - first argument k
dumvar - x
dumvar - x
minPoly k ==
is?(k, opalg) =>
numer univariate(first argument k,
retract(second argument k)@K)
is?(k, oproot) =>
monomial(1,retract(second argument k)@Z :: NonNegativeInteger)
- first(argument k)::UP
monomial(1, 1) - k::F::UP
evaluate(oproot, inroot)$BasicOperatorFunctions1(F)
derivative(oproot, [dvroot, lzero])
else -- R is not retractable to Integer
droot l ==
x := first(l)::OutputForm
(n := second l) = 2::F => root x
root(x, n::OutputForm)
minPoly k ==
is?(k, opalg) =>
numer univariate(first argument k,
retract(second argument k)@K)
monomial(1, 1) - k::F::UP
setProperty(oproot, SPECIALDISP,
droot@(List F -> OutputForm) pretend None)