)abbrev category LODOCAT LinearOrdinaryDifferentialOperatorCategory
++ Author: Manuel Bronstein
++ Date Created: 9 December 1993
++ Keywords: differential operator
++ Description:
++   \spad{LinearOrdinaryDifferentialOperatorCategory} is the category
++   of differential operators with coefficients in a ring A with a given
++   derivation.
++   Multiplication of operators corresponds to functional composition:
++       \spad{(L1 * L2).(f) = L1 L2 f}
LinearOrdinaryDifferentialOperatorCategory(A : Ring) : Category ==
  Join(UnivariateSkewPolynomialCategory A, Eltable(A, A)) with
        D : () -> %
            ++ D() provides the operator corresponding to a derivation
            ++ in the ring \spad{A}.
        adjoint : % -> %
            ++ adjoint(a) returns the adjoint operator of a.
        if A has Field then
          symmetricProduct : (%, %) -> %
            ++ symmetricProduct(a, b) computes an operator \spad{c} of
            ++ minimal order such that the nullspace of \spad{c} is
            ++ generated by all the products of a solution of \spad{a} by
            ++ a solution of \spad{b}.
          symmetricPower  : (%, NonNegativeInteger) -> %
            ++ symmetricPower(a, n) computes an operator \spad{c} of
            ++ minimal order such that the nullspace of \spad{c} is
            ++ generated by all the products of \spad{n} solutions
            ++ of \spad{a}.
          symmetricSquare : % -> %
            ++ symmetricSquare(a) computes \spad{symmetricProduct(a, a)}
            ++ using a more efficient method.
          directSum : (%, %) -> %
            ++ directSum(a, b) computes an operator \spad{c} of
            ++ minimal order such that the nullspace of \spad{c} is
            ++ generated by all the sums of a solution of \spad{a} by
            ++ a solution of \spad{b}.
   add
        m1monom : NonNegativeInteger -> %

        D() == monomial(1, 1)

        m1monom n ==
          a : A := (odd? n => -1; 1)
          monomial(a, n)

        adjoint a ==
          ans : % := 0
          while a ~= 0 repeat
            ans := ans + m1monom(degree a) * leadingCoefficient(a)::%
            a   := reductum a
          ans

        if A has Field then symmetricSquare l == symmetricPower(l, 2)

)abbrev package LODOOPS LinearOrdinaryDifferentialOperatorsOps
++ Author: Manuel Bronstein
++ Date Created: 18 January 1994
++ Description:
++   \spad{LinearOrdinaryDifferentialOperatorsOps} provides symmetric
++   products and sums for linear ordinary differential operators.
-- Putting those operations here rather than defaults in LODOCAT allows
-- LODOCAT to be defined independently of the derivative used.
-- MB 1/94
LinearOrdinaryDifferentialOperatorsOps(A, L) : Exports == Implementation where
    A : Field
    L : LinearOrdinaryDifferentialOperatorCategory A

    N  ==> NonNegativeInteger
    V  ==> OrderlyDifferentialVariable Symbol
    P  ==> DifferentialSparseMultivariatePolynomial(A, Symbol, V)

    Exports ==> with
          symmetricProduct : (L, L, A -> A) -> L
            ++ symmetricProduct(a, b, D) computes an operator \spad{c} of
            ++ minimal order such that the nullspace of \spad{c} is
            ++ generated by all the products of a solution of \spad{a} by
            ++ a solution of \spad{b}.
            ++ D is the derivation to use.
          symmetricPower : (L, N, A -> A) -> L
            ++ symmetricPower(a, n, D) computes an operator \spad{c} of
            ++ minimal order such that the nullspace of \spad{c} is
            ++ generated by all the products of \spad{n} solutions
            ++ of \spad{a}.
            ++ D is the derivation to use.
          directSum : (L, L, A -> A) -> L
            ++ directSum(a, b, D) computes an operator \spad{c} of
            ++ minimal order such that the nullspace of \spad{c} is
            ++ generated by all the sums of a solution of \spad{a} by
            ++ a solution of \spad{b}.
            ++ D is the derivation to use.

    Implementation ==> add

          var1 := new()$Symbol
          var2 := new()$Symbol

          applyLODO  : (L, V) -> P
          killer     : (P, N, List V, List P, A -> A) -> L
          vec2LODO   : Vector A -> L

          vec2LODO v    == +/[monomial(v.i, (i-1)::N) for i in 1..#v]

          symmetricPower(l, m, diff) ==
            u := var1::V; n := degree l
            un := differentiate(u, n)
            a  := applyLODO(inv(- leadingCoefficient l) * reductum l, u)
            killer(u::P ^ m, binomial(n + m - 1, n - 1)::N, [un], [a], diff)

-- returns an operator L such that L(u) = 0, for a given differential
-- polynomial u, given that the differential variables appearing in u
-- satisfy some linear ode's
-- m is a bound on the order of the operator searched.
-- lvar, lval describe the substitution(s) to perform when differentiating
--     the expression u (they encode the fact the the differential variables
--     satisfy some differential equations, which can be seen as the rewrite
--     rules   lvar --> lval)
-- diff is the derivation to use
          killer(u, m, lvar, lval, diff) ==
            lu : List P := [u]
            for q in 0..m repeat
              mat := reducedSystem(matrix([lu])@Matrix(P))@Matrix(A)
              l := nullSpace mat
              not empty?(l) => return vec2LODO(first l)
              u := eval(differentiate(u, diff), lvar, lval)
              lu := concat!(lu, [u])
            error "killer: no linear dependence found"

          symmetricProduct(l1, l2, diff) ==
            u  := var1::V;   v  := var2::V
            n1 := degree l1; n2 := degree l2
            un := differentiate(u, n1); vn := differentiate(v, n2)
            a  := applyLODO(inv(- leadingCoefficient l1) * reductum l1, u)
            b  := applyLODO(inv(- leadingCoefficient l2) * reductum l2, v)
            killer(u::P * v::P, n1 * n2, [un, vn], [a, b], diff)

          directSum(l1, l2, diff) ==
            u  := var1::V;   v  := var2::V
            n1 := degree l1; n2 := degree l2
            un := differentiate(u, n1); vn := differentiate(v, n2)
            a  := applyLODO(inv(- leadingCoefficient l1) * reductum l1, u)
            b  := applyLODO(inv(- leadingCoefficient l2) * reductum l2, v)
            killer(u::P + v::P, n1 + n2, [un, vn], [a, b], diff)

          applyLODO(l, v) ==
            p : P := 0
            while l ~= 0 repeat
              p := p + monomial(leadingCoefficient(l)::P,
                                  differentiate(v, degree l), 1)
              l := reductum l
            p

)abbrev domain LODO LinearOrdinaryDifferentialOperator
++ Author: Manuel Bronstein
++ Date Created: 9 December 1993
++ Keywords: differential operator
++ Description:
++   \spad{LinearOrdinaryDifferentialOperator} defines a ring of
++   differential operators with coefficients in a ring A with a given
++   derivation.
++   Multiplication of operators corresponds to functional composition:
++       \spad{(L1 * L2).(f) = L1 L2 f}
LinearOrdinaryDifferentialOperator(A : Ring, diff : A -> A):
    LinearOrdinaryDifferentialOperatorCategory A
      == SparseUnivariateSkewPolynomial(A, 1, diff) add
        Rep := SparseUnivariateSkewPolynomial(A, 1, diff)

        outputD := "D"@String :: Symbol :: OutputForm

        coerce(l : %) : OutputForm == outputForm(l, outputD)
        elt(p : %, a : A) : A        == apply(p, 0, a)

        if A has Field then
            import from LinearOrdinaryDifferentialOperatorsOps(A, %)

            symmetricProduct(a, b) == symmetricProduct(a, b, diff)
            symmetricPower(a, n)   == symmetricPower(a, n, diff)
            directSum(a, b)        == directSum(a, b, diff)

)abbrev domain LODO1 LinearOrdinaryDifferentialOperator1
++ Author: Manuel Bronstein
++ Date Created: 9 December 1993
++ Keywords: differential operator
++ Description:
++   \spad{LinearOrdinaryDifferentialOperator1} defines a ring of
++   differential operators with coefficients in a differential ring A.
++   Multiplication of operators corresponds to functional composition:
++       \spad{(L1 * L2).(f) = L1 L2 f}
LinearOrdinaryDifferentialOperator1(A : DifferentialRing) ==
  LinearOrdinaryDifferentialOperator(A, differentiate$A)

)abbrev domain LODO2 LinearOrdinaryDifferentialOperator2
++ Author: Stephen M. Watt, Manuel Bronstein
++ Date Created: 1986
++ Keywords: differential operator
++ Description:
++   \spad{LinearOrdinaryDifferentialOperator2} defines a ring of
++   differential operators with coefficients in a differential ring A
++   and acting on an A-module M.
++   Multiplication of operators corresponds to functional composition:
++       \spad{(L1 * L2).(f) = L1 L2 f}
LinearOrdinaryDifferentialOperator2(A, M) : Exports == Implementation where
  A : DifferentialRing
  M : LeftModule A with
        differentiate : % -> %
                ++ differentiate(x) returns the derivative of x

  Exports ==> Join(LinearOrdinaryDifferentialOperatorCategory A, Eltable(M, M))

  Implementation ==> LinearOrdinaryDifferentialOperator(A, differentiate$A) add
      elt(p : %, m : M) : M ==
        apply(p, differentiate, m)$ApplyUnivariateSkewPolynomial(A, M, %)

)abbrev domain LODO3AUX LinearOrdinaryDifferentialOperator3Aux
++ Description: \spad{LinearOrdinaryDifferentialOperator3Aux} is
++  a helper for \spad{LinearOrdinaryDifferentialOperator3}
++  defining appropriate derivative.
LinearOrdinaryDifferentialOperator3Aux(Coeff : Ring,
      A : AbelianMonoidRing(Coeff, NonNegativeInteger),
      R : Join(DifferentialRing, LeftModule(A))) : with
    delta_deriv : R -> R
      ++ delta_deriv(f) is x*f' where x is variable in A
  == add
    delta_deriv(x) ==
        monomial(1$Coeff, 1$NonNegativeInteger)$A*differentiate(x)$R

)abbrev domain LODO3 LinearOrdinaryDifferentialOperator3
++ Description: \spad{LinearOrdinaryDifferentialOperator3} is a ring
++  differential operators with coefficients in a differential ring R.
++  Basic derivative is derivative in R times variable (monomial
++  of degree 1).
LinearOrdinaryDifferentialOperator3(Coeff : Ring,
      A : AbelianMonoidRing(Coeff, NonNegativeInteger),
      R : Join(DifferentialRing, LeftModule(A))
    ) ==
  LinearOrdinaryDifferentialOperator(R,
        delta_deriv$LinearOrdinaryDifferentialOperator3Aux(Coeff, A, R))


)abbrev package LODOCONV LODOConvertions
++ Description: \spadtype{LODOConvertions} implements convertion between
++  \spadtype{LinearOrdinaryDifferentialOperator1} and
++  \spadtype{LinearOrdinaryDifferentialOperator3} and back.
LODOConvertions(Coeff, Ab, R) : Exports == Implementation where
    Coeff : Ring
    Ab : AbelianMonoidRing(Coeff, NonNegativeInteger)
    R : Join(DifferentialRing, LeftModule(Ab))

    L1 ==> LinearOrdinaryDifferentialOperator1 R
    L3 ==> LinearOrdinaryDifferentialOperator3(Coeff, Ab, R)

    Exports == with
        convert : L1 -> L3
            ++ convert(l1) converts an operator l1 from
            ++ \spadtype{LinearOrdinaryDifferentialOperator1} to
            ++ \spadtype{LinearOrdinaryDifferentialOperator3} such that the
            ++ resultant operator gives the same result as the original one
            ++ on application to an element of domain R.
        convert : L3 -> L1
            ++ convert(l3) converts an operator l3 from
            ++ \spadtype{LinearOrdinaryDifferentialOperator3} to
            ++ \spadtype{LinearOrdinaryDifferentialOperator1} such that the
            ++ resultant operator gives the same result as the original one
            ++ on application to an element of domain R.

    Implementation == add

        convert(l1 : L1) ==
            l3 : L3 := 0
            while l1 ~= 0 repeat
                l3 := (l3 +
                      leadingCoefficient(l1) *
                      (((recip(monomial(1, 1) * 1$R)) :: R) * D())^degree(l1))
                l1 := reductum l1
            l3
        convert(l3 : L3) ==
            l1 : L1 := 0
            while l3 ~= 0 repeat
                l1 := (l1 + leadingCoefficient(l3) *
                            ((monomial(1, 1) * 1) * D())^degree(l3))
                l3 := reductum l3
            l1


)abbrev domain ODR OrdinaryDifferentialRing
++ Author: Stephen M. Watt
++ Date Created: 1986
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords: differential ring
++ Examples:
++ References:
++ Description:
++   This constructor produces an ordinary differential ring from
++   a partial differential ring by specifying a variable.

OrdinaryDifferentialRing(Kernels, R, var) : DRcategory == DRcapsule where
    Kernels : SetCategory
    R : PartialDifferentialRing(Kernels)
    var : Kernels
    DRcategory == Join(BiModule(%, %), DifferentialRing) with
        if R has Field then Field
        coerce : R -> %
            ++ coerce(r) views r as a value in the ordinary differential ring.
        coerce : % -> R
            ++ coerce(p) views p as a valie in the partial differential ring.
    DRcapsule == R add
        n : Integer
        Rep := R
        coerce(u : R) : % == u::Rep::%
        coerce(p : %) : R == p::Rep::R
        differentiate p       == differentiate(p, var)

        if R has Field then
            p / q     == ((p::R) /$R (q::R))::%
            p ^ n    == ((p::R) ^$R n)::%
            inv(p)    == (inv(p::R)$R)::%

--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--    - Redistributions of source code must retain the above copyright
--      notice, this list of conditions and the following disclaimer.
--
--    - Redistributions in binary form must reproduce the above copyright
--      notice, this list of conditions and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--
--    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--      names of its contributors may be used to endorse or promote products
--      derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
