Constructing a function with Flat and OneIdentity attribute with the property that otimes[a]:>a
I see now. The problem arises with Flat
then. Just set the attributes after setting the definitions. Or at least the Flat
attribute
ClearAll[otimes];
SetAttributes[otimes, OneIdentity]
otimes[a_] := a
SetAttributes[otimes, Flat]
Check out this answer for more details on why this works.
Basically, MMA remembers if the symbol was Flat
or not at the time each DownValue
is defined. The infinite recursion is more related to this:
SetAttributes[f, Flat];
Replace[Hold@f[2], Hold@f[i_] :> Hold[i]]
So, when you did otimes[2]
and it checked the otimes[a_]:=a
downvalue, it matched a
with otimes[2]
, so you got your infinite recursion
Update
I came up with a better answer in my response to (174384), and since that question was closed as a duplicate of this question, I thought it might be nice to include it here. Basically, one can avoid the iteration error caused by the Flat
pattern matcher by inserting a Verbatim
into the definition. So use:
SetAttributes[otimes, {OneIdentity, Flat}];
Verbatim[otimes][a_] := a
Examples:
otimes[a, b]
otimes[a]
otimes[a, b]
a
Original answer
Another possibility is to use something like:
SetAttributes[otimes, {OneIdentity,Flat}]
a_otimes /; Length[Unevaluated[a]]==1 := First @ Unevaluated @ a
Then,
otimes[a]
a
No recursion issues!
I'm guessing a bit at what you're doing here, so I do hope some of this is relevant. Trying to define your own version of multiplication is essentially trying to implement a group structure in mathematics. Here's how I would implement the dihedral group using NonCommutativeMultiply
. At the end, you'll notice that I do need to deal with expressions like NonCommutativeMultiply[a]
.
The dihedral group of order $2n$ has presentation $$\langle a,b : a^2=b^2=(ab)^n=1 \rangle.$$
Given a finite string of $a$s and $b$s representing an element of the dihedral group, there is a standard procedure to place that string into one of the following four canonical forms: $(ab)^m$, $(ab)^m b$, $(ba)^m$, or ($ba)^m a$, where $m$ is an integer such that $0\leq m<n$. To do so, simply remove each consecutive pair of identical symbols and then reduce the exponent of $ab$ or $ba$ modulo $n$. This solves the so called Word Problem for the dihedral group.
To implement this in Mathematica, first associate UpValues
with a
and b
representing the order of those elements.
a /: a ** a = 1;
b /: b ** b = 1;
a /: a ** 1 = a;
b /: b ** 1 = b;
a /: 1 ** a = a;
b /: 1 ** b = b;
Now, let's generate a long product of $a$s and $b$s.
SeedRandom[1];
w = NonCommutativeMultiply @@ RandomChoice[{a, b}, 100]
a ** b ** a ** b ** a ** b ** a ** b ** a ** b ** a ** b ** a ** b ** a ** b
The result is much shorter than 100 because cancellation has already occurred. Now let's put it in it's final form. Assuming you're working in $D_6$, you can do the following:
n = 3;
finalForm[w : NonCommutativeMultiply[a, ___, b]] :=
(a ** b)^Mod[Length[w]/2, n];
finalForm[w : NonCommutativeMultiply[a, ___, a]] :=
(a ** b)^Mod[(Length[w] - 1)/2, n] ** a;
finalForm[w : NonCommutativeMultiply[b, ___, a]] :=
(b ** a)^Mod[Length[w]/2, n];
finalForm[w : NonCommutativeMultiply[b, ___, b]] :=
(b ** a)^Mod[(Length[w] - 1)/2, n] ** b;
finalForm[w]
(a ** b)^2
Well, that's cool but what about this example:
finalForm[a ** a ** a]
finalForm[a]
We've run into exactly the problem you've described. To fix it, simply associate DownValues
with finalForm
.
finalForm[a] = a;
finalForm[b] = b;
finalForm[a ** a ** a]
a
More generally, you might define a function simplify
with the property that
simplify[NonCommutativeMultiply[a_]] := a