Skip to main content
added 14 characters in body
Source Link
thorimur
  • 9.1k
  • 18
  • 32

IfNote: You might want to consider simply using NCExpand[a_] := Distribute[a, Plus, NonCommutativeMultiply]. That said, the following provides a useful way of making NonCommutativeMultiply behave like Times with an identity (which is beneficial even outside of this problem), and also answers the original question.

So, if you want to mirror how e.g. Times works, then what you want to do is exploit the OneIdentity attribute (which NonCommutativeMultiply already has), Default values and Optional patterns, and implement an identity value for NonCommutativeMultiply.

Unprotect[NonCommutativeMultiply];

Default[NonCommutativeMultiply] = 1; (* or whatever value you'd like here *)

(* Set unary and nullary behavior: *)
Block[{a = Attributes[NonCommutativeMultiply]},
  Attributes[NonCommutativeMultiply] = {};
  NonCommutativeMultiply[a_.] := a;
  Attributes[NonCommutativeMultiply] = a;
  ];

(* Make Default[NonCommutativeMultiply] behave as an identity
   for NonCommutativeMultiply and avoid infinite recursion
   via the intercept trick: *)
NCMIntercept = True;

NonCommutativeMultiply[a_, b__] :=
 Block[{NCMIntercept = False},
  NonCommutativeMultiply @@ DeleteCases[{a,b}, Default[NonCommutativeMultiply]]
 ] /; NCMIntercept

Protect[NonCommutativeMultiply, NCMIntercept];

NCExpand[a_. ** (b_ + c_) ** d_.] := a ** b ** d + a ** c ** d

If you want to mirror how e.g. Times works, then what you want to do is exploit the OneIdentity attribute (which NonCommutativeMultiply already has), Default values and Optional patterns, and an identity value for NonCommutativeMultiply.

Unprotect[NonCommutativeMultiply];

Default[NonCommutativeMultiply] = 1; (* or whatever value you'd like here *)

Block[{a = Attributes[NonCommutativeMultiply]},
  Attributes[NonCommutativeMultiply] = {};
  NonCommutativeMultiply[a_.] := a;
  Attributes[NonCommutativeMultiply] = a;
  ];

NCMIntercept = True;

NonCommutativeMultiply[a_, b__] :=
 Block[{NCMIntercept = False},
  NonCommutativeMultiply @@ DeleteCases[{a,b}, Default[NonCommutativeMultiply]]
 ] /; NCMIntercept

Protect[NonCommutativeMultiply, NCMIntercept];

NCExpand[a_. ** (b_ + c_) ** d_.] := a ** b ** d + a ** c ** d

Note: You might want to consider simply using NCExpand[a_] := Distribute[a, Plus, NonCommutativeMultiply]. That said, the following provides a useful way of making NonCommutativeMultiply behave like Times with an identity (which is beneficial even outside of this problem), and also answers the original question.

So, if you want to mirror how e.g. Times works, then what you want to do is exploit the OneIdentity attribute (which NonCommutativeMultiply already has), Default values and Optional patterns, and implement an identity value for NonCommutativeMultiply.

Unprotect[NonCommutativeMultiply];

Default[NonCommutativeMultiply] = 1; (* or whatever value you'd like here *)

(* Set unary and nullary behavior: *)
Block[{a = Attributes[NonCommutativeMultiply]},
  Attributes[NonCommutativeMultiply] = {};
  NonCommutativeMultiply[a_.] := a;
  Attributes[NonCommutativeMultiply] = a;
  ];

(* Make Default[NonCommutativeMultiply] behave as an identity
   for NonCommutativeMultiply and avoid infinite recursion
   via the intercept trick: *)
NCMIntercept = True;

NonCommutativeMultiply[a_, b__] :=
 Block[{NCMIntercept = False},
  NonCommutativeMultiply @@ DeleteCases[{a,b}, Default[NonCommutativeMultiply]]
 ] /; NCMIntercept

Protect[NonCommutativeMultiply, NCMIntercept];

NCExpand[a_. ** (b_ + c_) ** d_.] := a ** b ** d + a ** c ** d
added 14 characters in body
Source Link
thorimur
  • 9.1k
  • 18
  • 32
 
 
 
 
added 45 characters in body
Source Link
thorimur
  • 9.1k
  • 18
  • 32

We also need to make NonCommutativeMultiply[a] be a and NonCommutativeMultiply[] be the default value. Due to, I suspect (but possibly not), the magic of Optional, we need to temporarily clear the OneIdentityNonCommutativeMultiply attribute's attributes while setting that definition.

Unprotect[NonCommutativeMultiply];

Default[NonCommutativeMultiply] = 1; (* or whatever value you'd like here *)

ClearAttributes[NonCommutativeMultiply,Block[{a OneIdentity]= Attributes[NonCommutativeMultiply]},
  Attributes[NonCommutativeMultiply] = {};
  NonCommutativeMultiply[a_.] := aa;
  Attributes[NonCommutativeMultiply] = a;
SetAttributes[NonCommutativeMultiply, OneIdentity] ];

NCMIntercept = True;

NonCommutativeMultiply[a_, b__] :=
 Block[{NCMIntercept = False},
  NonCommutativeMultiply @@ DeleteCases[{a,b}, Default[NonCommutativeMultiply]]
 ] /; NCMIntercept

Protect[NonCommutativeMultiply, NCMIntercept];

NCExpand[a_. ** (b_ + c_) ** d_.] := a ** b ** d + a ** c ** d

We also need to make NonCommutativeMultiply[a] be a and NonCommutativeMultiply[] be the default value. Due to, I suspect (but possibly not), the magic of Optional, we need to temporarily clear the OneIdentity attribute while setting that definition.

Unprotect[NonCommutativeMultiply];

Default[NonCommutativeMultiply] = 1; (* or whatever value you'd like here *)

ClearAttributes[NonCommutativeMultiply, OneIdentity]

NonCommutativeMultiply[a_.] := a

SetAttributes[NonCommutativeMultiply, OneIdentity]

NCMIntercept = True;

NonCommutativeMultiply[a_, b__] :=
 Block[{NCMIntercept = False},
  NonCommutativeMultiply @@ DeleteCases[{a,b}, Default[NonCommutativeMultiply]]
 ] /; NCMIntercept

Protect[NonCommutativeMultiply, NCMIntercept];

NCExpand[a_. ** (b_ + c_) ** d_.] := a ** b ** d + a ** c ** d

We also need to make NonCommutativeMultiply[a] be a and NonCommutativeMultiply[] be the default value. Due to, I suspect (but possibly not), the magic of Optional, we need to temporarily clear NonCommutativeMultiply's attributes while setting that definition.

Unprotect[NonCommutativeMultiply];

Default[NonCommutativeMultiply] = 1; (* or whatever value you'd like here *)

Block[{a = Attributes[NonCommutativeMultiply]},
  Attributes[NonCommutativeMultiply] = {};
  NonCommutativeMultiply[a_.] := a;
  Attributes[NonCommutativeMultiply] = a;
  ];

NCMIntercept = True;

NonCommutativeMultiply[a_, b__] :=
 Block[{NCMIntercept = False},
  NonCommutativeMultiply @@ DeleteCases[{a,b}, Default[NonCommutativeMultiply]]
 ] /; NCMIntercept

Protect[NonCommutativeMultiply, NCMIntercept];

NCExpand[a_. ** (b_ + c_) ** d_.] := a ** b ** d + a ** c ** d
Source Link
thorimur
  • 9.1k
  • 18
  • 32
Loading