Short answer is replacement with ** is trick. See section ReplaceAll (/.) and ReplaceRepeated (//.) often fail of the manual. The best fix is to use the NCReplace
family of functions. But you still need to be carefull.
In your case there is a lot going on here for it to fail. Let me start with a couple of alternatives.
NCReplaceAll[a ** b ** c ** d ** e, c ** d -> Sequence[]]
is the simplest way to do it that I can think of. A pattern like yours would also work if you make the rule delayed, as in
NCReplaceAll[ a ** b ** c ** d ** e, {X___ ** c ** d ** Y___ :> X ** Y}]
This works because the right-hand side of the rule is only evaluated after the match, at which time X
and Y
hold noncommutative symbols and the **
survives the evaluation. The reason why your rule is failing is because the right-hand side, that is X ** Y
is evaluated before the match is done. At that time, X
and Y
are the global X
and Y
which are, in the absence of a SetNonCommutative
command, commutative. Therefore X ** Y
evaluates to X Y
before the rule is even applied. To make it even more confusing, the rule
NCReplaceAll[ a ** b ** c ** d ** e, {x___ ** c ** d ** y___ -> x ** y}]
would have worked because x
and y
are set as noncommutative by default so that the right-hand side evaluates to x**y
even if you use ->
instead of :>
.