)abbrev category PSCAT PowerSeriesCategory
++ Author: Clifton J. Williamson
++ Date Created: 21 December 1989
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords: power series
++ Examples:
++ References:
++ Description:
++   \spadtype{PowerSeriesCategory} is the most general power series
++   category with exponents in an ordered abelian monoid.
PowerSeriesCategory(Coef, Expon, Var) : Category == Definition where
  Coef  : Ring
  Expon : OrderedAbelianMonoid
  Var   : OrderedSet
  I   ==> Integer
  RN  ==> Fraction Integer

  Definition ==> Join(AbelianMonoidRing(Coef, Expon),
                      VariablesCommuteWithCoefficients) with

    leadingMonomial : % -> %
      ++ leadingMonomial(f) returns the monomial of \spad{f} of lowest order.
    leadingCoefficient : % -> Coef
      ++ leadingCoefficient(f) returns the coefficient of the lowest order
      ++ term of \spad{f}
    degree : % -> Expon
      ++ degree(f) returns the exponent of the lowest order term of \spad{f}.
    pole? : % -> Boolean
      ++ \spad{pole?(f)} determines if the power series f has a pole.
    complete : % -> %
      ++ \spad{complete(f)} causes all terms of f to be computed.
      ++ Note: this results in an infinite loop
      ++ if f has infinitely many terms.

   add
    n : I    * ps : % == (zero? n => 0; map((r1 : Coef) : Coef +-> n * r1, ps))
    r : Coef * ps : % == (zero? r => 0; map((r1 : Coef) : Coef +-> r * r1, ps))
    ps : % * r : Coef == (zero? r => 0; map((r1 : Coef) : Coef +-> r1 * r, ps))
    - ps          == map((r1 : Coef) : Coef +-> - r1, ps)

    if Coef has Algebra Fraction Integer then
      r : RN * ps : % == (zero? r => 0; map((r1 : Coef) : Coef +-> r * r1, ps))
      ps : % * r : RN == (zero? r => 0; map((r1 : Coef) : Coef +-> r1 * r, ps))

    if Coef has Field then
      ps : % / r : Coef == map((r1 : Coef) : Coef +-> r1 / r, ps)

)abbrev category UPSCAT UnivariatePowerSeriesCategory
++ Author: Clifton J. Williamson
++ Date Created: 21 December 1989
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ Examples:
++ References:
++ Description:
++   \spadtype{UnivariatePowerSeriesCategory} is the most general
++   univariate power series category with exponents in an ordered
++   abelian monoid.
++   Note: this category exports a substitution function if it is
++   possible to multiply exponents.
++   Note: this category exports a derivative operation if it is possible
++   to multiply coefficients by exponents.
UnivariatePowerSeriesCategory(Coef, Expon) : Category == Definition where
  Coef   : Ring
  Expon  : OrderedAbelianMonoid
  Term ==> Record(k : Expon, c : Coef)

  Definition ==> PowerSeriesCategory(Coef, Expon, SingletonAsOrderedSet) with

    terms : % -> Stream Term
      ++ \spad{terms(f(x))} returns a stream of non-zero terms, where a
      ++ a term is an exponent-coefficient pair.  The terms in the stream
      ++ are ordered by increasing order of exponents.
      ++ Warning: If the series f has only finitely many non-zero terms,
      ++ then accessing the resulting stream might lead to an infinite
      ++ search for the next non-zero coefficient.
    --series: Stream Term -> %
      --++ \spad{series(st)} creates a series from a stream of non-zero terms,
      --++ where a term is an exponent-coefficient pair.  The terms in the
      --++ stream should be ordered by increasing order of exponents.
    elt : (%, Expon) -> Coef
      ++ \spad{elt(f(x), r)} returns the coefficient of the term of degree r in
      ++ \spad{f(x)}.  This is the same as the function \spadfun{coefficient}.
    variable : % -> Symbol
      ++ \spad{variable(f)} returns the (unique) power series variable of
      ++ the power series f.
    center : % -> Coef
      ++ \spad{center(f)} returns the point about which the series f is
      ++ expanded.
    multiplyExponents : (%, PositiveInteger) -> %
      ++ \spad{multiplyExponents(f, n)} multiplies all exponents of the power
      ++ series f by the positive integer n.
    order : % -> Expon
      ++ \spad{order(f)} is the degree of the lowest order non-zero term in f.
      ++ This will result in an infinite loop if f has no non-zero terms.
    order : (%, Expon) -> Expon
      ++ \spad{order(f, n) = min(m, n)}, where m is the degree of the
      ++ lowest order non-zero term in f.
    truncate : (%, Expon) -> %
      ++ \spad{truncate(f, k)} returns a (finite) power series consisting of
      ++ the sum of all terms of f of degree \spad{<= k}.
    truncate : (%, Expon, Expon) -> %
      ++ \spad{truncate(f, k1, k2)} returns a (finite) power
      ++ series consisting of
      ++ the sum of all terms of f of degree d with \spad{k1 <= d <= k2}.
    if Coef has coerce : Symbol -> Coef then
      if Coef has "^":(Coef,Expon) -> Coef then
        approximate : (%, Expon) -> Coef
          ++ \spad{approximate(f)} returns a truncated power series with the
          ++ series variable viewed as an element of the coefficient domain.
    extend : (%, Expon) -> %
      ++ \spad{extend(f, n)} causes all terms of f of degree <= n to be computed.
    if Expon has SemiGroup then Eltable(%, %)
    if Coef has "*": (Expon,Coef) -> Coef then
      DifferentialRing
      --!! DifferentialExtension Coef
      if Coef has PartialDifferentialRing Symbol then
        PartialDifferentialRing Symbol
    if Coef has "^": (Coef,Expon) -> Coef then
      eval : (%, Coef) -> Stream Coef
        ++ \spad{eval(f, a)} evaluates a power series at a value in the
        ++ ground ring by returning a stream of partial sums.

   add
    degree f == order f
    leadingCoefficient f == coefficient(f, order f)
    leadingMonomial f ==
      ord := order f
      monomial(coefficient(f, ord), ord)
    reductum f == f - leadingMonomial f

)abbrev category RATPSCT UnivariateSeriesWithRationalExponents
UnivariateSeriesWithRationalExponents(Coef, Expon) : Category == Def where
  Coef   : Ring
  Expon  : OrderedAbelianMonoid
  Def ==> UnivariatePowerSeriesCategory(Coef, Expon) with
    if Coef has Algebra Fraction Integer then
      integrate : % -> %
        ++ \spad{integrate(f(x))} returns an anti-derivative of the power
        ++ series \spad{f(x)} with constant coefficient 0.
        ++ We may integrate a series when we can divide coefficients
        ++ by integers.
      if Coef has integrate : (Coef, Symbol) -> Coef and _
         Coef has variables : Coef -> List Symbol then
        integrate : (%, Symbol) -> %
          ++ \spad{integrate(f(x), y)} returns an anti-derivative of the
          ++ power series \spad{f(x)} with respect to the variable \spad{y}.
      RadicalCategory
        --++ We provide rational powers when we can divide coefficients
        --++ by integers.
      TranscendentalFunctionCategory
        --++ We provide transcendental functions when we can divide
        --++ coefficients by integers.

)abbrev category UTSCAT UnivariateTaylorSeriesCategory
++ Author: Clifton J. Williamson
++ Date Created: 21 December 1989
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords: series, Taylor, linebacker
++ Examples:
++ References:
++ Description:
++   \spadtype{UnivariateTaylorSeriesCategory} is the category of Taylor
++   series in one variable.
UnivariateTaylorSeriesCategory(Coef) : Category == Definition where
  Coef  : Ring
  I    ==> Integer
  L    ==> List
  NNI  ==> NonNegativeInteger
  OUT  ==> OutputForm
  RN   ==> Fraction Integer
  STTA ==> StreamTaylorSeriesOperations Coef
  STTF ==> StreamTranscendentalFunctions Coef
  STNC ==> StreamTranscendentalFunctionsNonCommutative Coef
  Term ==> Record(k : NNI, c : Coef)

  Definition ==> UnivariateSeriesWithRationalExponents(Coef, NNI) with

    series : Stream Term -> %
      ++ \spad{series(st)} creates a series from a stream of non-zero terms,
      ++ where a term is an exponent-coefficient pair.  The terms in the
      ++ stream should be ordered by increasing order of exponents.
    coefficients : % -> Stream Coef
      ++ \spad{coefficients(a0 + a1 x + a2 x^2 + ...)} returns a stream
      ++ of coefficients: \spad{[a0, a1, a2, ...]}. The entries of the stream
      ++ may be zero.
    series : Stream Coef -> %
      ++ \spad{series([a0, a1, a2, ...])} is the Taylor series
      ++ \spad{a0 + a1 x + a2 x^2 + ...}.
    quoByVar : % -> %
      ++ \spad{quoByVar(a0 + a1 x + a2 x^2 + ...)}
      ++ returns \spad{a1 + a2 x + a3 x^2 + ...}
      ++ Thus, this function substracts the constant term and divides by
      ++ the series variable.  This function is used when Laurent series
      ++ are represented by a Taylor series and an order.
    multiplyCoefficients : (I -> Coef, %) -> %
      ++ \spad{multiplyCoefficients(f, sum(n = 0..infinity, a[n] * x^n))}
      ++ returns \spad{sum(n = 0..infinity, f(n) * a[n] * x^n)}.
      ++ This function is used when Laurent series are represented by
      ++ a Taylor series and an order.
    polynomial : (%, NNI) -> Polynomial Coef
      ++ \spad{polynomial(f, k)} returns a polynomial consisting of the sum
      ++ of all terms of f of degree \spad{<= k}.
    polynomial : (%, NNI, NNI) -> Polynomial Coef
      ++ \spad{polynomial(f, k1, k2)} returns a polynomial consisting of the
      ++ sum of all terms of f of degree d with \spad{k1 <= d <= k2}.

    if Coef has Field then
      "^": (%,Coef) -> %
        ++ \spad{f(x) ^ a} computes a power of a power series.
        ++ When the coefficient ring is a field, we may raise a series
        ++ to an exponent from the coefficient ring provided that the
        ++ constant coefficient of the series is 1.

   add

    import from Stream(Coef)

    zero? x ==
      empty? (coefs := coefficients x) => true
      (zero? frst coefs) and (empty? rst coefs) => true
      false

--% OutputForms

--  We provide default output functions on UTSCAT using the functions
--  'coefficients', 'center', and 'variable'.

    factorials? : () -> Boolean
    -- check a global Lisp variable
    factorials?() == false

    termOutput : (I, Coef, OUT) -> OUT
    termOutput(k, c, vv) ==
    -- creates a term c * vv ^ k
      k = 0 => c :: OUT
      mon := (k = 1 => vv; vv ^ (k :: OUT))
--       if factorials?() and k > 1 then
--         c := factorial(k)$IntegerCombinatoricFunctions * c
--         mon := mon / hconcat(k :: OUT,"!" :: OUT)
      c = 1 => mon
      c = -1 => -mon
      (c :: OUT) * mon

    showAll? : () -> Boolean
    -- check a global Lisp variable
    showAll?() == _$streamsShowAll$Lisp

    coerce(p : %) : OUT ==
      empty? (uu := coefficients p) => (0$Coef) :: OUT
      var := variable p; cen := center p
      vv :=
        zero? cen => var :: OUT
        paren(var :: OUT - cen :: OUT)
      n : NNI ; count : NNI := _$streamCount$Lisp
      l : L OUT := empty()
      for n in 0..count while not empty? uu repeat
        if frst(uu) ~= 0 then
          l := concat(termOutput(n :: I, frst uu, vv), l)
        uu := rst uu
      if showAll?() then
        uu1 := uu
        for n in (count + 1).. while explicitEntries? uu and _
               not eq?(uu1, rst uu) repeat
          if frst(uu) ~= 0 then
            l := concat(termOutput(n :: I, frst uu, vv), l)
          if odd?(n) then uu1 := rst(uu1)
          uu := rst uu
      l :=
        explicitlyEmpty? uu => l
        eq?(uu, rst uu) and frst uu = 0 => l
        concat(prefix('O :: OUT, [vv ^ (n :: OUT)]), l)
      empty? l => (0$Coef) :: OUT
      reduce("+",reverse! l)

    if Coef has Field then
      (x : %) ^ (r : Coef) == series power(r, coefficients x)$STTA

    if Coef has Algebra Fraction Integer then
      if Coef has CommutativeRing then
        (x : %) ^ (y : %)    == series(coefficients x ^$STTF coefficients y)
        (x : %) ^ (r : RN)   == series powern(r, coefficients x)$STTA

        exp x == series exp(coefficients x)$STTF
        log x == series log(coefficients x)$STTF

        sin x == series sin(coefficients x)$STTF
        cos x == series cos(coefficients x)$STTF
        tan x == series tan(coefficients x)$STTF
        cot x == series cot(coefficients x)$STTF
        sec x == series sec(coefficients x)$STTF
        csc x == series csc(coefficients x)$STTF

        asin x == series asin(coefficients x)$STTF
        acos x == series acos(coefficients x)$STTF
        atan x == series atan(coefficients x)$STTF
        acot x == series acot(coefficients x)$STTF
        asec x == series asec(coefficients x)$STTF
        acsc x == series acsc(coefficients x)$STTF

        sinh x == series sinh(coefficients x)$STTF
        cosh x == series cosh(coefficients x)$STTF
        tanh x == series tanh(coefficients x)$STTF
        coth x == series coth(coefficients x)$STTF
        sech x == series sech(coefficients x)$STTF
        csch x == series csch(coefficients x)$STTF

        asinh x == series asinh(coefficients x)$STTF
        acosh x == series acosh(coefficients x)$STTF
        atanh x == series atanh(coefficients x)$STTF
        acoth x == series acoth(coefficients x)$STTF
        asech x == series asech(coefficients x)$STTF
        acsch x == series acsch(coefficients x)$STTF

      else
        (x : %) ^ (y : %) == series(coefficients x ^$STNC coefficients y)

        (x : %) ^ (r : RN) ==
          coefs := coefficients x
          empty? coefs =>
            positive? r => 0
            zero? r => error "0^0 undefined"
            error "0 raised to a negative power"
          not (frst coefs = 1) =>
            error "^: constant coefficient should be 1"
          coefs := concat(0, rst coefs)
          onePlusX := monom(1, 0)$STTA + $STTA monom(1, 1)$STTA
          ratPow := powern(r, onePlusX)$STTA
          series compose(ratPow, coefs)$STTA

        exp x == series exp(coefficients x)$STNC
        log x == series log(coefficients x)$STNC

        sin x == series sin(coefficients x)$STNC
        cos x == series cos(coefficients x)$STNC
        tan x == series tan(coefficients x)$STNC
        cot x == series cot(coefficients x)$STNC
        sec x == series sec(coefficients x)$STNC
        csc x == series csc(coefficients x)$STNC

        asin x == series asin(coefficients x)$STNC
        acos x == series acos(coefficients x)$STNC
        atan x == series atan(coefficients x)$STNC
        acot x == series acot(coefficients x)$STNC
        asec x == series asec(coefficients x)$STNC
        acsc x == series acsc(coefficients x)$STNC

        sinh x == series sinh(coefficients x)$STNC
        cosh x == series cosh(coefficients x)$STNC
        tanh x == series tanh(coefficients x)$STNC
        coth x == series coth(coefficients x)$STNC
        sech x == series sech(coefficients x)$STNC
        csch x == series csch(coefficients x)$STNC

        asinh x == series asinh(coefficients x)$STNC
        acosh x == series acosh(coefficients x)$STNC
        atanh x == series atanh(coefficients x)$STNC
        acoth x == series acoth(coefficients x)$STNC
        asech x == series asech(coefficients x)$STNC
        acsch x == series acsch(coefficients x)$STNC

)abbrev category ULSCAT UnivariateLaurentSeriesCategory
++ Author: Clifton J. Williamson
++ Date Created: 21 December 1989
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords: series, Laurent
++ Examples:
++ References:
++ Description:
++   \spadtype{UnivariateLaurentSeriesCategory} is the category of
++   Laurent series in one variable.
UnivariateLaurentSeriesCategory(Coef) : Category == Definition where
  Coef  : Ring
  I    ==> Integer
  NNI  ==> NonNegativeInteger
  Term ==> Record(k : I, c : Coef)

  Definition ==> UnivariateSeriesWithRationalExponents(Coef, Integer) with

    series : Stream Term -> %
      ++ \spad{series(st)} creates a series from a stream of non-zero terms,
      ++ where a term is an exponent-coefficient pair.  The terms in the
      ++ stream should be ordered by increasing order of exponents.
    laurent : (I, Stream Coef) -> %
      ++ \spad{laurent(n, st)} returns \spad{xn * series st} where
      ++ \spad{xn = monomial(1, n)} and \spad{series st} stands for
      ++ the power series with coefficients given by the stream st.
    multiplyCoefficients : (I -> Coef, %) -> %
      ++ \spad{multiplyCoefficients(f, sum(n = n0..infinity, a[n] * x^n)) =
      ++ sum(n = 0..infinity, f(n) * a[n] * x^n)}.
      ++ This function is used when Puiseux series are represented by
      ++ a Laurent series and an exponent.
    if Coef has IntegralDomain then
      rationalFunction : (%, I) -> Fraction Polynomial Coef
        ++ \spad{rationalFunction(f, k)} returns a rational function
        ++ consisting of the sum of all terms of f of degree <= k.
      rationalFunction : (%, I, I) -> Fraction Polynomial Coef
        ++ \spad{rationalFunction(f, k1, k2)} returns a rational function
        ++ consisting of the sum of all terms of f of degree d with
        ++ \spad{k1 <= d <= k2}.

    if Coef has Field then Field
        --++ Univariate Laurent series over a field form a field.
        --++ In fact, K((x)) is the quotient field of K[[x]].
   add
    laurentTerms(n: I, st: Stream Coef): Stream Term == delay
        empty? st => empty()$Stream(Term)
        c: Coef := frst st
        zero? c => laurentTerms(n+1, rst st)
        concat([n, c], laurentTerms(n+1, rst st))
    laurent(n: I, st: Stream Coef): % == series laurentTerms(n, st)

)abbrev category UPXSCAT UnivariatePuiseuxSeriesCategory
++ Author: Clifton J. Williamson
++ Date Created: 21 December 1989
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords: series, Puiseux
++ Examples:
++ References:
++ Description:
++   \spadtype{UnivariatePuiseuxSeriesCategory} is the category of Puiseux
++   series in one variable.
UnivariatePuiseuxSeriesCategory(Coef) : Category == Definition where
  Coef : Ring
  NNI  ==> NonNegativeInteger
  RN   ==> Fraction Integer
  Term ==> Record(k : RN, c : Coef)

  Definition ==> UnivariateSeriesWithRationalExponents(Coef, RN) with

    series : (NNI, Stream Term) -> %
      ++ \spad{series(n, st)} creates a series from a common denomiator and
      ++ a stream of non-zero terms, where a term is an exponent-coefficient
      ++ pair.  The terms in the stream should be ordered by increasing order
      ++ of exponents and \spad{n} should be a common denominator for the
      ++ exponents in the stream of terms.
    multiplyExponents : (%, Fraction Integer) -> %
      ++ \spad{multiplyExponents(f, r)} multiplies all exponents of the power
      ++ series f by the positive rational number r.

    if Coef has Field then Field
        --++ Univariate Puiseux series over a field form a field.

)abbrev category MTSCAT MultivariateTaylorSeriesCategory
++ Author: Clifton J. Williamson
++ Date Created: 6 March 1990
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords: multivariate, Taylor, series
++ Examples:
++ References:
++ Description:
++   \spadtype{MultivariateTaylorSeriesCategory} is the most general
++   multivariate Taylor series category.
MultivariateTaylorSeriesCategory(Coef, Var) : Category == Definition where
  Coef  : Ring
  Var   : OrderedSet
  L   ==> List
  NNI ==> NonNegativeInteger

  Definition ==> Join(PartialDifferentialRing Var, _
                     PowerSeriesCategory(Coef, IndexedExponents Var, Var), _
                     InnerEvalable(Var, %), Evalable %) with
    coefficient : (%, Var, NNI) -> %
      ++ \spad{coefficient(f, x, n)} returns the coefficient of \spad{x^n} in f.
    coefficient : (%, L Var, L NNI) -> %
      ++ \spad{coefficient(f, [x1, x2, ..., xk], [n1, n2, ..., nk])} returns the
      ++ coefficient of \spad{x1^n1 * ... * xk^nk} in f.
    extend : (%, NNI) -> %
      ++ \spad{extend(f, n)} causes all terms of f of degree
      ++ \spad{<= n} to be computed.
    monomial : (%, Var, NNI) -> %
      ++ \spad{monomial(a, x, n)} returns  \spad{a*x^n}.
    monomial : (%, L Var, L NNI) -> %
      ++ \spad{monomial(a, [x1, x2, ..., xk], [n1, n2, ..., nk])} returns
      ++ \spad{a * x1^n1 * ... * xk^nk}.
    order : (%, Var) -> NNI
      ++ \spad{order(f, x)} returns the order of f viewed as a series in x
      ++ may result in an infinite loop if f has no non-zero terms.
    order : (%, Var, NNI) -> NNI
      ++ \spad{order(f, x, n)} returns \spad{min(n, order(f, x))}.
    polynomial : (%, NNI) -> Polynomial Coef
      ++ \spad{polynomial(f, k)} returns a polynomial consisting of the sum
      ++ of all terms of f of degree \spad{<= k}.
    polynomial : (%, NNI, NNI) -> Polynomial Coef
      ++ \spad{polynomial(f, k1, k2)} returns a polynomial consisting of the
      ++ sum of all terms of f of degree d with \spad{k1 <= d <= k2}.
    if Coef has Algebra Fraction Integer then
      integrate : (%, Var) -> %
        ++ \spad{integrate(f, x)} returns the anti-derivative of the power
        ++ series \spad{f(x)} with respect to the variable x with constant
        ++ coefficient 1.  We may integrate a series when we can divide
        ++ coefficients by integers.
      RadicalCategory
        --++ We provide rational powers when we can divide coefficients
        --++ by integers.
      TranscendentalFunctionCategory
        --++ We provide transcendental functions when we can divide
        --++ coefficients by integers.

   add

    coefficient(s : %, v : Var, n : NNI) : % == coefficient(s, [v], [n])



--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.
