1

I'm having trouble setting a pattern for simplifying a complex expression. I've distilled the question down to the simplest case where Mathematica seems to fail.

I set up a simple rule based on a pattern:

simpRule = a b v___ - c d v___ -> e v

which works on the direct case

a b - c d /. simpRule
e

but fails if I simply add a minus sign.

-a b + c d /. simpRule
-a b + c d

How do I go about writing a more robust rule? Or perhaps there's a better way to go about performing simplifications of this sort?

Thanks, Keith

Keith
  • 243
  • Just so I understand your problem: you want all instances of Subtract[a b something, c d something] to be replaced by e*something, or do you need something more general? In any event, there is the built-in function Factor[] which might be apropos... – J. M. ain't a mathematician Aug 05 '11 at 05:28
  • I'm hoping that dealing with the minus sign issue will solve my more general problem. The real problem I'm trying to solve is more complicated, or rather there are more terms, but I think I've distilled the problem down to the source of my difficulty. I've tried Factor[], among other things, but so far I haven't been able to construct a replacement rule that works consistently. – Keith Aug 05 '11 at 05:44
  • If your "complex expression" is not too complex, could you post it, and then mention what you're expecting that to be turned into after applying the appropriate transformations? – J. M. ain't a mathematician Aug 05 '11 at 06:07
  • (1/(2 r^5)) c0 (x^2 + y^2 - 2 z^2 + s2 (-6 r x^2 [CapitalOmega] + 6 r y^2 [CapitalOmega] + x y (6 - 8 r^2 [CapitalOmega]^2)) + c2 (12 r x y [CapitalOmega] - 8 r^4 [CapitalOmega]^2 + x^2 (3 - 4 r^2 [CapitalOmega]^2) + y^2 (-3 + 4 r^2 [CapitalOmega]^2))) – Keith Aug 05 '11 at 06:29
  • to be turned in to... – Keith Aug 05 '11 at 06:29
  • (1/(2 r^5)) c0 (x^2 + y^2 - 2 z^2 + s2 a2 + c2 (a1 - 8 r^4 \Omega^4)) – Keith Aug 05 '11 at 06:38
  • 1
    Sorry, I'm still trying to figure out how to take expressions from Mathematica and paste them here in a sensible way. – Keith Aug 05 '11 at 06:39
  • I've got maybe 20 similar expressions that I need to simplify in the same way. So far I've been writing endless lists of very similar replacement rules, which works, but I'd really like to get Mathematica to do it for me. – Keith Aug 05 '11 at 06:41
  • 1
    "I'm still trying to figure out how to take expressions from Mathematica and paste them here in a sensible way." - apply InputForm[] to whatever output Mathematica spits back. – J. M. ain't a mathematician Aug 05 '11 at 06:46
  • Shall we move to chat? – Keith Aug 05 '11 at 06:59
  • @Keith What is the desired replacement rule for this example? As for the problem in the initial post, simpRule = {a b v___ - c d v___ -> e v, -a b v___ + c d v___ -> e v} gives the desired result. – Andrew Aug 05 '11 at 06:59
  • Is it possible to write the rule so that it can perform both substitutions? (Almost every time I compute a new quantity, I find that I have to write another variant of the original replacement rule.) – Keith Aug 05 '11 at 07:12
  • In this case works pat = a b v___ - c d v___; simpRule = {pat -> e v, -pat -> -e v}. – Andrew Aug 05 '11 at 07:44
  • Is there a way to express this in terms of conditionals on Heads? – Keith Aug 05 '11 at 07:47
  • I've given this suggestion a try: – Keith Aug 05 '11 at 07:53
  • (-4*c0*c2*r\[CapitalOmega]^2)/r^3 + (c0*x^2)/(2*r^5) + (3*c0*c2*x^2)/(2*r^5) - (2*c0*c2*r\[CapitalOmega]^2*x^2)/r^5 - (3*c0*r\[CapitalOmega]*s2*x^2)/r^5 + (6*c0*c2*r\[CapitalOmega]*x*y)/r^5 + (3*c0*s2*x*y)/r^5 - (4*c0*r\[CapitalOmega]^2*s2*x*y)/r^5 + (c0*y^2)/(2*r^5) - (3*c0*c2*y^2)/(2*r^5) + (2*c0*c2*r\[CapitalOmega]^2*y^2)/r^5 + (3*c0*r\[CapitalOmega]*s2*y^2)/r^5 - (c0*z^2)/r^5 – Keith Aug 05 '11 at 07:54
  • Here is the replacement rule you (@Andrew) suggested (assuming I translated correctly.) – Keith Aug 05 '11 at 07:56
  • {3*x^2*(v___) - 4*r\[CapitalOmega]^2*x^2*(v___) + 12*r\[CapitalOmega]*x*y*(v___) - 3*y^2*(v___) + 4*r\[CapitalOmega]^2*y^2*(v___) -> a1*v, -3*x^2*(v___) + 4*r\[CapitalOmega]^2*x^2*(v___) - 12*r\[CapitalOmega]*x*y*(v___) + 3*y^2*(v___) - 4*r\[CapitalOmega]^2*y^2*(v___) -> -(a1*v)} – Keith Aug 05 '11 at 07:56
  • But the output is unchanged. – Keith Aug 05 '11 at 07:57
  • It is possible to change parts as next. For example, one wants to change in expr=x^2y^2+ 3 x z^3+y+x z^4 the part x^2y^2+ 3 x z^3 on a1. Then one can take some pattern which appears in a1 only once, for example, pp=x z^3. Substituting in a1=x^2y^2+ 3 x z^3 and finding pp->a(1-x^2y^2)/3 it is possible now to simplify expr by changing expr/.{x z^3->pp}/.pp->(a1-x^2y^2)/3 – Andrew Aug 05 '11 at 09:13
  • Now if we have 'expr = (-4c0c2r[CapitalOmega]^2)/ r^3 + (c0x^2)/(2r^5) + (3c0c2x^2)/(2r^5) - (2c0c2 r[CapitalOmega]^2x^2)/r^5 - (3c0r[CapitalOmega]s2x^2)/ r^5 + (6c0c2r[CapitalOmega]xy)/r^5 + (3c0s2xy)/ r^5 - (4c0r[CapitalOmega]^2s2xy)/ r^5 + (c0y^2)/(2r^5) - (3c0c2y^2)/(2r^5) + (2c0c2 r[CapitalOmega]^2y^2)/r^5 + (3c0r[CapitalOmega]s2y^2)/ r^5 - (c0z^2)/r^5;' – Andrew Aug 05 '11 at 09:14
  • Then pat = 3*x^2 - 4*r\[CapitalOmega]^2*x^2 + 12*r\[CapitalOmega]*x*y - 3*y^2 + 4*r\[CapitalOmega]^2*y^2; pat1 = r\[CapitalOmega]*x*y; pat2 = (pat /. pat1 -> pp); pat3 = Solve[pat2 == a1, pp][[1]]; expr /. pat1 -> pp /. pat3 // Simplify will give $$\frac{\text{c0} \left(\text{a1} \text{c2}-8 \text{c2} r^2 \text{r$\Omega $}^2-8 \text{r$\Omega $}^2 \text{s2} x y-6 \text{r$\Omega $} \text{s2} x^2+6 \text{r$\Omega $} \text{s2} y^2+6 \text{s2} x y+x^2+y^2-2 z^2\right)}{2 r^5}$$ – Andrew Aug 05 '11 at 09:15
  • I see in your pat1 that you single out the rOmegaxy term for identification of the a1 piece in the expression. Unfortunately, a2 includes a term proportional to (rOmega)^2xy, and in the full set of expressions I need to simplify I can't rely on powers of rOmega to distinguish between these two. I'm now thinking that perhaps the ratio of the coefficients on the (x^2 - y^2) and (xy) will be the unique identifier, where I'll be relying on Coefficient[] to pull these out. – Keith Aug 09 '11 at 01:20
  • 1
    I'd still love to have an answer to the original question if anyone is interested. – Keith Aug 09 '11 at 01:23

3 Answers3

2

Eventually I posted the same question on MathGroup and received an answer which I think is superior to the one I posted before. I thought I should add it here.

As before, this is not strictly a replacement rule, instead it uses Mathematica's PolynomialReduce[], but it seems to be quite robust and if people come across this question they should be aware of this solution.

simpMeth[expr_] := Module[{pExpr},
  pExpr = PolynomialReduce[expr, a b - c d, {b, d}];
  pExpr[[1, 1]] e + pExpr[[2]]
 ]
Keith
  • 243
1

You need to be aware of the FullForm of the expressions you are working with to correctly use replacement rules. Consider the FullForm of the two expressions you use ReplaceAll (/.) on:

 a b - c d // FullForm
-a b + c d // FullForm
(* Out *) Plus[Times[a, b], Times[-1, c, d]]
(* Out *) Plus[Times[-1, a, b], Times[c, d]]

From this you can see how the negation is internally represented as multiplication by -1, and therefore, why your rule matches differently. One way to allow for the alternative pattern is this:

rule = (-1 a b v___ | a b v___) + (-1 c d v___ | c d v___) -> e v;

This makes use of Alternatives.

Another, somewhat more opaque way is:

rule = (-1 ...) a b v___ + (-1 ...) c d v___ -> e v;

Which makes use of RepeatedNull.

Mr.Wizard
  • 802
  • Unfortunately both of your rules produce unexpected results when the coefficient is negative. Naming the first subRuleMW1 I get c*d - a*b /. subRuleMW1 produces e. For the second, subRuleMW2 I get c*d - a*b /. subRuleMW2 produces e. – Keith Aug 20 '11 at 06:29
  • @Keith I do not understand what you are trying to accomplish. I am sorry if that resulted in giving you bad code. If looking at the FullForm of your expressions does not allow you to construct working rules yourself, please post a series of examples of input and desired output, and I will try again. – Mr.Wizard Aug 20 '11 at 06:38
  • I was not aware of RepeatedNull, +1. – rcollyer Sep 29 '11 at 14:58
0

Here's the best solution I've come up with so far. (Yes, I'm answering my own question, but I thought it would be nice to have some resolution to this question.)

simp[expr_] := Module[{fab,fcd,fabmcd,f0},
  {fab,fcd} = {Coefficient[expr, a b], Coefficient[expr, c d]};
  fabmcd = (1/2)(fab - fcd);
  f0 = Simplify[expr - fabmcd (a b - c d)];
  f0 + fabmcd e
]

Here's how it works:

simp[a b - c d] produces e,

simp[-a b + c d] produces -e and

simp[a b - c d + c] produces e + c.

My original intention was to make a more robust pattern rule, however I haven't figured out how to do that. Instead the solution I'm presenting here is based on using Mathematica's Coefficient[] function. In my experience, Coefficient[] and CoefficientList[] can be used to do quite sophisticated expression rearrangement. None the less, someday I'd like figure how to do sophisticated pattern matching.

Keith
  • 243
  • If anyone is interested in the Coefficient[] based solution to the problem posed in the comments above, I'll be happy to post that as well. – Keith Aug 09 '11 at 23:14
  • I don't have sufficient reputation to vote up anybody's comments, however I would like to give some credit to Andrew. In one of his comments above he outlines a technique where a single term is used to identify the coefficient on an a1 term. It was this approach that got me thinking, and ultimately led to the answer I've posted. – Keith Aug 10 '11 at 02:16