Missing, roughly in order of importance
* zero test
* hadamard product, algebraic substitution, integration, differentiation
* a recurrence version (should be trivial), along with appropriate coercions
* q-versions (should be trivial)
* sensible domain parameters
* a creation operation, i.e., given a linear homogeneous diffeq and initial
values, create a holonomic function
* RetractableTo EXPR INT, i.e., a solver that goes together with the creation
operation. I think it's best to have the Rep include also an EXPR INT.
* "normalization" of the diffeq: we should have one domain where this is done
automatically, another one where it's done on request only
moreover:
* generalisation to ADE's
* a domain for algebraic functions, so that UHOLO has
Eltable(AlgebraicFunction, %)
* generalisation to the multivariate case
Martin
\documentclass{article}
\usepackage{axiom,amsthm,amsmath,url}
\newtheorem{ToDo}{ToDo}[section]
\newcommand{\Axiom}{{\tt Axiom}}
\newcommand{\Rate}{{\tt Rate}}
\newcommand{\GFUN}{{\tt GFUN}}
\begin{document}
\title{holonomic.spad}
\author{Martin Rubey}
\maketitle
\begin{abstract}
\end{abstract}
\tableofcontents
\section{domain UHOLO1 UnivariateHolonomicSeries1}
<<domain UHOLO1 UnivariateHolonomicSeries1>>=
)abbrev domain UHOLO1 UnivariateHolonomicSeries1
UnivariateHolonomicSeries1(Coef: Join(Field, DifferentialRing)):
Exports == Implementation where
UFPS ==> UnivariateFormalPowerSeries Coef
DEQCOEF ==> SparseUnivariatePolynomial Coef
FDEQCOEF ==> Fraction DEQCOEF
LODO1 ==> LinearOrdinaryDifferentialOperator1 FDEQCOEF
Exports ==> AbelianMonoidRing(Coef, NonNegativeInteger) with
sin: () -> %
cos: () -> %
atan: () -> %
exp: () -> %
series: % -> UFPS
differentialEquation: % -> LODO1
Implementation ==> add
Rep := Record(eq : LODO1, init: UFPS)
series f == f.init
differentialEquation f == f.eq
coerce(f: %): OutputForm ==
bracket([f.eq::OutputForm,
f.init::OutputForm])$OutputForm
-- x*Dx x^n = x*n*x^(n-1)=n*x^n
Dx := D()$LODO1
monomial(c, n) ==
c1: FDEQCOEF := monomial(1,1)$DEQCOEF :: FDEQCOEF
c0: FDEQCOEF := (-n)::DEQCOEF :: FDEQCOEF
[c1*Dx+c0*1$LODO1, monomial(c,n)]$Rep
0 == [1, 0]$Rep
1 == [Dx, 1]$Rep
f + g == [directSum(f.eq, g.eq), f.init + g.init]
(n: Integer) * (f: %) == [f.eq, n*f.init]
(f: %) * (g: %) == [symmetricProduct(f.eq, g.eq), f.init * g.init]$Rep
sin() == [Dx**2+1, sin(monomial(1,1)$UFPS)$UFPS]$Rep
cos() == [Dx**2+1, cos(monomial(1,1)$UFPS)$UFPS]$Rep
exp() == [Dx-1, exp(monomial(1,1)$UFPS)$UFPS]$Rep
atan() ==
c2: FDEQCOEF := (monomial(1,2)$DEQCOEF+1)::FDEQCOEF
c1: FDEQCOEF := monomial(2*1$Coef,1)$DEQCOEF::FDEQCOEF
[c2*Dx**2+c1*Dx, atan(monomial(1,1)$UFPS)$UFPS]$Rep
@
%$
<<*>>=
<<domain UHOLO1 UnivariateHolonomicSeries1>>
@
\end{document}
I now implemented also integration and differentiation, and noticed something I
don't really like:
(1) -> Dx:=D()$LODO1(FRAC UP(x, INT))
(1) D
Type: LinearOrdinaryDifferentialOperator1(Fraction(UnivariatePolynomial(x,Integer)))
(2) -> Dx*x
(2) x D
Type: LinearOrdinaryDifferentialOperator1(Fraction(UnivariatePolynomial(x,Integer)))
(3) -> Dx*(x::LODO1 FRAC UP(x, INT))
(3) x D + 1
Type: LinearOrdinaryDifferentialOperator1(Fraction(UnivariatePolynomial(x,Integer)))
I think that (2) and (3) should give the same result, namely x D + 1. I do not
see a reason to have right multiplication by an element of the coefficient ring
differ from multiplication of operators.
Martin
\documentclass{article}
\usepackage{axiom,amsthm,amsmath,url}
\newtheorem{ToDo}{ToDo}[section]
\newcommand{\Axiom}{{\tt Axiom}}
\newcommand{\Rate}{{\tt Rate}}
\newcommand{\GFUN}{{\tt GFUN}}
\begin{document}
\title{holonomic.spad}
\author{Martin Rubey}
\maketitle
\begin{abstract}
\end{abstract}
\tableofcontents
\section{domain UHOLO1 UnivariateHolonomicSeries1}
<<domain UALG UnivariateAlgebraicSeries>>=
)abbrev domain UALG UnivariateAlgebraicSeries
UnivariateAlgebraicSeries(Coef: Algebra Fraction Integer):
Exports == Implementation where
@
\section{domain UHOLO1 UnivariateHolonomicSeries1}
<<domain UHOLO1 UnivariateHolonomicSeries1>>=
)abbrev domain UHOLO1 UnivariateHolonomicSeries1
UnivariateHolonomicSeries1(Coef: Algebra Fraction Integer):
Exports == Implementation where
UFPS ==> UnivariateFormalPowerSeries Coef
DEQCOEF ==> UnivariatePolynomial(x, Coef)
FDEQCOEF ==> Fraction DEQCOEF
LODO1 ==> LinearOrdinaryDifferentialOperator1 FDEQCOEF
Exports ==> Join(AbelianMonoidRing(Coef, NonNegativeInteger),
DifferentialRing) with
sin: () -> %
cos: () -> %
atan: () -> %
exp: () -> %
integrate: % -> %
series: % -> UFPS
differentialEquation: % -> LODO1
Implementation ==> add
Rep := Record(eq : LODO1, init: UFPS)
series f == f.init
differentialEquation f == f.eq
coerce(f: %): OutputForm ==
bracket([f.eq::OutputForm,
f.init::OutputForm])$OutputForm
Dx := D()$LODO1
0 == [1, 0]$Rep
1 == [Dx, 1]$Rep
-- x*Dx x^n = x*n*x^(n-1)=n*x^n
monomial(c, n) ==
c1: FDEQCOEF := monomial(1,1)$DEQCOEF :: FDEQCOEF
c0: FDEQCOEF := (-n)::DEQCOEF :: FDEQCOEF
[c1*Dx+c0*1$LODO1, monomial(c,n)]$Rep
f + g == [directSum(f.eq, g.eq), f.init + g.init]
(n: Integer) * (f: %) == [f.eq, n*f.init]
(f: %) * (g: %) == [symmetricProduct(f.eq, g.eq), f.init * g.init]$Rep
integrate f == [f.eq*Dx, integrate f.init]
D f ==
p0 := coefficient(f.eq, 0)
Deq: LODO1
if zero? p0
then Deq := f.eq
else
-- without the parenthesis below, we would use ordinary multiplication!
Deq := Dx * (inv p0 * f.eq)
lmo: List LODO1
:= [monomial(coefficient(Deq, i+1), i)$LODO1 _
for i in 0..degree Deq - 1]
[reduce(_+$LODO1, lmo, 0), D f.init]
> I think that (2) and (3) should give the same result, namely x D + 1. I do not
> see a reason to have right multiplication by an element of the coefficient ring
> differ from multiplication of operators.
Of course, the computer is right. ;-) But I agree, that is not really
what one wants in that situation. I'd rather like to see the coercion
x::LODO1 FRAC UP(x, INT)
happen automatically or the right multiplication with a coefficient done
correctly.
The reason for (2) and (3) not being equal lies in the definition of
LinearOrdinaryDifferentialOperator1. Its category is
LinearOrdinaryDifferentialOperatorCategory(A) and that inherits from
UnivariateSkewPolynomialCategory A. But if you look into its source in
ore.spad, you'll find:
UnivariateSkewPolynomialCategory(R:Ring):
Category == Join(Ring, BiModule(R, R), FullyRetractableTo R) with
^^^^^^^^^^^^^^
That, by itself, would not be the problem. It is only a problem if the
right multiplication by a coefficient is not implemented according to
the commutation rules.
What I found is that
LinearOrdinaryDifferentialOperator(A:Ring, diff: A -> A):
LinearOrdinaryDifferentialOperatorCategory A
== SparseUnivariateSkewPolynomial(A, 1, diff) add ...
and
SparseUnivariateSkewPolynomial(R:Ring, sigma:Automorphism R, delta: R -> R):
UnivariateSkewPolynomialCategory R with
outputForm: (%, OutputForm) -> OutputForm
== SparseUnivariatePolynomial R add
And the last line is the problem. It certainly implements multiplication
from the right, but, of course, in a commutative fashion.
Multiplication from the right should rather expand the definition
x * a == \sigma(a) * x + \delta(a)
where x is the indeterminate of the skewpolynomial ring.
So, I guess, adding
(z: %) * (r: R): % == times(z, r*(1$%), sigma, delta)
into the second chunk
<<domain ORESUP SparseUnivariateSkewPolynomial>>=
should solve Martin's problem and all the others that are just connected
to skew polynomials.
Other opinions?
BTW... it is *totally* ugly that this chunk
<<domain ORESUP SparseUnivariateSkewPolynomial>>
is split in two in such a way as it currently is.
I'd rather like to see something like
<<domain ORESUP SparseUnivariateSkewPolynomial>>=
)abbrev domain ORESUP SparseUnivariateSkewPolynomial
...
SparseUnivariateSkewPolynomial(R:Ring,sigma:Automorphism R,delta:R->R):
UnivariateSkewPolynomialCategory R with
...
== SparseUnivariatePolynomial R add
<<domain ORESUP SparseUnivariateSkewPolynomial: add-body>>
@
<<domain ORESUP SparseUnivariateSkewPolynomial: add-body>>=
import RepeatedSquaring(%)
_^(x:%, n:PositiveInteger):% == x ** n
...
if R has Field then
leftDivide(a, b) == leftDivide(a, b, sigma)
rightDivide(a, b) == rightDivide(a, b, sigma)
@
Common initial white space should not be important in a chunk.
Best regards
Ralf
I don't particularly like the design, improvements welcome. Documentation
non-existing currently, too.
Usage example:
(33) -> cat2 := coerce(univariate(x::UP(x, FRAC INT)*y^2-y+1,y)::SUP UP(x, FRAC INT), 0)$UALG FRAC INT
2
(33) [x ? - ? + 1,0]
Type: UnivariateAlgebraicSeries(Fraction(Integer))
Time: 0.14 (IN) + 0.004 (EV) + 0.05 (OT) = 0.19 sec
(34) -> cat2 * cat2
3 3 2 2
(34) [x ? + (x - x)? + (- x + 1)? - 1,0]
Type: UnivariateAlgebraicSeries(Fraction(Integer))
Time: 0.01 (EV) + 0.02 (OT) = 0.03 sec
check:
(71) -> cs := series([1/(2*n+1)*binomial(2*n+1, n) for n in 0..])$UFPS FRAC INT
(71)
2 3 4 5 6 7 8 9
1 + x + 2x + 5x + 14x + 42x + 132x + 429x + 1430x + 4862x
+
10 11
16796x + O(x )
Type: UnivariateFormalPowerSeries(Fraction(Integer))
Time: 0.02 (IN) + 0.03 (OT) = 0.05 sec
(72) -> guessAlg(entries complete first(coefficients(cs2*cs2), 42),
maxPower==6)
(72)
[
[
function =
n 2 2
[[x ]f(x): x f(x) + (2x - 1)f(x) + 1= 0,
2 3 4 5
f(x)= 1 + 2x + 5x + 14x + 42x + O(x )]
,
order= 0]
]
Type: List(Record(function: Expression(Integer),order: NonNegativeInteger))
Time: 0.08 (EV) + 0.01 (OT) = 0.08 sec
Martin
\documentclass{article}
\usepackage{axiom,amsthm,amsmath,url}
\newtheorem{ToDo}{ToDo}[section]
\newcommand{\Axiom}{{\tt Axiom}}
\newcommand{\Rate}{{\tt Rate}}
\newcommand{\GFUN}{{\tt GFUN}}
\begin{document}
\title{holonomic.spad}
\author{Martin Rubey}
\maketitle
\begin{abstract}
\end{abstract}
\tableofcontents
\section{domain UALG UnivariateAlgebraicSeries}
<<domain UALG UnivariateAlgebraicSeries>>=
)abbrev domain UALG UnivariateAlgebraicSeries
UnivariateAlgebraicSeries(Coef: Algebra Fraction Integer):
Exports == Implementation where
UFPS ==> UnivariateFormalPowerSeries Coef
EQCOEF ==> UnivariatePolynomial(x, Coef)
ALGEQ ==> SparseUnivariatePolynomial EQCOEF
Exports ==> Join(AbelianMonoidRing(Coef, NonNegativeInteger),
DifferentialRing, Field) with
coerce: (ALGEQ, UFPS) -> %
Implementation ==> add
Rep := Record(eq: ALGEQ, init: UFPS)
coerce(f: %): OutputForm ==
bracket([f.eq::OutputForm,
f.init::OutputForm])$OutputForm
coerce(feq: ALGEQ, finit: UFPS): % == [feq, finit]$Rep
0 == [monomial(1,1)$ALGEQ, 0]$Rep
1 == [monomial(1,1)$ALGEQ-1, 1]$Rep
monomial(c, n) ==
[monomial(1,1)$ALGEQ-monomial(c,n)$EQCOEF::ALGEQ,
monomial(c,n)]$Rep
FEQCOEF ==> Fraction EQCOEF
OVAR ==> OrderedVariableList ['u, 'v, 'y]
SMP ==> SparseMultivariatePolynomial(FEQCOEF, OVAR)
GROE ==> GroebnerPackage(FEQCOEF, IndexedExponents OVAR, OVAR, SMP)
CDEN ==> CommonDenominator(EQCOEF,FEQCOEF,List FEQCOEF)
SUP2EF ==> SparseUnivariatePolynomialFunctions2(EQCOEF, FEQCOEF)
SUP2FE ==> SparseUnivariatePolynomialFunctions2(FEQCOEF, EQCOEF)
f + g ==
ff: SparseUnivariatePolynomial FEQCOEF
:= map(#1::FEQCOEF, f.eq)$SUP2EF
gf: SparseUnivariatePolynomial FEQCOEF
:= map(#1::FEQCOEF, g.eq)$SUP2EF
leq: List SMP :=
[index(3)$OVAR::SMP-index(1)$OVAR::SMP-index(2)$OVAR::SMP, _
multivariate(ff, index(1)$OVAR), _
multivariate(gf, index(2)$OVAR)]
neweq: SMP := third groebner(leq)$GROE
neweq2: SparseUnivariatePolynomial FEQCOEF := univariate(neweq)$SMP
cden: EQCOEF := commonDenominator(coefficients neweq2)$CDEN
algeq: ALGEQ := map(retract(cden*#1)@EQCOEF, neweq2)$SUP2FE
[algeq, f.init + g.init]$Rep
(f: %) * (g: %) ==
ff: SparseUnivariatePolynomial FEQCOEF
:= map(#1::FEQCOEF, f.eq)$SUP2EF
gf: SparseUnivariatePolynomial FEQCOEF
:= map(#1::FEQCOEF, g.eq)$SUP2EF
leq: List SMP :=
[index(3)$OVAR::SMP-index(1)$OVAR::SMP*index(2)$OVAR::SMP, _
multivariate(ff, index(1)$OVAR), _
multivariate(gf, index(2)$OVAR)]
gb := groebner(leq)$GROE
output(gb::OutputForm)$OutputPackage
neweq: SMP := last gb
output(variables(neweq)$SMP::OutputForm)$OutputPackage
neweq2: SparseUnivariatePolynomial FEQCOEF := univariate(neweq)$SMP
cden: EQCOEF := commonDenominator(coefficients neweq2)$CDEN
algeq: ALGEQ := map(retract(cden*#1)@EQCOEF, neweq2)$SUP2FE
[algeq, f.init * g.init]$Rep
@
integrate: % -> %
series f == f.init
differentialEquation f == f.eq
Dx := D()$LODO1
@
%$
<<*>>=
<<domain UALG UnivariateAlgebraicSeries>>
> SparseUnivariateSkewPolynomial(R:Ring, sigma:Automorphism R, delta: R -> R):
> UnivariateSkewPolynomialCategory R with
> outputForm: (%, OutputForm) -> OutputForm
> == SparseUnivariatePolynomial R add
>
> And the last line is the problem. It certainly implements multiplication
> from the right, but, of course, in a commutative fashion.
Yes.
> Multiplication from the right should rather expand the definition
>
> x * a == \sigma(a) * x + \delta(a)
>
> where x is the indeterminate of the skewpolynomial ring.
>
> So, I guess, adding
>
> (z: %) * (r: R): % == times(z, r*(1$%), sigma, delta)
>
> into the second chunk
>
> <<domain ORESUP SparseUnivariateSkewPolynomial>>=
>
> should solve Martin's problem and all the others that are just connected
> to skew polynomials.
I'm all for it.
> BTW... it is *totally* ugly that this chunk
>
> <<domain ORESUP SparseUnivariateSkewPolynomial>>
>
> is split in two in such a way as it currently is.
> I'd rather like to see something like
>
> <<domain ORESUP SparseUnivariateSkewPolynomial>>=
> )abbrev domain ORESUP SparseUnivariateSkewPolynomial
> ...
> SparseUnivariateSkewPolynomial(R:Ring,sigma:Automorphism R,delta:R->R):
> UnivariateSkewPolynomialCategory R with
> ...
> == SparseUnivariatePolynomial R add
> <<domain ORESUP SparseUnivariateSkewPolynomial: add-body>>
> @
>
>
> <<domain ORESUP SparseUnivariateSkewPolynomial: add-body>>=
> import RepeatedSquaring(%)
> _^(x:%, n:PositiveInteger):% == x ** n
> ...
> if R has Field then
> leftDivide(a, b) == leftDivide(a, b, sigma)
> rightDivide(a, b) == rightDivide(a, b, sigma)
> @
>
> Common initial white space should not be important in a chunk.
Einverstanden!
Martin
I know that would be proper Aldor, but is this proper SPAD?
Whether this really fixes the problem, I first have to investigate, of
course.
Ralf
> >> (z: %) * (r: R): % == times(z, r*(1$%), sigma, delta)
>
> I know that would be proper Aldor, but is this proper SPAD?
As far as I can see, yes.
Martin
> Whether this really fixes the problem, I first have to investigate, of
> course.
I'm quite sure it does. We fixed already exponentiation this way. My question
really was: does anybody want to have it as it is currently, but it seems that
this is not the case, so: go ahead!
Martin
Martin, do you like that more...
GCL (GNU Common Lisp) 2.6.7 CLtL1 Oct 29 2006 02:32:45
Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
Binary License: GPL due to GPL'ed components: (XGCL READLINE BFD UNEXEC)
Modifications of this banner must retain notice of a compatible license
Dedicated to the memory of W. Schelter
Use (help) to get some basic information on how to use GCL.
Temporary directory for compiler files set to /tmp/hemmecke/
openServer result 0
FriCAS (AXIOM fork) Computer Algebra System
Version: FriCAS 2009-01-25
Timestamp: Wednesday January 28, 2009 at 23:40:51
-----------------------------------------------------------------------------
Issue )copyright to view copyright notices.
Issue )summary for a summary of useful system commands.
Issue )quit to leave FriCAS and return to shell.
-----------------------------------------------------------------------------
(1) ->
(1) -> Dx:=D()$LODO1(FRAC UP(x, INT))
(1) D
Type:
LinearOrdinaryDifferentialOperator1(Fraction(UnivariatePolynomial(x,Integer)))
(2) -> Dx*x
(2) x D + 1
Type:
LinearOrdinaryDifferentialOperator1(Fraction(UnivariatePolynomial(x,Integer)))
(3) -> Dx*(x::LODO1 FRAC UP(x, INT))
(3) x D + 1
Type:
LinearOrdinaryDifferentialOperator1(Fraction(UnivariatePolynomial(x,Integer)))
I basically modified ore.spad as I described in
http://groups.google.com/group/fricas-devel/msg/b2e1c329ad300ad1 .
Patch is below. Should I commit?
Ralf
diff -Naur ore.spad.pamphlet.old ore.spad.pamphlet > ore.patch
Good spot!!!
> I guess, the best thing is to write a test for *every* operation...
I completely agree. But now you have to teach me.
1) Where can I find a documentation of all your testsuite business?
2) Where is the testsuite machinery? How does it roughly work?
3) Where are the test files? (I don't see a "test" directory.)
Ralf
> > However (sorry...), we should check whether the line
> >
> > == SparseUnivariatePolynomial R add
> >
> > is a good idea. Yes, the Rep is the same, and a few operations are the same,
> > but many are different.
>
> Good spot!!!
>
> > I guess, the best thing is to write a test for *every* operation...
>
> I completely agree. But now you have to teach me.
>
> 1) Where can I find a documentation of all your testsuite business?
in src/algebra/unittest.spad.pamphlet
> 2) Where is the testsuite machinery? How does it roughly work?
2a: ditto. 2b: write a .input file that looks roughly like
src/input/elemnum.input.pamphlet
> 3) Where are the test files? (I don't see a "test" directory.)
see 2b.
actually, there is a tiny bit of disagreement between Waldek and myself on
where to put the tests. I'd like to have "categorical" tests (i.e., black box
tests that test every operation a category exports) in the spad.pamphlet, then
"paedagogic", "explanatory", i.e., system tests in a file in src/input, and
regression tests in src/input/bugs20??.input.
Waldek had good reasons not to put tests into category definitions, so for the
moment we put all tests into src/input...
1 000 000 thanks for your work!
Martin
> > However (sorry...), we should check whether the line
> >
> > == SparseUnivariatePolynomial R add
> >
> > is a good idea. Yes, the Rep is the same, and a few operations are the same,
> > but many are different.
>
> Good spot!!!
just noticed that OREUP does not have POLYCAT, so, I guess that
> > == SparseUnivariatePolynomial R add
is really out of place. However, please commit the change you made first, and
then dig further. History shows that this makes development proceed faster.
Martin
Yes. We should replace:
== SparseUnivariatePolynomial R add
by
== add
Rep := SparseUnivariatePolynomial R
but I agree with Martin that we should commit the fix first.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
| Ralf Hemmecke wrote:
| > I basically modified ore.spad as I described in
| > http://groups.google.com/group/fricas-devel/msg/b2e1c329ad300ad1 .
| > Patch is below. Should I commit?
| >
|
| Yes. We should replace:
|
| == SparseUnivariatePolynomial R add
|
| by
| == add
| Rep := SparseUnivariatePolynomial R
|
| but I agree with Martin that we should commit the fix first.
I would think that the first form is clearer and superior to the
second in that it clearly separates addon from addins and make the
connection. But, I agree that without better support in the
language -- where it is clear that the addon is the representation --
one would be forced to explicitly define Rep.
[ FWIW OpenAxiom automtically recognizes the construct and makes the
addon the reprsentation type. ]
The first form is superior _if appropriate_. However, skew
polynomials are really more general that commutative polynomials,
and operations typically must take this into account. So
inheritance does not look appropriate here (logically it would
be appropriate if SparseUnivariatePolynomial inherited from
SparseUnivariateSkewPolynomial) -- we just want to reuse
representation and _some_ operations.
--
Waldek Hebisch
heb...@math.uni.wroc.pl