3
$\begingroup$

I am trying to set up a clever set of rules. Say, I am working symbolically with commutators comm of matrices, where for instance

commRules={
    comm[a_+b_,c_]:>comm[a,c]+comm[b,c],
    comm[ac_?NumericQ * a_+bc_?NumericQ * b_,c_]:>ac*comm[a,c]+bc*comm[b,c],
};

Since those two rules are moreorless the same (up to the constants ac and bc), I am pretty sure one can combine them into one rule. I was thinking of using something like default arguments for functions, as for instance done in this question and answer - so maybe something along these lines: comm[ac:(_?NumericQ):1 *a_ + b_,c_]:>ac*comm[a,c]+comm[b,c]. Of course, this does not work and ends up throwing an error.

Is it possible to combine the _?NumericQ tests such that I do not have to hard-code each combination of where the constant factors may appear?

To be very clear, I would like to have a SINGLE rule commRule that does e.g. do the follwing

comm[a+b,c]/.commRule
comm[2*a+b,c]/.commRule
comm[2*a+3*b,4*c]/.commRule
(* comm[a,c]+comm[b,c] *)
(* 2*comm[a,c]+comm[b,c] *)
(* 8*comm[a,c]+12*comm[b,c] *)

** Update ** I also unsuccessfully attempted to use BlankNullSequence for this:

comm[a + b, c] /. {comm[a_ + fac2___?NumericQ*b_, c] :> comm[a, c] + fac2*comm[b, c]}
(* comm[a + b, c] *)
$\endgroup$
2
  • 1
    $\begingroup$ In order to avoid subtle mistakes it is usually better to use a set of simple rules. E.g. commRules={ comm[a_+b_,c_] :> comm[a,c]+comm[b,c], comm[ac_?NumericQ * a_,c_] :> ac*comm[a,c] }; $\endgroup$
    – Ray Shadow
    Apr 11, 2017 at 22:59
  • $\begingroup$ @Shadowray Thanks for your input. You're suggesting the usage of ReplaceRepeated in order to split all commutators involving sums into the form comm[a,c] and then check for constants, right? This is my current approach actually, but I am curious if a one-liner exists. Can you please be a bit more specific about the subtle mistakes you're referring to? $\endgroup$
    – Lukas
    Apr 11, 2017 at 23:10

1 Answer 1

3
$\begingroup$

Your three examples are met using Optional and the existing Default for Times:

commRule = comm[ac_. a_ + bc_. b_, cc_. c_] :> ac*cc*comm[a, c] + bc*cc*comm[b, c];

comm[a + b, c]       /. commRule
comm[2*a + b, c]     /. commRule
comm[2*a + 3*b, 4*c] /. commRule
comm[a, c] + comm[b, c]

2 comm[a, c] + comm[b, c]

8 comm[a, c] + 12 comm[b, c]

What remains is the additional testing to prevent:

comm[x*a + b, c] /. commRule
comm[b, c] + a comm[x, c]

With that additional testing:

commRule = comm[ac_. a_ + bc_. b_, cc_. c_] /; 
    NumericQ[ac] && NumericQ[bc] && NumericQ[cc] :> 
   ac*cc*comm[a, c] + bc*cc*comm[b, c];

Or in a different style, arguably more or less clean:

commRule = comm[Optional[ac_?NumericQ] a_ + Optional[bc_?NumericQ] b_, 
    Optional[cc_?NumericQ] c_] :> ac*cc*comm[a, c] + bc*cc*comm[b, c];

Now:

comm[x*a + b, c] /. commRule
comm[b, c] + comm[a x, c]

This might not be what is desired, but it results because the expression a x matches the pattern a_ and a default value of 1 is used for ac_. -- you should clarify how this case should be handled.

$\endgroup$
2
  • $\begingroup$ Thank you very much, your last version of commRule is exactly what I was looking for. That a x matches the pattern a is absolutely desired in this case, unless neither a or x have attribute NumericQ. $\endgroup$
    – Lukas
    Apr 12, 2017 at 8:58
  • $\begingroup$ @Lukas Glad I could help, and thanks for the Accept. $\endgroup$
    – Mr.Wizard
    Apr 12, 2017 at 16:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.