# How to define a number of infix operators with predefined relative precedences

Reading a number of questions about infix operator notations I want to ask if somebody could reimplement the problem below in a simpler way, say modifying UnicodeCharacters.tr file?

In geometric (Clifford) algebra one uses three different product: inner (.), outer (^) and geometric (clifford) $\circ$. Lets assume that inner have highest precedence, then goes outer and geometric product precedence is lowest. Plus precedence is lower that any of products, and Times precedence is equal of geometric product itself.

My solution is as follows:

$GAPackageInputAliases = {};$GAInstallProperties = {WedgeFont -> "ArialUnicodeMSFontForAllOS"};
If[(WedgeFont /. $GAInstallProperties) === "ArialUnicodeMSFontForAllOS",$GAPackageInputAliases =
Join[$GAPackageInputAliases, {"ip" -> RowBox[{" ", "∙", " ", "\[SelectionPlaceholder]"}], "il" -> RowBox[{" ", StyleBox["⎦", FontFamily -> "Arial Unicode MS"], " ", "\[SelectionPlaceholder]"}], "ir" -> RowBox[{" ", StyleBox["⎣", FontFamily -> "Arial Unicode MS"], " ", "\[SelectionPlaceholder]"}], "op" -> RowBox[{" ", StyleBox["⋏", FontFamily -> "Arial Unicode MS"], " ", "\[SelectionPlaceholder]"}], "gp" -> RowBox[{" ", "\[EmptySmallCircle]", " ", "\[SelectionPlaceholder]"}]}];, If[$SystemID === "Windows", $GAPackageInputAliases = Join[$GAPackageInputAliases, {"ip" ->
RowBox[{" ", "∙", " ", "\[SelectionPlaceholder]"}],
"il" -> RowBox[{" ",
StyleBox["⎦", FontFamily -> "Arial Unicode MS"], " ",
"\[SelectionPlaceholder]"}],
"ir" ->
RowBox[{" ", StyleBox["⎣", FontFamily -> "Arial Unicode MS"],
" ", "\[SelectionPlaceholder]"}],
"op" -> RowBox[{" ",
StyleBox["⋏", FontFamily -> "Arial Unicode MS"], " ",
"\[SelectionPlaceholder]"}],
"gp" -> RowBox[{" ", "\[EmptySmallCircle]", " ",
"\[SelectionPlaceholder]"}]}],
$GAPackageInputAliases = Join[$GAPackageInputAliases, {"ip" ->
RowBox[{" ", "∙", " ", "\[SelectionPlaceholder]"}],
"il" -> RowBox[{" ", "⎦", " ", "\[SelectionPlaceholder]"}],
"ir" -> RowBox[{" ", "⎣", " ", "\[SelectionPlaceholder]"}],
"op" -> RowBox[{" ", "⋏", " ", "\[SelectionPlaceholder]"}],
"gp" -> RowBox[{" ", "\[EmptySmallCircle]", " ",
"\[SelectionPlaceholder]"}]}]]];
SetOptions[System$FrontEndSession, InputAliases -> Join[CurrentValue[System$FrontEndSession,
InputAliases], $GAPackageInputAliases]]; MakeExpression[y_String, StandardForm] := MakeExpression[ StringReplace[ y, {"∙" -> "\[CircleDot]", "⎦" -> "\[Vee]", "⎣" -> "\[Wedge]"}], StandardForm] /; ! StringFreeQ[y, {"∙", "⎦", "⎣"}] MakeExpression[RowBox[{x___, y_String, w___}], StandardForm] := MakeExpression[ RowBox[{x, StringReplace[ y, {"∙" -> "\[CircleDot]", "⎦" -> "\[Vee]", "⎣" -> "\[Wedge]"}], w}], StandardForm] /; ! StringFreeQ[StringJoin[{y}], {"∙", "⎦", "⎣"}] MakeExpression[y_RowBox | _StyleBox, StandardForm] := MakeExpression[ ReplaceAll[ y, {StyleBox["⎦", FontFamily -> "Arial Unicode MS"] -> "\[Vee]", StyleBox["⎣", FontFamily -> "Arial Unicode MS"] -> "\[Wedge]"}], StandardForm] /; (! FreeQ[y, StyleBox["⎦", FontFamily -> "Arial Unicode MS"], Infinity]) || (! FreeQ[y, StyleBox["⎣", FontFamily -> "Arial Unicode MS"], Infinity]) MakeExpression[y_RowBox | _StyleBox, StandardForm] := MakeExpression[ ReplaceAll[ y, {StyleBox["⋏", FontFamily -> "Arial Unicode MS"] -> "\[CircleTimes]"}], StandardForm] /; ! FreeQ[y, StyleBox["⋏", FontFamily -> "Arial Unicode MS"], Infinity] MakeExpression[y_String, StandardForm] := MakeExpression[StringReplace[y, {"⋏" -> "\[CircleTimes]"}], StandardForm] /; ! StringFreeQ[y, "⋏"] MakeExpression[RowBox[{x___, y_String, w___}], StandardForm] := MakeExpression[ RowBox[{x, StringReplace[y, {"⋏" -> "\[CircleTimes]"}], w}], StandardForm] /; ! StringFreeQ[StringJoin[{y}], "⋏"] MakeExpression[y_String, StandardForm] := MakeExpression[ StringReplace[y, {"\[EmptySmallCircle]" -> "\[CirclePlus]"}], StandardForm] /; ! StringFreeQ[y, "\[EmptySmallCircle]"] MakeExpression[RowBox[{x___, y_String, w___}], StandardForm] := MakeExpression[ RowBox[{x, StringReplace[y, {"\[EmptySmallCircle]" -> "\[CirclePlus]"}], w}], StandardForm] /; ! StringFreeQ[StringJoin[{y}], "\[EmptySmallCircle]"] CirclePlus = GeometricProduct; GP = GeometricProduct; CircleTimes = OuterProduct; OP = OuterProduct; Vee = LeftContract; LC = LeftContract; Wedge = RightContract; RC = RightContract; CircleDot = InnerProduct; IP = InnerProduct; Protect[CirclePlus, CircleTimes, Vee, Wedge, CircleDot]; MakeBoxes[InnerProduct[y_], StandardForm] := MakeBoxes[y] /; ! MemberQ[{RightContract, LeftContract, OuterProduct, GeometricProduct, Plus}, Head[y]] MakeBoxes[InnerProduct[y_], StandardForm] := RowBox[{"(", MakeBoxes[y], ")"}] /; MemberQ[{RightContract, LeftContract, OuterProduct, GeometricProduct, Plus}, Head[y]] MakeBoxes[RightContract[y_], StandardForm] := MakeBoxes[y] /; ! MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[y]] MakeBoxes[RightContract[y_], StandardForm] := RowBox[{"(", MakeBoxes[y], ")"}] /; MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[y]] MakeBoxes[LeftContract[y_], StandardForm] := MakeBoxes[y] /; ! MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[y]] MakeBoxes[LeftContract[y_], StandardForm] := RowBox[{"(", MakeBoxes[y], ")"}] /; MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[y]] MakeBoxes[OuterProduct[y_], StandardForm] := MakeBoxes[y] /; ! MemberQ[{GeometricProduct, Plus}, Head[y]] MakeBoxes[OuterProduct[y_], StandardForm] := RowBox[{"(", MakeBoxes[y], ")"}] /; MemberQ[{GeometricProduct, Plus}, Head[y]] MakeBoxes[GeometricProduct[y_], StandardForm] := MakeBoxes[y] /; Head[y] =!= Plus MakeBoxes[GeometricProduct[y_], StandardForm] := RowBox[{"(", MakeBoxes[y], ")"}] /; Head[y] === Plus MakeBoxes[InnerProduct[x_, y__], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[x], "∙", MakeBoxes[InnerProduct[y]]}]]}] /; ! MemberQ[{RightContract, LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]] MakeBoxes[InnerProduct[x_, y__], StandardForm] := RowBox[Flatten[{"(", MakeBoxes[x], ")", "∙", MakeBoxes[InnerProduct[y]]}]] /; MemberQ[{RightContract, LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]] MakeBoxes[InnerProduct[y__, x_], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[InnerProduct[y]], "∙", MakeBoxes[x]}]]}] /; ! MemberQ[{RightContract, LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]] MakeBoxes[InnerProduct[y__, x_], StandardForm] := RowBox[Flatten[{MakeBoxes[InnerProduct[y]], "∙", "(", MakeBoxes[x], ")"}]] /; MemberQ[{RightContract, LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]] If[(WedgeFont /.$GAInstallProperties) ===
"UseArialUnicodeMSFontForAllOS" || $SystemID === "Windows", MakeBoxes[RightContract[x_, y__], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[x], StyleBox["⎣", FontFamily -> "Arial Unicode MS"], MakeBoxes[RightContract[y]]}]]}] /; ! MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[RightContract[x_, y__], StandardForm] := RowBox[Flatten[{"(", MakeBoxes[x], ")", StyleBox["⎣", FontFamily -> "Arial Unicode MS"], MakeBoxes[RightContract[y]]}]] /; MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[RightContract[y__, x_], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[RightContract[y]], StyleBox["⎣", FontFamily -> "Arial Unicode MS"], MakeBoxes[x]}]]}] /; ! MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[RightContract[y__, x_], StandardForm] := RowBox[Flatten[{MakeBoxes[RightContract[y]], StyleBox["⎣", FontFamily -> "Arial Unicode MS"], "(", MakeBoxes[x], ")"}]] /; MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]];, MakeBoxes[RightContract[x_, y__], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[x], "⎣", MakeBoxes[RightContract[y]]}]]}] /; ! MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[RightContract[x_, y__], StandardForm] := RowBox[Flatten[{"(", MakeBoxes[x], ")", "⎣", MakeBoxes[RightContract[y]]}]] /; MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[RightContract[y__, x_], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[RightContract[y]], "⎣", MakeBoxes[x]}]]}] /; ! MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[RightContract[y__, x_], StandardForm] := RowBox[Flatten[{MakeBoxes[RightContract[y]], "⎣", "(", MakeBoxes[x], ")"}]] /; MemberQ[{LeftContract, OuterProduct, GeometricProduct, Plus}, Head[x]];] If[(WedgeFont /.$GAInstallProperties) ===
"UseArialUnicodeMSFontForAllOS" || $SystemID === "Windows", MakeBoxes[LeftContract[x_, y__], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[x], StyleBox["⎦", FontFamily -> "Arial Unicode MS"], MakeBoxes[LeftContract[y]]}]]}] /; ! MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[LeftContract[x_, y__], StandardForm] := RowBox[Flatten[{"(", MakeBoxes[x], ")", StyleBox["⎦", FontFamily -> "Arial Unicode MS"], MakeBoxes[LeftContract[y]]}]] /; MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[LeftContract[y__, x_], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[LeftContract[y]], StyleBox["⎦", FontFamily -> "Arial Unicode MS"], MakeBoxes[x]}]]}] /; ! MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[LeftContract[y__, x_], StandardForm] := RowBox[Flatten[{MakeBoxes[LeftContract[y]], StyleBox["⎦", FontFamily -> "Arial Unicode MS"], "(", MakeBoxes[x], ")"}]] /; MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[x]];, MakeBoxes[LeftContract[x_, y__], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[x], "⎦", MakeBoxes[LeftContract[y]]}]]}] /; ! MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[LeftContract[x_, y__], StandardForm] := RowBox[Flatten[{"(", MakeBoxes[x], ")", "⎦", MakeBoxes[LeftContract[y]]}]] /; MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[LeftContract[y__, x_], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[LeftContract[y]], "⎦", MakeBoxes[x]}]]}] /; ! MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[x]]; MakeBoxes[LeftContract[y__, x_], StandardForm] := RowBox[Flatten[{MakeBoxes[LeftContract[y]], "⎦", "(", MakeBoxes[x], ")"}]] /; MemberQ[{OuterProduct, GeometricProduct, Plus}, Head[x]];] If[(WedgeFont /.$GAInstallProperties) ===
"UseArialUnicodeMSFontForAllOS" || $SystemID === "Windows", MakeBoxes[OuterProduct[x_, y__], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[x], StyleBox["⋏", FontFamily -> "Arial Unicode MS"], MakeBoxes[OuterProduct[y]]}]]}] /; ! MemberQ[{GeometricProduct, Plus}, Head[x]]; MakeBoxes[OuterProduct[x_, y__], StandardForm] := RowBox[Flatten[{"(", MakeBoxes[x], ")", StyleBox["⋏", FontFamily -> "Arial Unicode MS"], MakeBoxes[OuterProduct[y]]}]] /; MemberQ[{GeometricProduct, Plus}, Head[x]]; MakeBoxes[OuterProduct[y__, x_], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[OuterProduct[y]], StyleBox["⋏", FontFamily -> "Arial Unicode MS"], MakeBoxes[x]}]]}] /; ! MemberQ[{GeometricProduct, Plus}, Head[x]]; MakeBoxes[OuterProduct[y__, x_], StandardForm] := RowBox[Flatten[{MakeBoxes[OuterProduct[y]], StyleBox["⋏", FontFamily -> "Arial Unicode MS"], "(", MakeBoxes[x], ")"}]] /; MemberQ[{GeometricProduct, Plus}, Head[x]];, MakeBoxes[OuterProduct[x_, y__], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[x], "⋏", MakeBoxes[OuterProduct[y]]}]]}] /; ! MemberQ[{GeometricProduct, Plus}, Head[x]]; MakeBoxes[OuterProduct[x_, y__], StandardForm] := RowBox[Flatten[{"(", MakeBoxes[x], ")", "⋏", MakeBoxes[OuterProduct[y]]}]] /; MemberQ[{GeometricProduct, Plus}, Head[x]]; MakeBoxes[OuterProduct[y__, x_], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[OuterProduct[y]], "⋏", MakeBoxes[x]}]]}] /; ! MemberQ[{GeometricProduct, Plus}, Head[x]]; MakeBoxes[OuterProduct[y__, x_], StandardForm] := RowBox[Flatten[{MakeBoxes[OuterProduct[y]], "⋏", "(", MakeBoxes[x], ")"}]] /; MemberQ[{GeometricProduct, Plus}, Head[x]];] MakeBoxes[GeometricProduct[x_, y__], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[x], "\[EmptySmallCircle]", MakeBoxes[GeometricProduct[y]]}]]}] /; Head[x] =!= Plus MakeBoxes[GeometricProduct[x_, y__], StandardForm] := RowBox[Flatten[{"(", MakeBoxes[x], ")", "\[EmptySmallCircle]", MakeBoxes[GeometricProduct[y]]}]] /; Head[x] === Plus MakeBoxes[GeometricProduct[y__, x_], StandardForm] := RowBox[{RowBox[ Flatten[{MakeBoxes[GeometricProduct[y]], "\[EmptySmallCircle]", MakeBoxes[x]}]]}] /; Head[x] =!= Plus MakeBoxes[GeometricProduct[y__, x_], StandardForm] := RowBox[Flatten[{MakeBoxes[GeometricProduct[y]], "\[EmptySmallCircle]", "(", MakeBoxes[x], ")"}]] /; Head[x] === Plus  Code above is just proper opration notation with needed preferences. (no realization included). As a simple test can try this: aa\[EmptySmallCircle] (f ⋏ D[a[x], x]) ∙ b \[EmptySmallCircle] c \[EmptySmallCircle] g // FullForm  GeometricProduct[aa, InnerProduct[OuterProduct[f, Derivative[1][a][x]], b], c, g] or 1/(f ⋏ a ∙ b \[EmptySmallCircle] c \[EmptySmallCircle] g) // FullForm  GeometricProduct[OuterProduct[f, InnerProduct[a, b]], c, g]^(-1) • I started on this but I too ran into a problem with the operator precedence specified in UnicodeCharacters.tr. I'll try to find a solution but it may be that the values are simply not respected. Aug 3, 2015 at 1:28 • Are you using a 3rd party package? If yes, which one? Aug 3, 2015 at 22:47 • No. I am trying to write it myself. – Acus Aug 4, 2015 at 15:02 ## 2 Answers I did not attempt to implement everything you show but only what is needed for the two final examples. I initially seemed to have a problem with precedence but now it is working? I am not certain of what change made the difference, if any, but I'll post what I have now in case it is special in some way. I added these lines at the top of UnicodeCharacters.tr 0x25E6 \[GeometricProduct] ($gp$) Infix 430 None 5 5 0x22CF \[OuterProduct] ($op$) Infix 440 None 5 5 0x2219 \[InnerProduct] ($ip$) Infix 450 None 5 5  And made these definitions: MakeExpression[RowBox[x : {_, PatternSequence["\[InnerProduct]", _] ..}], sf : StandardForm] := MakeExpression[RowBox[{"InnerProduct", "[", ##, "]"}] & @@ Riffle[x[[;; ;; 2]], ","], sf] MakeExpression[RowBox[x : {_, PatternSequence["\[OuterProduct]", _] ..}], sf : StandardForm] := MakeExpression[RowBox[{"OuterProduct", "[", ##, "]"}] & @@ Riffle[x[[;; ;; 2]], ","], sf] MakeExpression[RowBox[x : {_, PatternSequence["\[EmptySmallCircle]", _] ..}], sf : StandardForm] := MakeExpression[RowBox[{"GeometricProduct", "[", ##, "]"}] & @@ Riffle[x[[;; ;; 2]], ","], sf]  Now I have this behavior: aa ◦ (f ⋏ D[a[x], x]) ∙ b ◦ c ◦ g // FullForm 1/(f ⋏ a ∙ b ◦ c ◦ g) // FullForm  GeometricProduct[aa, InnerProduct[OuterProduct[f, Derivative[1][a][x]], b], c, g] Power[GeometricProduct[OuterProduct[f, InnerProduct[a, b]], c, g], -1]  ### Update Code above adjusted to handle also this example: (1/f)∙a∙b◦c◦g === 1/f∙a∙b◦c◦g === GeometricProduct[InnerProduct[f^(-1),a,b],c,g]  True  • In most cases it seems to work. Still I found one case: (1/f) \[InnerProduct] a \[InnerProduct] b \[EmptySmallCircle] c \[EmptySmallCircle] g === 1/f \[InnerProduct] a \[InnerProduct] b \[EmptySmallCircle] c \[EmptySmallCircle] g === GeometricProduct[InnerProduct[f^(-1), a, b], c, g] where it fails. The problem is slightly complicated by the fact that these new operators are noncommuting quantities, so to make sure it will always work I need to add some implementation code. I would prefer this solution, because it allows to avoid empty space symbols aroud product operators. – Acus Aug 3, 2015 at 9:08 • @user18792 Please try the updated code. Aug 3, 2015 at 22:17 • I am accepting that approach. Strange, that initially I myself tried to implement the functionality by modifying (adding similar rules to the end) UnicodeCharacter.tr, however, without success. I think I will make a fork in my code and explore it further. Thanks. – Acus Aug 4, 2015 at 17:18 • @user18792 Thank you. Please let me know what you discover. Aug 4, 2015 at 18:21 • Just posted full working package on the github (the link below in self answer, which is based on your suggestions. Seems now I can claim that one can indeed adjust precedences for rather complicated cases. – Acus Sep 20, 2016 at 11:36 This should be a comment, however it is too large. The following contend appended to UnicodeCharacters.tr file (* Geometric algebra additions *) 0x26AC \[GeometricProduct] ($gp$) Infix 440 None 5 5 0x22CE \[OuterProduct] ($op$) Infix 450 None 5 5 (* if instead of wedge you see vee symbol replace 0x22CE by 0x22CF *) 0x26ab \[DorstProduct] ($id$) Infix 459 None 5 5 0x2219 \[InnerProduct] ($ip$) Infix 460 None 5 5 0x23A6 \[LeftContract] ($il$) Infix 461 None 5 5 0x23A3 \[RightContract] ($ir\$)      Infix       462 None    5   5


will ensure the following operator precedence ordering (presented in the context of other Mma operators):

• NonCommutativeMultiply (**, highest)

• Times (*, Space)

• RightContract ([RightContract])

• LeftContract ([LeftContract])

• InnerProduct ([InnerProduct])

• DorstProduct ([DorstProduct])

• OuterProduct ([OuterProduct] (bad representation in text cells in linux, as was noted above, input cells are ok., depends on what font is used)

• GeometricProduct([GeometricProduct])

• Plus (lowest)

Note: geometric product will not work correctly if 440 is replaced by 430. Also 540 ... precedences was tested and should be avoided.

If someone wants to test the behavior more carefully I just put the package on the github: https://github.com/ArturasAcus/GeometricAlgebra