1
$\begingroup$

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

  • 0
    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...2011-08-05
  • 0
    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.2011-08-05
  • 0
    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?2011-08-05
  • 0
    (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)))2011-08-05
  • 0
    to be turned in to...2011-08-05
  • 0
    `(1/(2 r^5)) c0 (x^2 + y^2 - 2 z^2 + s2 a2 + c2 (a1 - 8 r^4 \Omega^4))`2011-08-05
  • 1
    Sorry, I'm still trying to figure out how to take expressions from Mathematica and paste them here in a sensible way.2011-08-05
  • 0
    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.2011-08-05
  • 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.2011-08-05
  • 0
    Shall we move to chat?2011-08-05
  • 0
    @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.2011-08-05
  • 0
    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.)2011-08-05
  • 0
    In this case works `pat = a b v___ - c d v___; simpRule = {pat -> e v, -pat -> -e v}`.2011-08-05
  • 0
    Is there a way to express this in terms of conditionals on Heads?2011-08-05
  • 0
    I've given this suggestion a try:2011-08-05
  • 0
    `(-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`2011-08-05
  • 0
    Here is the replacement rule you (@Andrew) suggested (assuming I translated correctly.)2011-08-05
  • 0
    `{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)}`2011-08-05
  • 0
    But the output is unchanged.2011-08-05
  • 0
    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`2011-08-05
  • 0
    Now if we have 'expr = (-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;'2011-08-05
  • 0
    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}$$2011-08-05
  • 0
    I see in your pat1 that you single out the r*Omega*x*y term for identification of the a1 piece in the expression. Unfortunately, a2 includes a term proportional to (r*Omega)^2*x*y, and in the full set of expressions I need to simplify I can't rely on powers of r*Omega to distinguish between these two. I'm now thinking that perhaps the ratio of the coefficients on the (x^2 - y^2) and (x*y) will be the unique identifier, where I'll be relying on Coefficient[] to pull these out.2011-08-09
  • 1
    I'd still love to have an answer to the original question if anyone is interested.2011-08-09

3 Answers 3

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]]  ] 
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.

  • 0
    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`.2011-08-20
  • 0
    @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.2011-08-20
  • 0
    I was not aware of `RepeatedNull`, +1.2011-09-29
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.

  • 0
    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.2011-08-09
  • 0
    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.2011-08-10