Any idea how to define some operator ° such that e.g. $((a°b)°c)°d=a°(b°(c°d))=a°b°c°d=b°c°d°a$ (but $a°b\neq{b°a}$ in general)? So ° is Flat plus (insert here)?
2 Answers
Updated to fix cyclic sort, and to allow additional operator definitions
@mikado mentions that giving an operator the Flat
attribute in addition to a cyclic automatic sort makes the operator commutative. This is because the cyclic automatic sort gets applied during the Flat
pattern matching rewrite. It is possible to avoid this issue as follows:
ClearAll[SmallCircle];
SetAttributes[SmallCircle,Flat];
u_SmallCircle:= Module[{args = Hold @@ Unevaluated @ u, ord},
ord = First @ Ordering @ NestList[RotateLeft, args, Length[args] - 1];
RotateLeft[Unevaluated[u], ord-1] /; ord != 1
]
The key is that SmallCircle[u__]
is never used, and so Flat
pattern matching rewrites of the sort:
SmallCircle[a, b, c] -> SmallCircle[SmallCircle[a, b], c]
never occur. Simple example:
a ∘ c ∘ b
e ∘ c ∘ b
a∘c∘b
b∘e∘c
Update
The OP requested to have support for additional SmallCircle
definitions. The problem with adding additional SmallCircle
rules is that inevitably these additional rules will cause the operator to become commutative. One can either use mikado's approach, or one can add a helper function to take care of these additional rules. For example:
ClearAll[SmallCircle, iSmallCircle];
SetAttributes[{SmallCircle, iSmallCircle}, Flat];
u_SmallCircle := Module[{args = Hold @@ Unevaluated @ u, r},
r = cycleSort[iSmallCircle @@ args];
SmallCircle @@ r /; r =!= args
]
iSmallCircle[b, a] := d
iSmallCircle[a, x___, b] := iSmallCircle[d, x]
cycleSort[u_iSmallCircle] := RotateLeft[
Hold @@ u,
First @ Ordering @ NestList[RotateLeft, u, Length[u] - 1] - 1
]
A couple examples:
e ∘ b ∘ a ∘ x ∘ b ∘ a
a ∘ c ∘ b
d∘e∘d∘x
c∘d
-
$\begingroup$ Now suppose that in your example I have an additional simplification rule, say b°a=d. Under which condition will Mathematica "find" it, i.e. try out a°c°b=b°a°c and then simplify to d°c? (And not being stuck at the canonical order a°c°b) $\endgroup$ Commented Jun 5, 2017 at 10:40
-
-
$\begingroup$ It's tricky. :-) (I also already thought about if the pattern a(...)b would be sufficient to take care of a b°a in the "wrong" place.) THX. $\endgroup$ Commented Jun 6, 2017 at 8:45
The following definitions give what you request. I use a definition of can1
(from Szabolcs) to canonicalise the order of the arguments.
SmallCircle[a___, SmallCircle[b___], c___] := SmallCircle[a, b, c]
can1 = RotateLeft[#, Ordering[#, 1] - 1] &;
SmallCircle[u__] /; First[Ordering[{u}, 1]] != 1 := SmallCircle @@ can1[{u}]
This gives
{((a∘b)∘c)∘d, b∘c∘d∘a, a∘c∘b∘d}
(* {a∘b∘c∘d, a∘b∘c∘d, a∘c∘b∘d} *)
Note that we can't use SetAttribute
Flat
as this effectively makes the operator commutative (it lets Mathematica permute any subsequence)
-
$\begingroup$
Flat
does not make the operator commutative. Maybe you're thinking ofOrderless
? $\endgroup$ Commented Jun 4, 2017 at 21:54 -
$\begingroup$ @CarlWoll quite correct. However, if I give
SmallCircle
the attributeFlat
(in conjunction with the 2nd definition) it becomes commutative (try it if you don't believe me). For this reason, I have to give a slightly weaker version of flattening in the 1st definition. $\endgroup$– mikadoCommented Jun 4, 2017 at 22:05 -
$\begingroup$ I see. That's because you use SmallCircle[u__] .. in your definition. I'll give an alternate answer that doesn't suffer from this issue. $\endgroup$ Commented Jun 4, 2017 at 22:12
Tr[A.B.C]
where the arguments are matrices. This is only defined for matrices whose sizes agree. With two arguments it is commutative, but with three or more, generally not. $\endgroup$Flat
. Just try to imagineTr[a,Tr[b,c]] == Tr[a,b,c]
. To define tensor trace fully consistent you will need two functions, say,tr
anddot
, wheredot
isFlat
andtr[dot[x__]]
is cyclic. How to implement such functions depends on what kind of patterns do you want to use. If you want to combinetr
anddot
in one symbol, you should not expect it to beFlat
. $\endgroup$