Simplification Problem



On 9/5/06, Wolfgang Hugemann <Wolfgang at hugemann.de> wrote:
> This is a general problem for me when working with Maxima: I seldomly
> succed in compacting the output.

Yes, this is often difficult, and of course the optimum form of the
result depends on the application.  But here are a few techniques to
try.

The "factor" and "factorsum" functions often simplify expressions
considerably.  If there are exponentials and roots, "radcan" is worth
trying.  With expressions involving trigonometric functions,
"trigsimp" and "trigrat" are often useful, though it is sometimes
better to expand using trigexpand, simplify algebraically, then
contract using trigreduce -- or vice versa.

In your particular example, there is a lot of room for factoring
subexpressions.  In that case, I use the substpart function quite a
lot.  But I wanted an approach which might be more automatic, so I
wrote a simple combinatorial function which looks for factorizations
of parts of a sum.

partition_factor(ex):=
  block([s,op,inflag:true],
    if atom(ex) or op(ex) # "+"
      then set(set(ex))
      else
        s: set_partitions(setify(args(ex))),
	map(lambda([q],
		   xreduce("+",map(lambda([r],factor(xreduce("+",args(r)))),q)))
	     ,s))$

This is somewhat like factorsum, but more general and much slower.
Examples:

    ex:  e*f+d*f+b*c+a*c$
    factorsum(ex) =>  (e+d)*f+(b+a)*c
    partition_factor(ex) =>                         (factors all
partitions of the sum)
     {e*f+d*f+b*c+a*c,e*f+d*f+(b+a)*c,(e+d)*f+b*c+a*c,(e+d)*f+(b+a)*c}

But factorsum doesn't work in many cases:

   ex: a^2-b^2+c^2-d^2$
   factorsum(ex) => same
   partition_factor(ex) =>
     {(c-b)*(c+b)-(d-a)*(d+a),  /*This is probably what you're looking for*/
      -(d-a)*(d+a)+c^2-b^2,
      -(d-c)*(d+c)-(b-a)*(b+a),
      -(d-c)*(d+c)-b^2+a^2,
      -d^2+(c-b)*(c+b)+a^2,
      -d^2+c^2-(b-a)*(b+a),
      -d^2+c^2-b^2+a^2}

Now let's look at your example,

rr: 4*a^2*y/(sin(alpha)*g) =
4*a^2*(((2*sin(alpha)*g*v0^2-4*a*sin(alpha)*g*t*v0+2*a^2*sin(alpha)*g*t^2)*log(2*a*v0-2*a\
^2*t)+2*a*sin(alpha)*g*t*v0-a^2*sin(alpha)*g*t^2)/(4*a^2)-sin(alpha)*g*(v0-a*t)^2*log(2*a*v0)/(2*a^2))/(sin(alpha)*g)

(by the way, make sure to return logexpand to its default first:
logexpand:false)

Let's concentrate on the right-hand side:

rh: part(rr,2)$

Now factor it in order to make logexpand more effective, and expand
the logarithms:

  ri:  expand(  ev(factor(rh),logexpand:all) )$

Now let's use partition_factor to pull out some of the obvious structure here:

  pf: partition_factor(ri)$

NOTE: I am using "$" to not display the result, since it is very large.

partition_factor is very slow (exponential in the length of the
expression) and on my machine takes about 8 seconds.

 length(pf) => 2589

Obviously we don't want to look at all of these.

Let's sort by size:

load("stringproc")$
shortest_first(s):=
sort(args(s),lambda([a,b],slength(string(a))<slength(string(b))))$

pfs: shortest_first(pf)$
/* Amazingly, this takes 45 seconds, much more than the
     main calculation.  Could be optimized, but why bother? */

Now look at the first few results (with display2d:false):

pfs1: part(pfs,1) =>  2*(v0-a*t)^2*(log(v0-a*t)-log(v0))+a*t*(2*v0-a*t)
pfs2: part(pfs,2) => 2*(v0-a*t)^2*(log(v0-a*t)-log(v0))+2*a*t*v0-a^2*t^2

These look pretty good.  Let's just contract the logs in the first one:

   substpart(logcontract(piece), pfs1, 1,3)
          => 2*(v0-a*t)^2*log((v0-a*t)/v0)+a*t*(2*v0-a*t)

Which looks very good!

I will admit that the first time around, I did this all using
substpart, and only wrote partition_factor afterwards.

Hope this is helpful.

            -s