login  home  contents  what's new  discussion  bug reports     help  links  subscribe  changes  refresh  edit

Edit detail for SandBox Manip revision 1 of 3

1 2 3
Editor:
Time: 2007/11/18 18:07:26 GMT-8
Note: trig rules

changed:
-
Demonstration of modifying and testing a SPAD file

I changed the abbreviation to TRMANIP2 and the name to
!TranscendentalManipulations2 so I can call both the old
and new package if necessary.

\begin{spad}
)abbrev package TRMANIP2 TranscendentalManipulations2
++ Transformations on transcendental objects
++ Author: Bob Sutor, Manuel Bronstein
++ Date Created: Way back
++ Date Last Updated: 22 January 1996, added simplifyLog MCD.
++ Description:
++   TranscendentalManipulations provides functions to simplify and
++   expand expressions involving transcendental operators.
++ Keywords: transcendental, manipulation.
TranscendentalManipulations2(R, F): Exports == Implementation where
  R : Join(OrderedSet, GcdDomain)
  F : Join(FunctionSpace R, TranscendentalFunctionCategory)

  Z       ==> Integer
  K       ==> Kernel F
  P       ==> SparseMultivariatePolynomial(R, K)
  UP      ==> SparseUnivariatePolynomial P
  POWER   ==> "%power"::Symbol
  POW     ==> Record(val: F,exponent: Z)
  PRODUCT ==> Record(coef : Z, var : K)
  FPR     ==> Fraction Polynomial R

  Exports ==> with
    expand     : F -> F
      ++ expand(f) performs the following expansions on f:\begin{items}
      ++ \item 1. logs of products are expanded into sums of logs,
      ++ \item 2. trigonometric and hyperbolic trigonometric functions
      ++ of sums are expanded into sums of products of trigonometric
      ++ and hyperbolic trigonometric functions.
      ++ \item 3. formal powers of the form \spad{(a/b)**c} are expanded into
      ++ \spad{a**c * b**(-c)}.
      ++ \end{items}
    simplify   : F -> F
      ++ simplify(f) performs the following simplifications on f:\begin{items}
      ++ \item 1. rewrites trigs and hyperbolic trigs in terms
      ++ of \spad{sin} ,\spad{cos}, \spad{sinh}, \spad{cosh}.
      ++ \item 2. rewrites \spad{sin**2} and \spad{sinh**2} in terms
      ++ of \spad{cos} and \spad{cosh},
      ++ \item 3. rewrites \spad{exp(a)*exp(b)} as \spad{exp(a+b)}.
      ++ \item 4. rewrites \spad{(a**(1/n))**m * (a**(1/s))**t} as a single
      ++ power of a single radical of \spad{a}.
      ++ \end{items}
    htrigs     : F -> F
      ++ htrigs(f) converts all the exponentials in f into
      ++ hyperbolic sines and cosines.
    simplifyExp: F -> F
      ++ simplifyExp(f) converts every product \spad{exp(a)*exp(b)}
      ++ appearing in f into \spad{exp(a+b)}.
    simplifyLog : F -> F
      ++ simplifyLog(f) converts every \spad{log(a) - log(b)} appearing in f
      ++ into \spad{log(a/b)}, every \spad{log(a) + log(b)} into \spad{log(a*b)}
      ++ and every \spad{n*log(a)} into \spad{log(a^n)}.
    expandPower: F -> F
      ++ expandPower(f) converts every power \spad{(a/b)**c} appearing
      ++ in f into \spad{a**c * b**(-c)}.
    expandLog  : F -> F
      ++ expandLog(f) converts every \spad{log(a/b)} appearing in f into
      ++ \spad{log(a) - log(b)}, and every \spad{log(a*b)} into
      ++ \spad{log(a) + log(b)}..
    cos2sec    : F -> F
      ++ cos2sec(f) converts every \spad{cos(u)} appearing in f into
      ++ \spad{1/sec(u)}.
    cosh2sech  : F -> F
      ++ cosh2sech(f) converts every \spad{cosh(u)} appearing in f into
      ++ \spad{1/sech(u)}.
    cot2trig   : F -> F
      ++ cot2trig(f) converts every \spad{cot(u)} appearing in f into
      ++ \spad{cos(u)/sin(u)}.
    coth2trigh : F -> F
      ++ coth2trigh(f) converts every \spad{coth(u)} appearing in f into
      ++ \spad{cosh(u)/sinh(u)}.
    csc2sin    : F -> F
      ++ csc2sin(f) converts every \spad{csc(u)} appearing in f into
      ++ \spad{1/sin(u)}.
    csch2sinh  : F -> F
      ++ csch2sinh(f) converts every \spad{csch(u)} appearing in f into
      ++ \spad{1/sinh(u)}.
    sec2cos    : F -> F
      ++ sec2cos(f) converts every \spad{sec(u)} appearing in f into
      ++ \spad{1/cos(u)}.
    sech2cosh  : F -> F
      ++ sech2cosh(f) converts every \spad{sech(u)} appearing in f into
      ++ \spad{1/cosh(u)}.
    sin2csc    : F -> F
      ++ sin2csc(f) converts every \spad{sin(u)} appearing in f into
      ++ \spad{1/csc(u)}.
    sinh2csch  : F -> F
      ++ sinh2csch(f) converts every \spad{sinh(u)} appearing in f into
      ++ \spad{1/csch(u)}.
    tan2trig   : F -> F
      ++ tan2trig(f) converts every \spad{tan(u)} appearing in f into
      ++ \spad{sin(u)/cos(u)}.
    tanh2trigh : F -> F
      ++ tanh2trigh(f) converts every \spad{tanh(u)} appearing in f into
      ++ \spad{sinh(u)/cosh(u)}.
    tan2cot    : F -> F
      ++ tan2cot(f) converts every \spad{tan(u)} appearing in f into
      ++ \spad{1/cot(u)}.
    tanh2coth  : F -> F
      ++ tanh2coth(f) converts every \spad{tanh(u)} appearing in f into
      ++ \spad{1/coth(u)}.
    cot2tan    : F -> F
      ++ cot2tan(f) converts every \spad{cot(u)} appearing in f into
      ++ \spad{1/tan(u)}.
    coth2tanh  : F -> F
      ++ coth2tanh(f) converts every \spad{coth(u)} appearing in f into
      ++ \spad{1/tanh(u)}.
    removeCosSq: F -> F
      ++ removeCosSq(f) converts every \spad{cos(u)**2} appearing in f into
      ++ \spad{1 - sin(x)**2}, and also reduces higher
      ++ powers of \spad{cos(u)} with that formula.
    removeSinSq: F -> F
      ++ removeSinSq(f) converts every \spad{sin(u)**2} appearing in f into
      ++ \spad{1 - cos(x)**2}, and also reduces higher powers of
      ++ \spad{sin(u)} with that formula.
    removeCoshSq:F -> F
      ++ removeCoshSq(f) converts every \spad{cosh(u)**2} appearing in f into
      ++ \spad{1 - sinh(x)**2}, and also reduces higher powers of
      ++ \spad{cosh(u)} with that formula.
    removeSinhSq:F -> F
      ++ removeSinhSq(f) converts every \spad{sinh(u)**2} appearing in f into
      ++ \spad{1 - cosh(x)**2}, and also reduces higher powers
      ++ of \spad{sinh(u)} with that formula.
    if R has PatternMatchable(R) and R has ConvertibleTo(Pattern(R)) and F has ConvertibleTo(Pattern(R)) and F has PatternMatchable R then
      expandTrigProducts : F -> F
        ++ expandTrigProducts(e) replaces \axiom{sin(x)*sin(y)} by
        ++ \spad{(cos(x-y)-cos(x+y))/2}, \axiom{cos(x)*cos(y)} by
        ++ \spad{(cos(x-y)+cos(x+y))/2}, and \axiom{sin(x)*cos(y)} by
        ++ \spad{(sin(x-y)+sin(x+y))/2}.  Note that this operation uses
        ++ the pattern matcher and so is relatively expensive.  To avoid
        ++ getting into an infinite loop the transformations are applied
        ++ at most ten times.

  Implementation ==> add
-- for debugging only
    import OutputForm
    import OutputPackage
-- end debugging
    import FactoredFunctions(P)
    import PolynomialCategoryLifting(IndexedExponents K, K, R, P, F)
    import
      PolynomialCategoryQuotientFunctions(IndexedExponents K,K,R,P,F)

    smpexp    : P -> F
    termexp   : P -> F
    exlog     : P -> F
    smplog    : P -> F
    smpexpand : P -> F
    smp2htrigs: P -> F
    kerexpand : K -> F
    expandpow : K -> F
    logexpand : K -> F
    sup2htrigs: (UP, F) -> F
    supexp    : (UP, F, F, Z) -> F
    ueval     : (F, String, F -> F) -> F
    ueval2    : (F, String, F -> F) -> F
    powersimp : (P, List K) -> F
    t2t       : F -> F
    c2t       : F -> F
    c2s       : F -> F
    s2c       : F -> F
    s2c2      : F -> F
    th2th     : F -> F
    ch2th     : F -> F
    ch2sh     : F -> F
    sh2ch     : F -> F
    sh2ch2    : F -> F
    simplify0 : F -> F
    simplifyLog1 : F -> F
    logArgs   : List F -> F

    import F
    import List F

    if R has PatternMatchable R and R has ConvertibleTo Pattern R and F has ConvertibleTo(Pattern(R)) and F has PatternMatchable R then
      XX : F := coerce new()$Symbol
      YY : F := coerce new()$Symbol
      sinCosRule : RewriteRule(R,R,F) :=
        rule(cos(XX)*sin(YY),(sin(XX+YY)-sin(XX-YY))/2::F)
      sinSinRule : RewriteRule(R,R,F) :=
        rule(sin(XX)*sin(YY),(cos(XX-YY)-cos(XX+YY))/2::F)
      cosCosRule : RewriteRule(R,R,F) :=
        rule(cos(XX)*cos(YY),(cos(XX-YY)+cos(XX+YY))/2::F)
      expandTrigProducts(e:F):F ==
        applyRules([sinCosRule,sinSinRule,cosCosRule],e,10)$ApplyRules(R,R,F)

    logArgs(l:List F):F ==
      -- This function will take a list of Expressions (implicitly a sum) and
      -- add them up, combining log terms.  It also replaces n*log(x) by
      -- log(x^n).
      import K
      sum  : F := 0
      arg  : F := 1
      for term in l repeat
        is?(term,"log"::Symbol) =>
          arg := arg * simplifyLog(first(argument(first(kernels(term)))))
        -- Now look for multiples, including negative ones.
        prod : Union(PRODUCT, "failed") := isMult(term)
        (prod case PRODUCT) and is?(prod.var,"log"::Symbol) =>
            arg := arg * simplifyLog ((first argument(prod.var))**(prod.coef))
        sum := sum+term
      sum+log(arg)
    
    simplifyLog(e:F):F ==
      simplifyLog1(numerator e)/simplifyLog1(denominator e)

    simplifyLog1(e:F):F ==
      freeOf?(e,"log"::Symbol) => e

      -- Check for n*log(u)
      prod : Union(PRODUCT, "failed") := isMult(e)
      (prod case PRODUCT) and is?(prod.var,"log"::Symbol) =>
        log simplifyLog ((first argument(prod.var))**(prod.coef))
      
      termList : Union(List(F),"failed") := isTimes(e)
      -- I'm using two variables, termList and terms, to work round a
      -- bug in the old compiler.
      not (termList case "failed") =>
        -- We want to simplify each log term in the product and then multiply
        -- them together.  However, if there is a constant or arithmetic
        -- expression (i.e. somwthing which looks like a Polynomial) we would
        -- like to combine it with a log term.
        terms :List F := [simplifyLog(term) for term in termList::List(F)]
        exprs :List F := []
        for i in 1..#terms repeat
          if retractIfCan(terms.i)@Union(FPR,"failed") case FPR then
            exprs := cons(terms.i,exprs)
            terms := delete!(terms,i)
        if not empty? exprs then
          foundLog := false
          i : NonNegativeInteger := 0
          while (not(foundLog) and (i < #terms)) repeat
            i := i+1
            if is?(terms.i,"log"::Symbol) then
              args : List F := argument(retract(terms.i)@K)
              setelt(terms,i, log simplifyLog1(first(args)**(*/exprs)))
              foundLog := true
          -- The next line deals with a situation which shouldn't occur,
          -- since we have checked whether we are freeOf log already.
          if not foundLog then terms := append(exprs,terms)
        */terms
    
      terms : Union(List(F),"failed") := isPlus(e)
      not (terms case "failed") => logArgs(terms) 

      expt : Union(POW, "failed") := isPower(e)
--      (expt case POW) and not one? expt.exponent =>
      (expt case POW) and not (expt.exponent = 1) =>
        simplifyLog(expt.val)**(expt.exponent)
    
      kers : List K := kernels e
--      not(one?(#kers)) => e -- Have a constant
      not(((#kers) = 1)) => e -- Have a constant
      kernel(operator first kers,[simplifyLog(u) for u in argument first kers])


    if R has RetractableTo Integer then
      simplify x == rootProduct(simplify0 x)$AlgebraicManipulations(R,F)

    else simplify x == simplify0 x

    expandpow k ==
      a := expandPower first(arg := argument k)
      b := expandPower second arg
--      ne:F := (one? numer a => 1; numer(a)::F ** b)
      ne:F := (((numer a) = 1) => 1; numer(a)::F ** b)
--      de:F := (one? denom a => 1; denom(a)::F ** (-b))
      de:F := (((denom a) = 1) => 1; denom(a)::F ** (-b))
      ne * de

    termexp p ==
      exponent:F := 0
      coef := (leadingCoefficient p)::P
      lpow := select(is?(#1, POWER)$K, lk := variables p)$List(K)
      for k in lk repeat
        d := degree(p, k)
        if is?(k, "exp"::Symbol) then
          exponent := exponent + d * first argument k
        else if not is?(k, POWER) then
          -- Expand arguments to functions as well ... MCD 23/1/97
          --coef := coef * monomial(1, k, d)
          coef := coef * monomial(1, kernel(operator k,[simplifyExp u for u in argument k], height k), d)
      coef::F * exp exponent * powersimp(p, lpow)

    expandPower f ==
      l := select(is?(#1, POWER)$K, kernels f)$List(K)
      eval(f, l, [expandpow k for k in l])

-- l is a list of pure powers appearing as kernels in p
    powersimp(p, l) ==
      empty? l => 1
      k := first l                           -- k = a**b
      a := first(arg := argument k)
      exponent := degree(p, k) * second arg
      empty?(lk := select(a = first argument #1, rest l)) =>
        (a ** exponent) * powersimp(p, rest l)
      for k0 in lk repeat
        exponent := exponent + degree(p, k0) * second argument k0
      (a ** exponent) * powersimp(p, setDifference(rest l, lk))

    t2t x         == sin(x) / cos(x)
    c2t x         == cos(x) / sin(x)
    c2s x         == inv sin x
    s2c x         == inv cos x
    s2c2 x        == 1 - cos(x)**2
    th2th x       == sinh(x) / cosh(x)
    ch2th x       == cosh(x) / sinh(x)
    ch2sh x       == inv sinh x
    sh2ch x       == inv cosh x
    sh2ch2 x      == cosh(x)**2 - 1
    ueval(x, s,f) == eval(x, s::Symbol, f)
    ueval2(x,s,f) == eval(x, s::Symbol, 2, f)
    cos2sec x     == ueval(x, "cos", inv sec #1)
    sin2csc x     == ueval(x, "sin", inv csc #1)
    csc2sin x     == ueval(x, "csc", c2s)
    sec2cos x     == ueval(x, "sec", s2c)
    tan2cot x     == ueval(x, "tan", inv cot #1)
    cot2tan x     == ueval(x, "cot", inv tan #1)
    tan2trig x    == ueval(x, "tan", t2t)
    cot2trig x    == ueval(x, "cot", c2t)
    cosh2sech x   == ueval(x, "cosh", inv sech #1)
    sinh2csch x   == ueval(x, "sinh", inv csch #1)
    csch2sinh x   == ueval(x, "csch", ch2sh)
    sech2cosh x   == ueval(x, "sech", sh2ch)
    tanh2coth x   == ueval(x, "tanh", inv coth #1)
    coth2tanh x   == ueval(x, "coth", inv tanh #1)
    tanh2trigh x  == ueval(x, "tanh", th2th)
    coth2trigh x  == ueval(x, "coth", ch2th)
    removeCosSq x == ueval2(x, "cos", 1 - (sin #1)**2)
    removeSinSq x == ueval2(x, "sin", s2c2)
    removeCoshSq x== ueval2(x, "cosh", 1 + (sinh #1)**2)
    removeSinhSq x== ueval2(x, "sinh", sh2ch2)
    expandLog x   == smplog(numer x) / smplog(denom x)
    simplifyExp x == (smpexp numer x) / (smpexp denom x)
    expand x      == (smpexpand numer x) / (smpexpand denom x)
    smpexpand p   == map(kerexpand, #1::F, p)
    smplog p      == map(logexpand, #1::F, p)
    smp2htrigs p  == map(htrigs(#1::F), #1::F, p)

    htrigs f ==
      (m := mainKernel f) case "failed" => f
      op  := operator(k := m::K)
      arg := [htrigs x for x in argument k]$List(F)
      num := univariate(numer f, k)
      den := univariate(denom f, k)
      is?(op, "exp"::Symbol) =>
        g1 := cosh(a := first arg) + sinh(a)
        g2 := cosh(a) - sinh(a)
        supexp(num,g1,g2,b:= (degree num)::Z quo 2)/supexp(den,g1,g2,b)
      sup2htrigs(num, g1:= op arg) / sup2htrigs(den, g1)

    supexp(p, f1, f2, bse) ==
      ans:F := 0
      while p ^= 0 repeat
        g := htrigs(leadingCoefficient(p)::F)
        if ((d := degree(p)::Z - bse) >= 0) then
             ans := ans + g * f1 ** d
        else ans := ans + g * f2 ** (-d)
        p := reductum p
      ans

    sup2htrigs(p, f) ==
      (map(smp2htrigs, p)$SparseUnivariatePolynomialFunctions2(P, F)) f

    exlog p == +/[r.coef * log(r.logand::F) for r in log squareFree p]

    logexpand k ==
      nullary?(op := operator k) => k::F
      is?(op, "log"::Symbol) =>
         exlog(numer(x := expandLog first argument k)) - exlog denom x
      op [expandLog x for x in argument k]$List(F)

    kerexpand k ==
      nullary?(op := operator k) => k::F
      is?(op, POWER) => expandpow k
      arg := first argument k
      is?(op, "sec"::Symbol) => inv expand cos arg
      is?(op, "csc"::Symbol) => inv expand sin arg
      is?(op, "log"::Symbol) =>
         exlog(numer(x := expand arg)) - exlog denom x
      num := numer arg
      den := denom arg
      num := numer arg
      den := denom arg

-- for debugging output
      num := numer arg
      den := denom arg
      output(message "num:")
      output(num::OutputForm)
      output(message "den:")
      output(den::OutputForm)
-- end debugging

      (b := (reductum num) / den) ^= 0 =>
        a := (leadingMonomial num) / den
        is?(op, "exp"::Symbol) => exp(expand a) * expand(exp b)
        is?(op, "sin"::Symbol) =>
           sin(expand a) * expand(cos b) + cos(expand a) * expand(sin b)
        is?(op, "cos"::Symbol) =>
           cos(expand a) * expand(cos b) - sin(expand a) * expand(sin b)
        is?(op, "tan"::Symbol) =>
          ta := tan expand a
          tb := expand tan b
          (ta + tb) / (1 - ta * tb)
        is?(op, "cot"::Symbol) =>
          cta := cot expand a
          ctb := expand cot b
          (cta * ctb - 1) / (ctb + cta)
        op [expand x for x in argument k]$List(F)
      op [expand x for x in argument k]$List(F)

    smpexp p ==
      ans:F := 0
      while p ^= 0 repeat
        ans := ans + termexp leadingMonomial p
        p   := reductum p
      ans

    -- this now works in 3 passes over the expression:
    --   pass1 rewrites trigs and htrigs in terms of sin,cos,sinh,cosh
    --   pass2 rewrites sin**2 and sinh**2 in terms of cos and cosh.
    --   pass3 groups exponentials together
    simplify0 x ==
      simplifyExp eval(eval(x,
          ["tan"::Symbol,"cot"::Symbol,"sec"::Symbol,"csc"::Symbol,
           "tanh"::Symbol,"coth"::Symbol,"sech"::Symbol,"csch"::Symbol],
              [t2t,c2t,s2c,c2s,th2th,ch2th,sh2ch,ch2sh]),
                ["sin"::Symbol, "sinh"::Symbol], [2, 2], [s2c2, sh2ch2])

\end{spad}

Testing the change
\begin{axiom}
-- old
ex1:=expandTrigProducts(sin(x)*sin(y))$TRMANIP(INT,Expression Integer)
ex2:=expand(ex1)$TRMANIP(INT,Expression Integer)
--new
ex3:=expand(ex1)$TRMANIP2(INT,Expression Integer)
\end{axiom}

From unknown Mon Sep 12 18:13:59 -0500 2005
From: unknown
Date: Mon, 12 Sep 2005 18:13:59 -0500
Subject: 
Message-ID: <20050912181359-0500@page.axiom-developer.org>

\begin{axiom}
sinCosProducts := rule
  sin(x)*sin(y) == (cos(x-y) - cos(x+y))/2
  cos(x)*cos(y) == (cos(x-y) + cos(x+y))/2
  sin(x)*cos(y) == (sin(x-y) + sin(x+y))/2
  sin(x)^2 == (1 - cos(2*x))/2
  sin(x)^3 == sin(x)*(1 - cos(2*x))/2
\end{axiom}



Demonstration of modifying and testing a SPAD file

I changed the abbreviation to TRMANIP2 and the name to TranscendentalManipulations2 so I can call both the old and new package if necessary.

spad
)abbrev package TRMANIP2 TranscendentalManipulations2
++ Transformations on transcendental objects
++ Author: Bob Sutor, Manuel Bronstein
++ Date Created: Way back
++ Date Last Updated: 22 January 1996, added simplifyLog MCD.
++ Description:
++   TranscendentalManipulations provides functions to simplify and
++   expand expressions involving transcendental operators.
++ Keywords: transcendental, manipulation.
TranscendentalManipulations2(R, F): Exports == Implementation where
  R : Join(OrderedSet, GcdDomain)
  F : Join(FunctionSpace R, TranscendentalFunctionCategory)
Z ==> Integer K ==> Kernel F P ==> SparseMultivariatePolynomial(R, K) UP ==> SparseUnivariatePolynomial P POWER ==> "%power"::Symbol POW ==> Record(val: F,exponent: Z) PRODUCT ==> Record(coef : Z, var : K) FPR ==> Fraction Polynomial R
Exports ==> with expand : F -> F ++ expand(f) performs the following expansions on f:\begin{items} ++ \item 1. logs of products are expanded into sums of logs, ++ \item 2. trigonometric and hyperbolic trigonometric functions ++ of sums are expanded into sums of products of trigonometric ++ and hyperbolic trigonometric functions. ++ \item 3. formal powers of the form \spad{(a/b)**c} are expanded into ++ \spad{a**c * b**(-c)}. ++ \end{items} simplify : F -> F ++ simplify(f) performs the following simplifications on f:\begin{items} ++ \item 1. rewrites trigs and hyperbolic trigs in terms ++ of \spad{sin} ,\spad{cos}, \spad{sinh}, \spad{cosh}. ++ \item 2. rewrites \spad{sin**2} and \spad{sinh**2} in terms ++ of \spad{cos} and \spad{cosh}, ++ \item 3. rewrites \spad{exp(a)*exp(b)} as \spad{exp(a+b)}. ++ \item 4. rewrites \spad{(a**(1/n))**m * (a**(1/s))**t} as a single ++ power of a single radical of \spad{a}. ++ \end{items} htrigs : F -> F ++ htrigs(f) converts all the exponentials in f into ++ hyperbolic sines and cosines. simplifyExp: F -> F ++ simplifyExp(f) converts every product \spad{exp(a)*exp(b)} ++ appearing in f into \spad{exp(a+b)}. simplifyLog : F -> F ++ simplifyLog(f) converts every \spad{log(a) - log(b)} appearing in f ++ into \spad{log(a/b)}, every \spad{log(a) + log(b)} into \spad{log(a*b)} ++ and every \spad{n*log(a)} into \spad{log(a^n)}. expandPower: F -> F ++ expandPower(f) converts every power \spad{(a/b)**c} appearing ++ in f into \spad{a**c * b**(-c)}. expandLog : F -> F ++ expandLog(f) converts every \spad{log(a/b)} appearing in f into ++ \spad{log(a) - log(b)}, and every \spad{log(a*b)} into ++ \spad{log(a) + log(b)}.. cos2sec : F -> F ++ cos2sec(f) converts every \spad{cos(u)} appearing in f into ++ \spad{1/sec(u)}. cosh2sech : F -> F ++ cosh2sech(f) converts every \spad{cosh(u)} appearing in f into ++ \spad{1/sech(u)}. cot2trig : F -> F ++ cot2trig(f) converts every \spad{cot(u)} appearing in f into ++ \spad{cos(u)/sin(u)}. coth2trigh : F -> F ++ coth2trigh(f) converts every \spad{coth(u)} appearing in f into ++ \spad{cosh(u)/sinh(u)}. csc2sin : F -> F ++ csc2sin(f) converts every \spad{csc(u)} appearing in f into ++ \spad{1/sin(u)}. csch2sinh : F -> F ++ csch2sinh(f) converts every \spad{csch(u)} appearing in f into ++ \spad{1/sinh(u)}. sec2cos : F -> F ++ sec2cos(f) converts every \spad{sec(u)} appearing in f into ++ \spad{1/cos(u)}. sech2cosh : F -> F ++ sech2cosh(f) converts every \spad{sech(u)} appearing in f into ++ \spad{1/cosh(u)}. sin2csc : F -> F ++ sin2csc(f) converts every \spad{sin(u)} appearing in f into ++ \spad{1/csc(u)}. sinh2csch : F -> F ++ sinh2csch(f) converts every \spad{sinh(u)} appearing in f into ++ \spad{1/csch(u)}. tan2trig : F -> F ++ tan2trig(f) converts every \spad{tan(u)} appearing in f into ++ \spad{sin(u)/cos(u)}. tanh2trigh : F -> F ++ tanh2trigh(f) converts every \spad{tanh(u)} appearing in f into ++ \spad{sinh(u)/cosh(u)}. tan2cot : F -> F ++ tan2cot(f) converts every \spad{tan(u)} appearing in f into ++ \spad{1/cot(u)}. tanh2coth : F -> F ++ tanh2coth(f) converts every \spad{tanh(u)} appearing in f into ++ \spad{1/coth(u)}. cot2tan : F -> F ++ cot2tan(f) converts every \spad{cot(u)} appearing in f into ++ \spad{1/tan(u)}. coth2tanh : F -> F ++ coth2tanh(f) converts every \spad{coth(u)} appearing in f into ++ \spad{1/tanh(u)}. removeCosSq: F -> F ++ removeCosSq(f) converts every \spad{cos(u)**2} appearing in f into ++ \spad{1 - sin(x)**2}, and also reduces higher ++ powers of \spad{cos(u)} with that formula. removeSinSq: F -> F ++ removeSinSq(f) converts every \spad{sin(u)**2} appearing in f into ++ \spad{1 - cos(x)**2}, and also reduces higher powers of ++ \spad{sin(u)} with that formula. removeCoshSq:F -> F ++ removeCoshSq(f) converts every \spad{cosh(u)**2} appearing in f into ++ \spad{1 - sinh(x)**2}, and also reduces higher powers of ++ \spad{cosh(u)} with that formula. removeSinhSq:F -> F ++ removeSinhSq(f) converts every \spad{sinh(u)**2} appearing in f into ++ \spad{1 - cosh(x)**2}, and also reduces higher powers ++ of \spad{sinh(u)} with that formula. if R has PatternMatchable(R) and R has ConvertibleTo(Pattern(R)) and F has ConvertibleTo(Pattern(R)) and F has PatternMatchable R then expandTrigProducts : F -> F ++ expandTrigProducts(e) replaces \axiom{sin(x)*sin(y)} by ++ \spad{(cos(x-y)-cos(x+y))/2}, \axiom{cos(x)*cos(y)} by ++ \spad{(cos(x-y)+cos(x+y))/2}, and \axiom{sin(x)*cos(y)} by ++ \spad{(sin(x-y)+sin(x+y))/2}. Note that this operation uses ++ the pattern matcher and so is relatively expensive. To avoid ++ getting into an infinite loop the transformations are applied ++ at most ten times.
Implementation ==> add -- for debugging only import OutputForm import OutputPackage -- end debugging import FactoredFunctions(P) import PolynomialCategoryLifting(IndexedExponents K, K, R, P, F) import PolynomialCategoryQuotientFunctions(IndexedExponents K,K,R,P,F)
smpexp : P -> F termexp : P -> F exlog : P -> F smplog : P -> F smpexpand : P -> F smp2htrigs: P -> F kerexpand : K -> F expandpow : K -> F logexpand : K -> F sup2htrigs: (UP, F) -> F supexp : (UP, F, F, Z) -> F ueval : (F, String, F -> F) -> F ueval2 : (F, String, F -> F) -> F powersimp : (P, List K) -> F t2t : F -> F c2t : F -> F c2s : F -> F s2c : F -> F s2c2 : F -> F th2th : F -> F ch2th : F -> F ch2sh : F -> F sh2ch : F -> F sh2ch2 : F -> F simplify0 : F -> F simplifyLog1 : F -> F logArgs : List F -> F
import F import List F
if R has PatternMatchable R and R has ConvertibleTo Pattern R and F has ConvertibleTo(Pattern(R)) and F has PatternMatchable R then XX : F := coerce new()$Symbol YY : F := coerce new()$Symbol sinCosRule : RewriteRule(R,R,F) := rule(cos(XX)*sin(YY),(sin(XX+YY)-sin(XX-YY))/2::F) sinSinRule : RewriteRule(R,R,F) := rule(sin(XX)*sin(YY),(cos(XX-YY)-cos(XX+YY))/2::F) cosCosRule : RewriteRule(R,R,F) := rule(cos(XX)*cos(YY),(cos(XX-YY)+cos(XX+YY))/2::F) expandTrigProducts(e:F):F == applyRules([sinCosRule,sinSinRule,cosCosRule],e,10)$ApplyRules(R,R,F)
logArgs(l:List F):F == -- This function will take a list of Expressions (implicitly a sum) and -- add them up, combining log terms. It also replaces n*log(x) by -- log(x^n). import K sum : F := 0 arg : F := 1 for term in l repeat is?(term,"log"::Symbol) => arg := arg * simplifyLog(first(argument(first(kernels(term))))) -- Now look for multiples, including negative ones. prod : Union(PRODUCT, "failed") := isMult(term) (prod case PRODUCT) and is?(prod.var,"log"::Symbol) => arg := arg * simplifyLog ((first argument(prod.var))**(prod.coef)) sum := sum+term sum+log(arg)
simplifyLog(e:F):F == simplifyLog1(numerator e)/simplifyLog1(denominator e)
simplifyLog1(e:F):F == freeOf?(e,"log"::Symbol) => e
-- Check for n*log(u) prod : Union(PRODUCT, "failed") := isMult(e) (prod case PRODUCT) and is?(prod.var,"log"::Symbol) => log simplifyLog ((first argument(prod.var))**(prod.coef))
termList : Union(List(F),"failed") := isTimes(e) -- I'm using two variables, termList and terms, to work round a -- bug in the old compiler. not (termList case "failed") => -- We want to simplify each log term in the product and then multiply -- them together. However, if there is a constant or arithmetic -- expression (i.e. somwthing which looks like a Polynomial) we would -- like to combine it with a log term. terms :List F := [simplifyLog(term) for term in termList::List(F)] exprs :List F := [] for i in 1..#terms repeat if retractIfCan(terms.i)@Union(FPR,"failed") case FPR then exprs := cons(terms.i,exprs) terms := delete!(terms,i) if not empty? exprs then foundLog := false i : NonNegativeInteger := 0 while (not(foundLog) and (i < #terms)) repeat i := i+1 if is?(terms.i,"log"::Symbol) then args : List F := argument(retract(terms.i)@K) setelt(terms,i, log simplifyLog1(first(args)**(*/exprs))) foundLog := true -- The next line deals with a situation which shouldn't occur, -- since we have checked whether we are freeOf log already. if not foundLog then terms := append(exprs,terms) */terms
terms : Union(List(F),"failed") := isPlus(e) not (terms case "failed") => logArgs(terms)
expt : Union(POW, "failed") := isPower(e) -- (expt case POW) and not one? expt.exponent => (expt case POW) and not (expt.exponent = 1) => simplifyLog(expt.val)**(expt.exponent)
kers : List K := kernels e -- not(one?(#kers)) => e -- Have a constant not(((#kers) = 1)) => e -- Have a constant kernel(operator first kers,[simplifyLog(u) for u in argument first kers])
if R has RetractableTo Integer then simplify x == rootProduct(simplify0 x)$AlgebraicManipulations(R,F)
else simplify x == simplify0 x
expandpow k == a := expandPower first(arg := argument k) b := expandPower second arg -- ne:F := (one? numer a => 1; numer(a)::F ** b) ne:F := (((numer a) = 1) => 1; numer(a)::F ** b) -- de:F := (one? denom a => 1; denom(a)::F ** (-b)) de:F := (((denom a) = 1) => 1; denom(a)::F ** (-b)) ne * de
termexp p == exponent:F := 0 coef := (leadingCoefficient p)::P lpow := select(is?(#1, POWER)$K, lk := variables p)$List(K) for k in lk repeat d := degree(p, k) if is?(k, "exp"::Symbol) then exponent := exponent + d * first argument k else if not is?(k, POWER) then -- Expand arguments to functions as well ... MCD 23/1/97 --coef := coef * monomial(1, k, d) coef := coef * monomial(1, kernel(operator k,[simplifyExp u for u in argument k], height k), d) coef::F * exp exponent * powersimp(p, lpow)
expandPower f == l := select(is?(#1, POWER)$K, kernels f)$List(K) eval(f, l, [expandpow k for k in l])
-- l is a list of pure powers appearing as kernels in p powersimp(p, l) == empty? l => 1 k := first l -- k = a**b a := first(arg := argument k) exponent := degree(p, k) * second arg empty?(lk := select(a = first argument #1, rest l)) => (a ** exponent) * powersimp(p, rest l) for k0 in lk repeat exponent := exponent + degree(p, k0) * second argument k0 (a ** exponent) * powersimp(p, setDifference(rest l, lk))
t2t x == sin(x) / cos(x) c2t x == cos(x) / sin(x) c2s x == inv sin x s2c x == inv cos x s2c2 x == 1 - cos(x)**2 th2th x == sinh(x) / cosh(x) ch2th x == cosh(x) / sinh(x) ch2sh x == inv sinh x sh2ch x == inv cosh x sh2ch2 x == cosh(x)**2 - 1 ueval(x, s,f) == eval(x, s::Symbol, f) ueval2(x,s,f) == eval(x, s::Symbol, 2, f) cos2sec x == ueval(x, "cos", inv sec #1) sin2csc x == ueval(x, "sin", inv csc #1) csc2sin x == ueval(x, "csc", c2s) sec2cos x == ueval(x, "sec", s2c) tan2cot x == ueval(x, "tan", inv cot #1) cot2tan x == ueval(x, "cot", inv tan #1) tan2trig x == ueval(x, "tan", t2t) cot2trig x == ueval(x, "cot", c2t) cosh2sech x == ueval(x, "cosh", inv sech #1) sinh2csch x == ueval(x, "sinh", inv csch #1) csch2sinh x == ueval(x, "csch", ch2sh) sech2cosh x == ueval(x, "sech", sh2ch) tanh2coth x == ueval(x, "tanh", inv coth #1) coth2tanh x == ueval(x, "coth", inv tanh #1) tanh2trigh x == ueval(x, "tanh", th2th) coth2trigh x == ueval(x, "coth", ch2th) removeCosSq x == ueval2(x, "cos", 1 - (sin #1)**2) removeSinSq x == ueval2(x, "sin", s2c2) removeCoshSq x== ueval2(x, "cosh", 1 + (sinh #1)**2) removeSinhSq x== ueval2(x, "sinh", sh2ch2) expandLog x == smplog(numer x) / smplog(denom x) simplifyExp x == (smpexp numer x) / (smpexp denom x) expand x == (smpexpand numer x) / (smpexpand denom x) smpexpand p == map(kerexpand, #1::F, p) smplog p == map(logexpand, #1::F, p) smp2htrigs p == map(htrigs(#1::F), #1::F, p)
htrigs f == (m := mainKernel f) case "failed" => f op := operator(k := m::K) arg := [htrigs x for x in argument k]$List(F) num := univariate(numer f, k) den := univariate(denom f, k) is?(op, "exp"::Symbol) => g1 := cosh(a := first arg) + sinh(a) g2 := cosh(a) - sinh(a) supexp(num,g1,g2,b:= (degree num)::Z quo 2)/supexp(den,g1,g2,b) sup2htrigs(num, g1:= op arg) / sup2htrigs(den, g1)
supexp(p, f1, f2, bse) == ans:F := 0 while p ^= 0 repeat g := htrigs(leadingCoefficient(p)::F) if ((d := degree(p)::Z - bse) >= 0) then ans := ans + g * f1 ** d else ans := ans + g * f2 ** (-d) p := reductum p ans
sup2htrigs(p, f) == (map(smp2htrigs, p)$SparseUnivariatePolynomialFunctions2(P, F)) f
exlog p == +/[r.coef * log(r.logand::F) for r in log squareFree p]
logexpand k == nullary?(op := operator k) => k::F is?(op, "log"::Symbol) => exlog(numer(x := expandLog first argument k)) - exlog denom x op [expandLog x for x in argument k]$List(F)
kerexpand k == nullary?(op := operator k) => k::F is?(op, POWER) => expandpow k arg := first argument k is?(op, "sec"::Symbol) => inv expand cos arg is?(op, "csc"::Symbol) => inv expand sin arg is?(op, "log"::Symbol) => exlog(numer(x := expand arg)) - exlog denom x num := numer arg den := denom arg num := numer arg den := denom arg
-- for debugging output num := numer arg den := denom arg output(message "num:") output(num::OutputForm) output(message "den:") output(den::OutputForm) -- end debugging
(b := (reductum num) / den) ^= 0 => a := (leadingMonomial num) / den is?(op, "exp"::Symbol) => exp(expand a) * expand(exp b) is?(op, "sin"::Symbol) => sin(expand a) * expand(cos b) + cos(expand a) * expand(sin b) is?(op, "cos"::Symbol) => cos(expand a) * expand(cos b) - sin(expand a) * expand(sin b) is?(op, "tan"::Symbol) => ta := tan expand a tb := expand tan b (ta + tb) / (1 - ta * tb) is?(op, "cot"::Symbol) => cta := cot expand a ctb := expand cot b (cta * ctb - 1) / (ctb + cta) op [expand x for x in argument k]$List(F) op [expand x for x in argument k]$List(F)
smpexp p == ans:F := 0 while p ^= 0 repeat ans := ans + termexp leadingMonomial p p := reductum p ans
-- this now works in 3 passes over the expression: -- pass1 rewrites trigs and htrigs in terms of sin,cos,sinh,cosh -- pass2 rewrites sin**2 and sinh**2 in terms of cos and cosh. -- pass3 groups exponentials together simplify0 x == simplifyExp eval(eval(x, ["tan"::Symbol,"cot"::Symbol,"sec"::Symbol,"csc"::Symbol, "tanh"::Symbol,"coth"::Symbol,"sech"::Symbol,"csch"::Symbol], [t2t,c2t,s2c,c2s,th2th,ch2th,sh2ch,ch2sh]), ["sin"::Symbol, "sinh"::Symbol], [2, 2], [s2c2, sh2ch2])
spad
   Compiling FriCAS source code from file 
      /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/6388374989627192641-25px001.spad
      using old system compiler.
   TRMANIP2 abbreviates package TranscendentalManipulations2 
******** Spad syntax error detected ********
Expected: |)|
The prior line was:
199> (prod case PRODUCT) and is?(prod.var,"log"::Symbol) =>
The current line is:
200> arg := arg * simplifyLog ((first argument(prod.var))**(prod.coef))
The number of valid tokens is 1. The prior token was #S(TOKEN :SYMBOL |)| :TYPE KEYWORD :NONBLANK 200) The current token is #S(TOKEN :SYMBOL POWER :TYPE KEYWORD :NONBLANK 200)

Testing the change

axiom
-- old
ex1:=expandTrigProducts(sin(x)*sin(y))$TRMANIP(INT,Expression Integer)

\label{eq1}{-{\cos \left({y + x}\right)}+{\cos \left({y - x}\right)}}\over 2(1)
Type: Expression(Integer)
axiom
ex2:=expand(ex1)$TRMANIP(INT,Expression Integer)

\label{eq2}{\sin \left({x}\right)}\ {\sin \left({y}\right)}(2)
Type: Expression(Integer)
axiom
--new
ex3:=expand(ex1)$TRMANIP2(INT,Expression Integer)
TranscendentalManipulations2 is an unknown constructor and so is unavailable. Did you mean to use -> but type something different instead?

axiom
sinCosProducts := rule
  sin(x)*sin(y) == (cos(x-y) - cos(x+y))/2
  cos(x)*cos(y) == (cos(x-y) + cos(x+y))/2
  sin(x)*cos(y) == (sin(x-y) + sin(x+y))/2
  sin(x)^2 == (1 - cos(2*x))/2
  sin(x)^3 == sin(x)*(1 - cos(2*x))/2

\label{eq3}\begin{array}{@{}l}
\displaystyle
\left\{{{\%G \ {\sin \left({x}\right)}\ {\sin \left({y}\right)}}\mbox{\rm = =}{{-{\%G \ {\cos \left({y + x}\right)}}+{\%G \ {\cos \left({y - x}\right)}}}\over 2}}, \: \right.
\
\
\displaystyle
\left.{{\%H \ {\cos \left({x}\right)}\ {\cos \left({y}\right)}}\mbox{\rm = =}{{{\%H \ {\cos \left({y + x}\right)}}+{\%H \ {\cos \left({y - x}\right)}}}\over 2}}, \: \right.
\
\
\displaystyle
\left.{{\%I \ {\cos \left({y}\right)}\ {\sin \left({x}\right)}}\mbox{\rm = =}{{{\%I \ {\sin \left({y + x}\right)}}-{\%I \ {\sin \left({y - x}\right)}}}\over 2}}, \: \right.
\
\
\displaystyle
\left.{{{\sin \left({x}\right)}^{2}}\mbox{\rm = =}{{-{\cos \left({2 \  x}\right)}+ 1}\over 2}}, \: \right.
\
\
\displaystyle
\left.{{{\sin \left({x}\right)}^{3}}\mbox{\rm = =}{{{\left(-{\cos \left({2 \  x}\right)}+ 1 \right)}\ {\sin \left({x}\right)}}\over 2}}\right\} 
(3)
Type: Ruleset(Integer,Integer,Expression(Integer))