2
$\begingroup$

I'm working with a notebook that defines NonCommutativeMultiply on a defined set of symbols, called operators. Semantically, this is a list of objects that have a noncommutative multiplication (operators on a Hilbert space). It also contains a function CNumberQ that returns true when its argument does not contain any operator.

CNumberQ[expr_] := And @@ (FreeQ[expr, #] & /@ operators);

NonCommutativeMultiply has, as one of its definitions,

x_ ** y_ := x y /; CNumberQ[x] || CNumberQ[y]

Even though the replacement rule is constrained, the following pattern

x_ ** y_

evaluates to

x_ y_

Why does Mathematica apply a constrained replacement rule to a pattern that is unconstrained? I know I can work around this by using HoldPattern, but I could not figure out why this replacement happens by looking at the documentation for rules and patterns.

$\endgroup$
  • 1
    $\begingroup$ probably because Pattern and Blank are not in the list of operators, i.e., CNumberQ[y_] evaluates to True? $\endgroup$ – kglr Jul 3 at 14:22
  • $\begingroup$ That could be it. The behaviour still seems counterintuitive to me though, given CNumberQ's intended purpose. Perhaps CNumberQ could be redefined to treat pattern arguments properly? I'm a little new to Mathematica, so do you know if this comes under some common design pattern? $\endgroup$ – Styg Jul 3 at 14:26
  • $\begingroup$ Samarth, could you post some concrete examples of operators. $\endgroup$ – kglr Jul 3 at 14:28
  • $\begingroup$ The notebook I'm working with is based on the virasoro.nb notebook here. Everything relevant to my question is unchanged from virasoro.nb $\endgroup$ – Styg Jul 3 at 17:22
  • $\begingroup$ Samarth, posted the comment as an answer. $\endgroup$ – kglr Jul 3 at 18:43
3
$\begingroup$

Using a made-up operator ncm (to avoid unprotecting and making changes to NoncommutativeMultiply)

This replicates the case in OP:

ClearAll[ncm]
operators = {Times, Plus};
CNumberQ[expr_] := And @@ (FreeQ[expr, #] & /@ operators);
x_ ~ ncm ~ y_ := x y /; CNumberQ[x] || CNumberQ[y]
x_~ ncm ~ y_
x_ y_

As expected

 CNumberQ[y_]

True

and adding Pattern in the list operators:

ClearAll[ncm]
operators = {Times, Plus, Pattern};
x_ ~ ncm ~ y_ := x y /; CNumberQ[x] || CNumberQ[y]
x_~ ncm ~ y_
ncm[x_, y_]
$\endgroup$
  • $\begingroup$ By "operators" in this context I don't mean things like Times and Plus. I mean things that have a noncommutative multiplication (it is clear if one looks at the virasoro.nb notebook, but I'll edit the question accordingly). $\endgroup$ – Styg Jul 4 at 16:21
  • $\begingroup$ @Samarth, just use your own list for operators (this was meant as an illustration). $\endgroup$ – kglr Jul 4 at 16:23
  • $\begingroup$ I see. Thanks for the answer! A little follow up: instead of adding Pattern to operators, which would be semantically incorrect, is there a way to supplement the definition of CNumberQ with a special case for a blank or a pattern? $\endgroup$ – Styg Jul 4 at 16:27
  • $\begingroup$ Samarth, you can use x_ ** y_ := x y /; (CNumberQ[x] || CNumberQ[y]) && FreeQ[{x, y}, Pattern] or define CNumberQ2 as CNumberQ2[expr_] := CNumberQ[expr] && FreeQ[expr, Pattern] and use it instead of CnumberQ, i.e. x_ ** y_ := x y /; CNumberQ2[x] || CNumberQ2[y]. $\endgroup$ – kglr Jul 4 at 16:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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