--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 package STTF StreamTranscendentalFunctions
++ Author: William Burge, Clifton J. Williamson
++ Date Created: 1986
++ Date Last Updated: 6 March 1995
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords: Taylor series, elementary function, transcendental function
++ Examples:
++ References:
++ Description:
++   StreamTranscendentalFunctions implements transcendental functions on
++   Taylor series, where a Taylor series is represented by a stream of
++   its coefficients.
StreamTranscendentalFunctions(Coef): Exports == Implementation where
  Coef : Algebra Fraction Integer
  L   ==> List
  I   ==> Integer
  RN  ==> Fraction Integer
  SG  ==> String
  ST  ==> Stream Coef
  STT ==> StreamTaylorSeriesOperations Coef
  YS  ==> Y$ParadoxicalCombinatorsForStreams(Coef)

  Exports ==> with
--% Exponentials and Logarithms
    exp     : ST -> ST
      ++ exp(st) computes the exponential of a power series st.
    log     : ST -> ST
      ++ log(st) computes the log of a power series.
    **    : (ST,ST) -> ST
      ++ st1 ** st2 computes the power of a power series st1 by another
      ++ power series st2.

--% TrigonometricFunctionCategory
    sincos  : ST -> Record(sin:ST, cos:ST)
      ++ sincos(st) returns a record containing the sine and cosine
      ++ of a power series st.
    sin     : ST -> ST
      ++ sin(st) computes sine of a power series st.
    cos     : ST -> ST
      ++ cos(st) computes cosine of a power series st.
    tan     : ST -> ST
      ++ tan(st) computes tangent of a power series st.
    cot     : ST -> ST
      ++ cot(st) computes cotangent of a power series st.
    sec     : ST -> ST
      ++ sec(st) computes secant of a power series st.
    csc     : ST -> ST
      ++ csc(st) computes cosecant of a power series st.
    asin    : ST -> ST
      ++ asin(st) computes arcsine of a power series st.
    acos    : ST -> ST
      ++ acos(st) computes arccosine of a power series st.
    atan    : ST -> ST
      ++ atan(st) computes arctangent of a power series st.
    acot    : ST -> ST
      ++ acot(st) computes arccotangent of a power series st.
    asec    : ST -> ST
      ++ asec(st) computes arcsecant of a power series st.
    acsc    : ST -> ST
      ++ acsc(st) computes arccosecant of a power series st.

--% HyperbloicTrigonometricFunctionCategory
    sinhcosh: ST -> Record(sinh:ST, cosh:ST)
      ++ sinhcosh(st) returns a record containing
      ++ the hyperbolic sine and cosine
      ++ of a power series st.
    sinh    : ST -> ST
      ++ sinh(st) computes the hyperbolic sine of a power series st.
    cosh    : ST -> ST
      ++ cosh(st) computes the hyperbolic cosine of a power series st.
    tanh    : ST -> ST
      ++ tanh(st) computes the hyperbolic tangent of a power series st.
    coth    : ST -> ST
      ++ coth(st) computes the hyperbolic cotangent of a power series st.
    sech    : ST -> ST
      ++ sech(st) computes the hyperbolic secant of a power series st.
    csch    : ST -> ST
      ++ csch(st) computes the hyperbolic cosecant of a power series st.
    asinh   : ST -> ST
      ++ asinh(st) computes the inverse hyperbolic sine of a power series st.
    acosh   : ST -> ST
      ++ acosh(st) computes the inverse hyperbolic cosine
      ++ of a power series st.
    atanh   : ST -> ST
      ++ atanh(st) computes the inverse hyperbolic tangent
      ++ of a power series st.
    acoth   : ST -> ST
      ++ acoth(st) computes the inverse hyperbolic
      ++ cotangent of a power series st.
    asech   : ST -> ST
      ++ asech(st) computes the inverse hyperbolic secant of a
      ++ power series st.
    acsch   : ST -> ST
      ++ acsch(st) computes the inverse hyperbolic
      ++ cosecant of a power series st.

  Implementation ==> add
    import StreamTaylorSeriesOperations Coef

    TRANSFCN : Boolean := Coef has TranscendentalFunctionCategory

--% Error Reporting

    TRCONST : SG := "series expansion involves transcendental constants"
    NPOWERS : SG := "series expansion has terms of negative degree"
    FPOWERS : SG := "series expansion has terms of fractional degree"
    MAYFPOW : SG := "series expansion may have terms of fractional degree"
    LOGS : SG := "series expansion has logarithmic term"
    NPOWLOG : SG :=
       "series expansion has terms of negative degree or logarithmic term"
    FPOWLOG : SG :=
       "series expansion has terms of fractional degree or logarithmic term"
    NOTINV : SG := "leading coefficient not invertible"

--% Exponentials and Logarithms

    expre:(Coef,ST,ST) -> ST
    expre(r,e,dx) == lazyIntegrate(r,e*dx)

    exp z ==
      empty? z => 1@Coef :: ST
      (coef := frst z) = 0 => YS expre(1,#1,deriv z)
      TRANSFCN => YS expre(exp coef,#1,deriv z)
      error concat("exp: ",TRCONST)

    log z ==
      empty? z => error "log: constant coefficient should not be 0"
      (coef := frst z) = 0 => error "log: constant coefficient should not be 0"
      coef = 1 => lazyIntegrate(0,deriv z/z)
      TRANSFCN => lazyIntegrate(log coef,deriv z/z)
      error concat("log: ",TRCONST)

    z1:ST ** z2:ST == exp(z2 * log z1)

--% Trigonometric Functions

    sincosre:(Coef,Coef,L ST,ST,Coef) -> L ST
    sincosre(rs,rc,sc,dx,sign) ==
      [lazyIntegrate(rs,(second sc)*dx),lazyIntegrate(rc,sign*(first sc)*dx)]

    -- When the compiler had difficulties with the above definition,
    -- I did the following to help it:

    -- sincosre:(Coef,Coef,L ST,ST,Coef) -> L ST
    -- sincosre(rs,rc,sc,dx,sign) ==
      -- st1 : ST := (second sc) * dx
      -- st2 : ST := (first sc) * dx
      -- st2 := sign * st2
      -- [lazyIntegrate(rs,st1),lazyIntegrate(rc,st2)]

    sincos z ==
      empty? z => [0@Coef :: ST,1@Coef :: ST]
      l :=
        (coef := frst z) = 0 => YS(sincosre(0,1,#1,deriv z,-1),2)
        TRANSFCN => YS(sincosre(sin coef,cos coef,#1,deriv z,-1),2)
        error concat("sincos: ",TRCONST)
      [first l,second l]

    sin z == sincos(z).sin
    cos z == sincos(z).cos

    tanre:(Coef,ST,ST,Coef) -> ST
    tanre(r,t,dx,sign) == lazyIntegrate(r,((1@Coef :: ST) + sign*t*t)*dx)

    -- When the compiler had difficulties with the above definition,
    -- I did the following to help it:

    -- tanre:(Coef,ST,ST,Coef) -> ST
    -- tanre(r,t,dx,sign) ==
      -- st1 : ST := t * t
      -- st1 := sign * st1
      -- st2 : ST := 1 :: ST
      -- st1 := st2 + st1
      -- st1 := st1 * dx
      -- lazyIntegrate(r,st1)

    tan z ==
      empty? z => 0@Coef :: ST
      (coef := frst z) = 0 => YS tanre(0,#1,deriv z,1)
      TRANSFCN => YS tanre(tan coef,#1,deriv z,1)
      error concat("tan: ",TRCONST)

    cotre:(Coef,ST,ST) -> ST
    cotre(r,t,dx) == lazyIntegrate(r,-((1@Coef :: ST) + t*t)*dx)

    -- When the compiler had difficulties with the above definition,
    -- I did the following to help it:

    -- cotre:(Coef,ST,ST) -> ST
    -- cotre(r,t,dx) ==
      -- st1 : ST := t * t
      -- st2 : ST := 1 :: ST
      -- st1 := st2 + st1
      -- st1 := st1 * dx
      -- st1 := -st1
      -- lazyIntegrate(r,st1)

    cot z ==
      empty? z => error "cot: cot(0) is undefined"
      (coef := frst z) = 0 => error concat("cot: ",NPOWERS)
      TRANSFCN => YS cotre(cot coef,#1,deriv z)
      error concat("cot: ",TRCONST)

    sec z ==
      empty? z => 1@Coef :: ST
      frst z = 0 => recip(cos z) :: ST
      TRANSFCN =>
        cosz := cos z
        first cosz = 0 => error concat("sec: ",NPOWERS)
        recip(cosz) :: ST
      error concat("sec: ",TRCONST)

    csc z ==
      empty? z => error "csc: csc(0) is undefined"
      TRANSFCN =>
        sinz := sin z
        first sinz = 0 => error concat("csc: ",NPOWERS)
        recip(sinz) :: ST
      error concat("csc: ",TRCONST)

    orderOrFailed : ST -> Union(I,"failed")
    orderOrFailed x ==
    -- returns the order of x or "failed"
    -- if -1 is returned, the series is identically zero
      for n in 0..1000 repeat
        empty? x => return -1
        not zero? frst x => return n :: I
        x := rst x
      "failed"

    asin z ==
      empty? z => 0@Coef :: ST
      (coef := frst z) = 0 =>
        integrate(0,powern(-1/2,(1@Coef :: ST) - z*z) * (deriv z))
      TRANSFCN =>
        coef = 1 or coef = -1 =>
          x := (1@Coef :: ST) - z*z
          -- compute order of 'x'
          (ord := orderOrFailed x) case "failed" =>
            error concat("asin: ",MAYFPOW)
          (order := ord :: I) = -1 => return asin(coef) :: ST
          odd? order => error concat("asin: ",FPOWERS)
          squirt := powern(1/2,x)
          (quot := (deriv z) exquo squirt) case "failed" =>
             error concat("asin: ",NOTINV)
          integrate(asin coef,quot :: ST)
        integrate(asin coef,powern(-1/2,(1@Coef :: ST) - z*z) * (deriv z))
      error concat("asin: ",TRCONST)

    acos z ==
      empty? z =>
        TRANSFCN => acos(0)$Coef :: ST
        error concat("acos: ",TRCONST)
      TRANSFCN =>
        coef := frst z
        coef = 1 or coef = -1 =>
          x := (1@Coef :: ST) - z*z
          -- compute order of 'x'
          (ord := orderOrFailed x) case "failed" =>
            error concat("acos: ",MAYFPOW)
          (order := ord :: I) = -1 => return acos(coef) :: ST
          odd? order => error concat("acos: ",FPOWERS)
          squirt := powern(1/2,x)
          (quot := (-deriv z) exquo squirt) case "failed" =>
             error concat("acos: ",NOTINV)
          integrate(acos coef,quot :: ST)
        integrate(acos coef,-powern(-1/2,(1@Coef :: ST) - z*z) * (deriv z))
      error concat("acos: ",TRCONST)

    atan z ==
      empty? z => 0@Coef :: ST
      (coef := frst z) = 0 =>
        integrate(0,(recip((1@Coef :: ST) + z*z) :: ST) * (deriv z))
      TRANSFCN =>
        (y := recip((1@Coef :: ST) + z*z)) case "failed" =>
          error concat("atan: ",LOGS)
        integrate(atan coef,(y :: ST) * (deriv z))
      error concat("atan: ",TRCONST)

    acot z ==
      empty? z =>
        TRANSFCN => acot(0)$Coef :: ST
        error concat("acot: ",TRCONST)
      TRANSFCN =>
        (y := recip((1@Coef :: ST) + z*z)) case "failed" =>
          error concat("acot: ",LOGS)
        integrate(acot frst z,-(y :: ST) * (deriv z))
      error concat("acot: ",TRCONST)

    asec z ==
      empty? z => error "asec: constant coefficient should not be 0"
      TRANSFCN =>
        (coef := frst z) = 0 =>
          error "asec: constant coefficient should not be 0"
        coef = 1 or coef = -1 =>
          x := z*z - (1@Coef :: ST)
          -- compute order of 'x'
          (ord := orderOrFailed x) case "failed" =>
            error concat("asec: ",MAYFPOW)
          (order := ord :: I) = -1 => return asec(coef) :: ST
          odd? order => error concat("asec: ",FPOWERS)
          squirt := powern(1/2,x)
          (quot := (deriv z) exquo squirt) case "failed" =>
            error concat("asec: ",NOTINV)
          (quot2 := (quot :: ST) exquo z) case "failed" =>
            error concat("asec: ",NOTINV)
          integrate(asec coef,quot2 :: ST)
        integrate(asec coef,(powern(-1/2,z*z-(1@Coef::ST))*(deriv z)) / z)
      error concat("asec: ",TRCONST)

    acsc z ==
      empty? z => error "acsc: constant coefficient should not be zero"
      TRANSFCN =>
        (coef := frst z) = 0 =>
          error "acsc: constant coefficient should not be zero"
        coef = 1 or coef = -1 =>
          x := z*z - (1@Coef :: ST)
          -- compute order of 'x'
          (ord := orderOrFailed x) case "failed" =>
            error concat("acsc: ",MAYFPOW)
          (order := ord :: I) = -1 => return acsc(coef) :: ST
          odd? order => error concat("acsc: ",FPOWERS)
          squirt := powern(1/2,x)
          (quot := (-deriv z) exquo squirt) case "failed" =>
            error concat("acsc: ",NOTINV)
          (quot2 := (quot :: ST) exquo z) case "failed" =>
            error concat("acsc: ",NOTINV)
          integrate(acsc coef,quot2 :: ST)
        integrate(acsc coef,-(powern(-1/2,z*z-(1@Coef::ST))*(deriv z)) / z)
      error concat("acsc: ",TRCONST)

--% Hyperbolic Trigonometric Functions

    sinhcosh z ==
      empty? z => [0@Coef :: ST,1@Coef :: ST]
      l :=
        (coef := frst z) = 0 => YS(sincosre(0,1,#1,deriv z,1),2)
        TRANSFCN => YS(sincosre(sinh coef,cosh coef,#1,deriv z,1),2)
        error concat("sinhcosh: ",TRCONST)
      [first l,second l]

    sinh z == sinhcosh(z).sinh
    cosh z == sinhcosh(z).cosh

    tanh z ==
      empty? z => 0@Coef :: ST
      (coef := frst z) = 0 => YS tanre(0,#1,deriv z,-1)
      TRANSFCN => YS tanre(tanh coef,#1,deriv z,-1)
      error concat("tanh: ",TRCONST)

    coth z ==
      tanhz := tanh z
      empty? tanhz => error "coth: coth(0) is undefined"
      (frst tanhz) = 0 => error concat("coth: ",NPOWERS)
      recip(tanhz) :: ST

    sech z ==
      coshz := cosh z
      (empty? coshz) or (frst coshz = 0) => error concat("sech: ",NPOWERS)
      recip(coshz) :: ST

    csch z ==
      sinhz := sinh z
      (empty? sinhz) or (frst sinhz = 0) => error concat("csch: ",NPOWERS)
      recip(sinhz) :: ST

    asinh z ==
      empty? z => 0@Coef :: ST
      (coef := frst z) = 0 => log(z + powern(1/2,(1@Coef :: ST) + z*z))
      TRANSFCN =>
        x := (1@Coef :: ST) + z*z
        -- compute order of 'x', in case coefficient(z,0) = +- %i
        (ord := orderOrFailed x) case "failed" =>
          error concat("asinh: ",MAYFPOW)
        (order := ord :: I) = -1 => return asinh(coef) :: ST
        odd? order => error concat("asinh: ",FPOWERS)
        -- the argument to 'log' must have a non-zero constant term
        log(z + powern(1/2,x))
      error concat("asinh: ",TRCONST)

    acosh z ==
      empty? z =>
        TRANSFCN => acosh(0)$Coef :: ST
        error concat("acosh: ",TRCONST)
      TRANSFCN =>
        coef := frst z
        coef = 1 or coef = -1 =>
          x := z*z - (1@Coef :: ST)
          -- compute order of 'x'
          (ord := orderOrFailed x) case "failed" =>
            error concat("acosh: ",MAYFPOW)
          (order := ord :: I) = -1 => return acosh(coef) :: ST
          odd? order => error concat("acosh: ",FPOWERS)
          -- the argument to 'log' must have a non-zero constant term
          log(z + powern(1/2,x))
        log(z + powern(1/2,z*z - (1@Coef :: ST)))
      error concat("acosh: ",TRCONST)

    atanh z ==
      empty? z => 0@Coef :: ST
      (coef := frst z) = 0 =>
        (inv(2::RN)::Coef) * log(((1@Coef :: ST) + z)/((1@Coef :: ST) - z))
      TRANSFCN =>
        coef = 1 or coef = -1 => error concat("atanh: ",LOGS)
        (inv(2::RN)::Coef) * log(((1@Coef :: ST) + z)/((1@Coef :: ST) - z))
      error concat("atanh: ",TRCONST)

    acoth z ==
      empty? z =>
        TRANSFCN => acoth(0)$Coef :: ST
        error concat("acoth: ",TRCONST)
      TRANSFCN =>
        frst z = 1 or frst z = -1 => error concat("acoth: ",LOGS)
        (inv(2::RN)::Coef) * log((z + (1@Coef :: ST))/(z - (1@Coef :: ST)))
      error concat("acoth: ",TRCONST)

    asech z ==
      empty? z => error "asech: asech(0) is undefined"
      TRANSFCN =>
        (coef := frst z) = 0 => error concat("asech: ",NPOWLOG)
        coef = 1 or coef = -1 =>
          x := (1@Coef :: ST) - z*z
          -- compute order of 'x'
          (ord := orderOrFailed x) case "failed" =>
            error concat("asech: ",MAYFPOW)
          (order := ord :: I) = -1 => return asech(coef) :: ST
          odd? order => error concat("asech: ",FPOWERS)
          log(((1@Coef :: ST) + powern(1/2,x))/z)
        log(((1@Coef :: ST) + powern(1/2,(1@Coef :: ST) - z*z))/z)
      error concat("asech: ",TRCONST)

    acsch z ==
      empty? z => error "acsch: acsch(0) is undefined"
      TRANSFCN =>
        frst z = 0 => error concat("acsch: ",NPOWLOG)
        x := z*z + (1@Coef :: ST)
        -- compute order of 'x'
        (ord := orderOrFailed x) case "failed" =>
          error concat("acsc: ",MAYFPOW)
        (order := ord :: I) = -1 => return acsch(frst z) :: ST
        odd? order => error concat("acsch: ",FPOWERS)
        log(((1@Coef :: ST) + powern(1/2,x))/z)
      error concat("acsch: ",TRCONST)

)abbrev package STTFNC StreamTranscendentalFunctionsNonCommutative
++ Author: Clifton J. Williamson
++ Date Created: 26 May 1994
++ Date Last Updated: 26 May 1994
++ Basic Operations:
++ Related Domains:
++ Also See:
++ AMS Classifications:
++ Keywords: Taylor series, transcendental function, non-commutative
++ Examples:
++ References:
++ Description:
++   StreamTranscendentalFunctionsNonCommutative implements transcendental
++   functions on Taylor series over a non-commutative ring, where a Taylor
++   series is represented by a stream of its coefficients.
StreamTranscendentalFunctionsNonCommutative(Coef): _
         Exports == Implementation where
  Coef :   Algebra Fraction Integer
  I    ==> Integer
  SG   ==> String
  ST   ==> Stream Coef
  STTF ==> StreamTranscendentalFunctions Coef

  Exports ==> with
--% Exponentials and Logarithms
    exp     : ST -> ST
      ++ exp(st) computes the exponential of a power series st.
    log     : ST -> ST
      ++ log(st) computes the log of a power series.
    **    : (ST,ST) -> ST
      ++ st1 ** st2 computes the power of a power series st1 by another
      ++ power series st2.

--% TrigonometricFunctionCategory
    sin     : ST -> ST
      ++ sin(st) computes sine of a power series st.
    cos     : ST -> ST
      ++ cos(st) computes cosine of a power series st.
    tan     : ST -> ST
      ++ tan(st) computes tangent of a power series st.
    cot     : ST -> ST
      ++ cot(st) computes cotangent of a power series st.
    sec     : ST -> ST
      ++ sec(st) computes secant of a power series st.
    csc     : ST -> ST
      ++ csc(st) computes cosecant of a power series st.
    asin    : ST -> ST
      ++ asin(st) computes arcsine of a power series st.
    acos    : ST -> ST
      ++ acos(st) computes arccosine of a power series st.
    atan    : ST -> ST
      ++ atan(st) computes arctangent of a power series st.
    acot    : ST -> ST
      ++ acot(st) computes arccotangent of a power series st.
    asec    : ST -> ST
      ++ asec(st) computes arcsecant of a power series st.
    acsc    : ST -> ST
      ++ acsc(st) computes arccosecant of a power series st.

--% HyperbloicTrigonometricFunctionCategory
    sinh    : ST -> ST
      ++ sinh(st) computes the hyperbolic sine of a power series st.
    cosh    : ST -> ST
      ++ cosh(st) computes the hyperbolic cosine of a power series st.
    tanh    : ST -> ST
      ++ tanh(st) computes the hyperbolic tangent of a power series st.
    coth    : ST -> ST
      ++ coth(st) computes the hyperbolic cotangent of a power series st.
    sech    : ST -> ST
      ++ sech(st) computes the hyperbolic secant of a power series st.
    csch    : ST -> ST
      ++ csch(st) computes the hyperbolic cosecant of a power series st.
    asinh   : ST -> ST
      ++ asinh(st) computes the inverse hyperbolic sine of a power series st.
    acosh   : ST -> ST
      ++ acosh(st) computes the inverse hyperbolic cosine
      ++ of a power series st.
    atanh   : ST -> ST
      ++ atanh(st) computes the inverse hyperbolic tangent
      ++ of a power series st.
    acoth   : ST -> ST
      ++ acoth(st) computes the inverse hyperbolic
      ++ cotangent of a power series st.
    asech   : ST -> ST
      ++ asech(st) computes the inverse hyperbolic secant of a
      ++ power series st.
    acsch   : ST -> ST
      ++ acsch(st) computes the inverse hyperbolic
      ++ cosecant of a power series st.

  Implementation ==> add
    import StreamTaylorSeriesOperations(Coef)

--% Error Reporting

    ZERO    : SG := "series must have constant coefficient zero"
    ONE     : SG := "series must have constant coefficient one"
    NPOWERS : SG := "series expansion has terms of negative degree"

--% Exponentials and Logarithms

    exp z ==
      empty? z => 1@Coef :: ST
      (frst z) = 0 =>
        expx := exp(monom(1,1))$STTF
        compose(expx,z)
      error concat("exp: ",ZERO)

    log z ==
      empty? z => error concat("log: ",ONE)
      (frst z) = 1 =>
        log1PlusX := log(monom(1,0) + monom(1,1))$STTF
        compose(log1PlusX,z - monom(1,0))
      error concat("log: ",ONE)

    (z1:ST) ** (z2:ST) == exp(log(z1) * z2)

--% Trigonometric Functions

    sin z ==
      empty? z => 0@Coef :: ST
      (frst z) = 0 =>
        sinx := sin(monom(1,1))$STTF
        compose(sinx,z)
      error concat("sin: ",ZERO)

    cos z ==
      empty? z => 1@Coef :: ST
      (frst z) = 0 =>
        cosx := cos(monom(1,1))$STTF
        compose(cosx,z)
      error concat("cos: ",ZERO)

    tan z ==
      empty? z => 0@Coef :: ST
      (frst z) = 0 =>
        tanx := tan(monom(1,1))$STTF
        compose(tanx,z)
      error concat("tan: ",ZERO)

    cot z ==
      empty? z => error "cot: cot(0) is undefined"
      (frst z) = 0 => error concat("cot: ",NPOWERS)
      error concat("cot: ",ZERO)

    sec z ==
      empty? z => 1@Coef :: ST
      (frst z) = 0 =>
        secx := sec(monom(1,1))$STTF
        compose(secx,z)
      error concat("sec: ",ZERO)

    csc z ==
      empty? z => error "csc: csc(0) is undefined"
      (frst z) = 0 => error concat("csc: ",NPOWERS)
      error concat("csc: ",ZERO)

    asin z ==
      empty? z => 0@Coef :: ST
      (frst z) = 0 =>
        asinx := asin(monom(1,1))$STTF
        compose(asinx,z)
      error concat("asin: ",ZERO)

    atan z ==
      empty? z => 0@Coef :: ST
      (frst z) = 0 =>
        atanx := atan(monom(1,1))$STTF
        compose(atanx,z)
      error concat("atan: ",ZERO)

    acos z == error "acos: acos undefined on this coefficient domain"
    acot z == error "acot: acot undefined on this coefficient domain"
    asec z == error "asec: asec undefined on this coefficient domain"
    acsc z == error "acsc: acsc undefined on this coefficient domain"

--% Hyperbolic Trigonometric Functions

    sinh z ==
      empty? z => 0@Coef :: ST
      (frst z) = 0 =>
        sinhx := sinh(monom(1,1))$STTF
        compose(sinhx,z)
      error concat("sinh: ",ZERO)

    cosh z ==
      empty? z => 1@Coef :: ST
      (frst z) = 0 =>
        coshx := cosh(monom(1,1))$STTF
        compose(coshx,z)
      error concat("cosh: ",ZERO)

    tanh z ==
      empty? z => 0@Coef :: ST
      (frst z) = 0 =>
        tanhx := tanh(monom(1,1))$STTF
        compose(tanhx,z)
      error concat("tanh: ",ZERO)

    coth z ==
      empty? z => error "coth: coth(0) is undefined"
      (frst z) = 0 => error concat("coth: ",NPOWERS)
      error concat("coth: ",ZERO)

    sech z ==
      empty? z => 1@Coef :: ST
      (frst z) = 0 =>
        sechx := sech(monom(1,1))$STTF
        compose(sechx,z)
      error concat("sech: ",ZERO)

    csch z ==
      empty? z => error "csch: csch(0) is undefined"
      (frst z) = 0 => error concat("csch: ",NPOWERS)
      error concat("csch: ",ZERO)

    asinh z ==
      empty? z => 0@Coef :: ST
      (frst z) = 0 =>
        asinhx := asinh(monom(1,1))$STTF
        compose(asinhx,z)
      error concat("asinh: ",ZERO)

    atanh z ==
      empty? z => 0@Coef :: ST
      (frst z) = 0 =>
        atanhx := atanh(monom(1,1))$STTF
        compose(atanhx,z)
      error concat("atanh: ",ZERO)

    acosh z == error "acosh: acosh undefined on this coefficient domain"
    acoth z == error "acoth: acoth undefined on this coefficient domain"
    asech z == error "asech: asech undefined on this coefficient domain"
    acsch z == error "acsch: acsch undefined on this coefficient domain"

