Simplification of exp(x*%i*%pi)



I had a look at the implementation of simplifications for expressions
like exp(x*%i*%pi) where x is an arbitrary expression.

With revision 1.88 of simp.lisp the call of %especial has been disabled
for x a float or bigfloat value to avoid curious results. But %especial
can do a lot of more general simplifications. Unfortunately, these have
been disabled too (my error).

Some simplifications of %especial are problematic, e.g.

exp((2+x)^2*%pi*%i)  -> %e^(%i*%pi*(x+2)^2-4*%i*%pi)
exp((2+x)^10*%pi*%i) -> %e^(%i*%pi*(x+2)^10-1024*%i*%pi)

Now the handling of expressions is inconsistent, e.g. the following is
simplified

   exp((2+x)*%i*%pi) -> exp(%i*%pi*x)

but not the expanded form

   exp(2*%i*%pi%+%i*%pi*x) -> e^(%i*%pi*x+2*%i*%pi)

Furthermore, we have inconsistent simplifications of expressions which
contain float or bigfloat values.

The following shows some examples of a testfile to check the
simplification of expressions like exp(x*%pi*%) and the desired results:

********************** Problem 5 ***************
Input:
exp(2*%i*%pi)


Result:
1

... Which was correct.

********************** Problem 6 ***************
Input:
exp((x+2)*%i*%pi)


Result:
%e^(%i*%pi*x)

... Which was correct.

********************** Problem 7 ***************
Input:
exp(x*%i*%pi+2*%i*%pi)


Result:
%e^(%i*%pi*x+2*%i*%pi)

This differed from the expected result:
exp(x*%i*%pi)

********************** Problem 8 ***************
Input:
log(exp((x+2)^2*%i*%pi))


Result:
%i*%pi*(x+2)^2-4*%i*%pi

This differed from the expected result:
(x+2)^2*%i*%pi

********************** Problem 9 ***************
Input:
exp(2.0*%i*%pi)


Result:
%e^(2.0*%i*%pi)

This differed from the expected result:
1.0

********************** Problem 10 ***************
Input:
exp((x+2.0)*%i*%pi)


Result:
%e^(%i*%pi*x)

This differed from the expected result:
exp(1.0*x*%i*%pi)

********************** Problem 11 ***************
Input:
exp(x*%i*%pi+2.0*%i*%pi)


Result:
%e^(%i*%pi*x+2.0*%i*%pi)

This differed from the expected result:
exp(1.0*x*%i*%pi)

********************** Problem 12 ***************
Input:
log(exp((x+2.0)^2*%i*%pi))


Result:
%i*%pi*(x+2.0)^2-4*%i*%pi

This differed from the expected result:
(x+2.0)^2*%i*%pi

********************** Problem 13 ***************
Input:
exp(2.0b0*%i*%pi)


Result:
%e^(2.0b0*%i*%pi)

This differed from the expected result:
1.0b0

********************** Problem 14 ***************
Input:
exp((x+2.0b0)*%i*%pi)


Result:
%e^(%i*%pi*x)

This differed from the expected result:
exp(1.0b0*x*%i*%pi)

********************** Problem 15 ***************
Input:
exp(x*%i*%pi+2.0b0*%i*%pi)


Result:
%e^(%i*%pi*x+2.0b0*%i*%pi)

This differed from the expected result:
exp(1.0b0*x*%i*%pi)

********************** Problem 16 ***************
Input:
log(exp((x+2.0b0)^2*%i*%pi))


Result:
%i*%pi*(x+2.0b0)^2-4*%i*%pi

This differed from the expected result:
(x+2.0b0)^2*%i*%pi

********************** Problem 17 ***************
Input:
exp(3*%pi*%i/2)


Result:
-%i

... Which was correct.

********************** Problem 18 ***************
Input:
exp(1.5*%pi*%i)


Result:
%e^(1.5*%i*%pi)

This differed from the expected result:
-1.0*%i

********************** Problem 19 ***************
Input:
exp(1.5b0*%pi*%i)


Result:
%e^(1.5b0*%i*%pi)

This differed from the expected result:
-1.0b0*%i

********************** Problem 20 ***************
Input:
exp((x+3/2)*%pi*%i)


Result:
-%i*%e^(%i*%pi*x)

... Which was correct.

********************** Problem 21 ***************
Input:
exp((x+1.5)*%pi*%i)


Result:
-%i*%e^(%i*%pi*x)

This differed from the expected result:
-%i*exp(1.0*%i*%pi*x)

********************** Problem 22 ***************
Input:
exp((x+1.5b0)*%pi*%i)


Result:
-%i*%e^(%i*%pi*x)

This differed from the expected result:
-%i*exp(1.0b0*%i*%pi*x)


To get all desired simplifications we have to modify the routine %
especial. This could be the new code:

(defun %especial (e)
  (prog (varlist y k kk j ans $%emode $ratprint genvar)
     (let ()
       (unless (setq y (pip ($ratcoef e '$%i))) (return nil))

       ;; Subtract the term y*%i*%pi from the expression e.
       (setq k ($expand (add e (mul -1 '$%pi '$%i y)) 1))

       ;; This is a workaround to get the type (integer, float, or
bigfloat)
       ;; of the expression. kk must evaluate to 1, 1.0, or 1.0b0.
       ;; Furthermore, if e is nonlinear, kk does not simplify to a
number ONE.
       ;; Because of this we do not simplify something like exp((2+x)^2*
%i*%pi)
       (setq kk (div (sub ($expand e) k) (mul '$%i '$%pi y)))
       
       ;; Return if kk is not an integer or kk is ONE, but y not an
integer
       ;; or a half integral value.
       (if (not (or (integerp kk)
                    (and (onep1 kk)
                         (integerp (add y y)))))
           (return nil))
       
       (setq j (trigred y))
       (setq ans (spang1 j t)))
                
     (cond ((among '%sin ans)
            (cond ((equal y j) (return nil))
                  ((zerop1 k)
                   ;; To preverse the type we add k into the expression.
                   (return (power '$%e (mul %p%i (add k j)))))
                  (t 
                    ;; To preserve the type we multiply kk into the
result.
                    (return (power '$%e (add (mul kk k) (mul kk %p%i
j))))))))
     (setq y (spang1 j nil))
     ;; To preserve the type we multiply kk into the expression.
     (return (mul (power '$%e (mul kk k)) (add y (mul '$%i ans))))))

Dieter Kaiser