I recently wrote to Joel Cohen for clarification on a procedure
'Simplify_trig' from volume 1 of his computer algebra texts. I'm
copying y'all in case there's someone who's worked through this part
of the book and might have some advice.
The code is available at: http://github.com/dharmatech/mpl
Ed
----------------------------------------------------------------------
Joel,
Example 7.16 of Elementary Algorithms says that contract-trig should
simplify the expression to 0. Indeed, I'm able to confirm this:
(contract-trig
(alge
" sin(x) + sin(y) - 2 * sin(x/2 + y/2) * cos(x/2 - y/2) "))
;; 0
By by way, my 'alge' procedure is a simple infix-to-prefix
translator. So for example:
> (alge "a*(b+c)")
(* a (+ b c))
The example text then mentions that the expansion algorithm alone
cannot attain the full simplification to 0.
Later on, the text mentions that the Simplify_trig procedure can
perform the simplification. However, here's what I get:
(simplify-trig
(alge
" sin(x) + sin(y) - 2 * sin(x/2 + y/2) * cos(x/2 - y/2) "))
;; (+ (* -1/2 (sin (+ (* -1 x) y)))
;; (* -1/2 (sin (+ x (* -1 y)))))
Note that, if I apply simplify-trig twice, I get the simplification:
(simplify-trig
(simplify-trig
(alge
" sin(x) + sin(y) - 2 * sin(x/2 + y/2) * cos(x/2 - y/2) ")))
;; 0
My 'simplify-trig' procedure is a direct translation of the one
from your book:
(define (simplify-trig u)
(let ((w (rationalize-expression (trig-substitute u))))
(/ (contract-trig (expand-trig (numerator w)))
(contract-trig (expand-trig (denominator w))))))
For example 7.16, it really boils down to this code:
(contract-trig (expand-trig u))
If I try that out directly:
(contract-trig
(expand-trig
(alge " sin(x) + sin(y) - 2 * sin(x/2 + y/2) * cos(x/2 - y/2) ")))
;; (+ (* -1/2 (sin (+ (* -1 x) y)))
;; (* -1/2 (sin (+ x (* -1 y)))))
I get the same result as 'simplify-trig'.
Let's see what happens with (expand-trig u):
(expand-trig
(alge " sin(x) + sin(y) - 2 * sin(x/2 + y/2) * cos(x/2 - y/2) "))
;; (+ (sin x)
;; (sin y)
;; (* -2
;; (+ (* (cos (* 1/2 x)) (cos (* 1/2 y)))
;; (* (sin (* 1/2 x)) (sin (* 1/2 y))))
;; (+ (* (cos (* 1/2 y)) (sin (* 1/2 x)))
;; (* (cos (* 1/2 x)) (sin (* 1/2 y))))))
Apparently, 'contract-trig' is having trouble simplifying that
expression down to 0.
Note that if I insert a call to 'algebraic-expand' between the
'contract-trig' and 'expand-trig', the simplification works:
(contract-trig
(algebraic-expand
(expand-trig
(alge " sin(x) + sin(y) - 2 * sin(x/2 + y/2) * cos(x/2 - y/2) "))))
;; 0
So I have a few options.
1 : Modify 'expand-trig' so that it ouputs results in algebraic
expanded
form. Page 285 contains a section entitled "Appraisal of Expand_trig"
which actually mentions this as an extension. Exercise 8 is about this
extension.
2 : Modify 'simplify-trig' as above. I.e. insert a call to
'algebraic-expand'.
3 : Enhance 'contract-trig' to be able to deal with the case
above. This might involve doing expansion in that procedure.
So, it's essentially a question of where to inject the expansion.
The book claims that the default 'simpliy-trig' should arrive at 0 so
perhaps I should take another look at the code before straying from
the default algorithms.
Suggestions welcome! :-)
Ed
Much of this will depend on details of how one represent internals for
purposes of trig (or other) manipulation. For example, one could use
complex exponentials as "variables", in an effort to maintain
algebraic relationships between them. In this setting, an expression
that has half angles might give rise to a variable such as exp(i*x/2).
But then sin(x) will be written in terms of the square of this one.
Upshot being, expansion and/or contraction might directly give zero,
if this approach toward "canonicalizing" the expression, prior to
expansion or contraction, is taken.
Daniel Lichtblau
Wolfram Research
Essentially all high-school trigonometry identities can be confirmed by
this technique, converting to exponentials and doing "rational
simplification" on the result. DanL's comment is right that one must
first recognize that r1=exp(s) and r2=exp(s/2) are not algebraically
independent; r1 must be rewritten as r2^2.
I wrote a paper on Rationally Simplifying Non-Rational Expressions,
ACM SIGSAM Bulletin, July 1972,
with such examples.
In Macsyma, use exponentialize and then radcan.
When does it fail? Some trig identities have square-roots in them,
which can result in wrong branch choices.
sqrt((sec(x)-1)/(sec(x)+1)) +(1-cos(x))/sin(x) caused some problems
in 1971, though it seems to reduce to 0 right now.
If the expression is NOT zero, then the resulting expression may not
be easy to convert back to sin, cos, tan. Just a warning, that
being able to confirm high-school identities is not necessarily what
you need to do.
RJF
For real x, the expression SQRT((SEC(x)-1)/(SEC(x)+1)) +
(1-COS(x))/SIN(x) is equivalent to (1 + SIGN(SIN(x))) TAN(x/2). This
equals zero only when SIN(x) < 0.
Martin.
mathematica 6.0 produces (using FullSimplify)
tan(x/2)+ sqrt(tan(x/2)2 )
which is, as you say, zero when sin(x)<0.
This is a cute result, and it may be worth thinking about how something
like it might be obtained!
Apparently Mathematica has a route from (SEC(x)-1)/(SEC(x)+1) =
(1-COS(x))/(COS(x)+1) to SIN(x/2)^2/COS(x/2)^2 = TAN(x/2)^2.
Derive only knows to go the other way (for a suitable Trigpower
setting):
TAN(x/2)^2
[Trigonometry:=Auto, Trigpower:=Cosines]
" TAN(z/2) -> SIN(z)/(1+COS(z)) "
(SIN(x)/(COS(x)+1))^2
" SIN(z)^2 -> 1-COS(z)^2 "
(1-COS(x)^2)/(COS(x)+1)^2
" one final step "
(1-COS(x))/(COS(x)+1)
For SQRT((SEC(x)-1)/(SEC(x)+1)) with a suitable Trigonometry setting,
Derive delivers
SQRT((SEC(x)-1)/(SEC(x)+1))
[Trigonometry:=Collect, Trigpower:=Auto]
TAN(x/2)*SIGN(SIN(x)/2)
but this not stable (it also shows signs of a premature exit), with
further simplification resulting in
ABS(SIN(x))/(COS(x)+1)
Tell me if you want to see the steps.
What Maxima effectively did when simplifying SQRT((SEC(x)-1)/(SEC(x)+1))
+ (1-COS(x))/SIN(x) to zero was to take the negative root when SIN(x) >
0 and the positive root when SIN(x) < 0. With equal justification it
might have taken the positive root when SIN(x) > 0 and the negative root
when SIN(x) < 0, and thus have arrived at 2 TAN(x/2) instead of zero.
Martin.