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)?

  • 3
    $\begingroup$ If I define $e=b \circ c \circ d$ then you propose $a \circ e \neq e \circ a$, but on the other hand you say $a \circ (b \circ c \circ d) = a \circ b \circ c \circ d = b \circ c \circ d \circ a = (b \circ c \circ d) \circ a = e \circ a$. If $\circ$ is flat and cyclic then mustn't $a \circ e = e \circ a$...? $\endgroup$ Commented Jun 4, 2017 at 19:04
  • $\begingroup$ @MariusLadegårdMeyer, I think that a non-commutative "operator" with the requested properties could be 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$
    – mikado
    Commented Jun 4, 2017 at 19:16
  • $\begingroup$ Yes, it's indeed a tensor trace in "reality". $\endgroup$ Commented Jun 5, 2017 at 10:41
  • $\begingroup$ Somewhat related: (17041), (55702) $\endgroup$
    – Mr.Wizard
    Commented Jun 6, 2017 at 0:03
  • 1
    $\begingroup$ Tensor trace cannot be Flat. Just try to imagine Tr[a,Tr[b,c]] == Tr[a,b,c]. To define tensor trace fully consistent you will need two functions, say, tr and dot, where dot is Flat and tr[dot[x__]] is cyclic. How to implement such functions depends on what kind of patterns do you want to use. If you want to combine tr and dot in one symbol, you should not expect it to be Flat. $\endgroup$
    – Ray Shadow
    Commented Jun 6, 2017 at 6:36

2 Answers 2


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:


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




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



  • $\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$ @HaukeReddmann See edit $\endgroup$
    – Carl Woll
    Commented Jun 5, 2017 at 22:49
  • $\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 of Orderless? $\endgroup$
    – Carl Woll
    Commented Jun 4, 2017 at 21:54
  • $\begingroup$ @CarlWoll quite correct. However, if I give SmallCircle the attribute Flat (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$
    – mikado
    Commented 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$
    – Carl Woll
    Commented Jun 4, 2017 at 22:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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