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

)abbrev domain SUPXS SparseUnivariatePuiseuxSeries
++ Author: Clifton J. Williamson
++ Date Created: 11 November 1994
++ Date Last Updated: June 18, 2010
++ Basic Operations:
++ Related Domains: InnerSparseUnivariatePowerSeries,
++   SparseUnivariateTaylorSeries, SparseUnivariateLaurentSeries
++ Also See:
++ AMS Classifications:
++ Keywords: sparse, series
++ Examples:
++ References:
++ Description: Sparse Puiseux series in one variable
++   \spadtype{SparseUnivariatePuiseuxSeries} is a domain representing Puiseux
++   series in one variable with coefficients in an arbitrary ring.  The
++   parameters of the type specify the coefficient ring, the power series
++   variable, and the center of the power series expansion.  For example,
++   \spad{SparseUnivariatePuiseuxSeries(Integer,x,3)} represents Puiseux
++   series in \spad{(x - 3)} with \spadtype{Integer} coefficients.
SparseUnivariatePuiseuxSeries(Coef,var,cen): Exports == Implementation where
  Coef : Ring
  var  : Symbol
  cen  : Coef
  I    ==> Integer
  NNI  ==> NonNegativeInteger
  OUT  ==> OutputForm
  RN   ==> Fraction Integer
  SUTS ==> SparseUnivariateTaylorSeries(Coef,var,cen)
  SULS ==> SparseUnivariateLaurentSeries(Coef,var,cen)
  SUPS ==> InnerSparseUnivariatePowerSeries(Coef)

  Exports ==> Join(UnivariatePuiseuxSeriesConstructorCategory(Coef,SULS),_
                   PartialDifferentialDomain(%,Variable var),_
                   RetractableTo SUTS,CoercibleFrom Variable var) with
    if Coef has Algebra Fraction Integer then
      integrate: (%,Variable(var)) -> %
        ++ \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.

  Implementation ==> UnivariatePuiseuxSeriesConstructor(Coef,SULS) add

    Rep := Record(expon:RN,lSeries:SULS)

    getExpon: % -> RN
    getExpon pxs == pxs.expon

    variable x == var
    center   x == cen

    coerce(v: Variable(var)) ==
      zero? cen => monomial(1,1)
      monomial(1,1) + monomial(cen,0)

    coerce(uts:SUTS) == uts :: SULS :: %

    retractIfCan(upxs:%):Union(SUTS,"failed") ==
      (uls := retractIfCan(upxs)@Union(SULS,"failed")) case "failed" =>
        "failed"
      retractIfCan(uls :: SULS)@Union(SUTS,"failed")

    if Coef has "*": (Fraction Integer, Coef) -> Coef then
      differentiate(upxs:%,v:Variable(var)) == differentiate upxs

    if Coef has Algebra Fraction Integer then
      integrate(upxs:%,v:Variable(var)) == integrate upxs

--% OutputForms

    coerce(x:%): OUT ==
      sups : SUPS := laurentRep(x) pretend SUPS
      st := getStream sups; refer := getRef sups
      if not(explicitlyEmpty? st or explicitEntries? st) _
        and (nx := retractIfCan(deref refer)@Union(I,"failed")) case I then
        count : NNI := _$streamCount$Lisp
        degr := min(count,(nx :: I) + count + 1)
        extend(sups,degr)
      seriesToOutputForm(st,refer,variable x,center x,rationalPower x)

