# Skew-symmetric function

I have a simple question:

1) I defined a skew symmetric function this way

 M[i_,j_]/;i>j:=-M[j,i];
M[i_,i_]:=0;


this is of course the most general skew symmetric function in two variable.

2) in the second part of the code I need to really define entrance by entrance: here I find some problem

a) if I do

M[1,2]:= a


it automatically gives the correct answer for M[2,1], -a b) but if I define M[2,1]:= -a of course it cannot write me M[1,2]. I know why this happens, but I want to find an elegant solution to define the element of my matrix as i like, I would like to set M[2,1] and get mathematica give me the correct answer when I ask for M[1,2]

Can you provide me an elegant solution?

• Why not use SymmetrizedArray[] with the Antisymmetric[] symmetry mode? Commented Jan 25, 2017 at 21:16
• An exemplary application of what J.M. suggested is shown here for a 7-dimensional vector cross product. Commented Jan 25, 2017 at 21:58
• I see, but in my case I cannot use matrices since I have to use functions (I'm dealing with commutator on Hilbert spaces). I would like to find a solution in terms of functions
– MaPo
Commented Jan 26, 2017 at 0:18

I'm not sure if this is relevant for particular use case of OP, but we can force M to normalize itself to canonical order, for arbitrary symbolic arguments, by using OrderedQ@{j, i} instead of i>j in the Condition.

I also like yohbs idea of overriding Set... functions, but I'd use a "softer" overriding method by using UpValues.

Putting it together:

declareAntisymmetric // ClearAll
declareAntisymmetric@sym_Symbol := Module[{inside},
sym[i_, i_] = 0;
sym[i_, j_] /; OrderedQ@{j, i} := -sym[j, i];
sym /: (set : Set | SetDelayed /; Not@TrueQ@inside)[sym[i_, j_], val_] :=
Block[{inside = True},
set[sym[j, i], -val];
set[sym[i, j], val]
]
]


Alternatively, if you prefer not to have pairs of DownValues as created by above function, but at the expense of potential swapping overhead at each call to your antisymmetric function. You can use something like following:

declareAntisymmetric // ClearAll
declareAntisymmetric@sym_Symbol := Module[{swapped},
sym[i_, i_] = 0;
sym[i_, j_] /; OrderedQ@{i, j} && Not@TrueQ@swapped :=
Block[{swapped = True}, -sym[j, i]];
sym[i_, j_] /; OrderedQ@{j, i} := -sym[j, i]
]


In above, function declared as antisymmetric can swap arguments from ordered to unordered and from unordered to ordered, but the former swap can be performed only once per function call. This version is based on answer to "Assign value to an odd function" post, by Simon Rochester.

Both above declareAntisymmetric functions give the same outputs in following code.

You can declare M to be antisymmetric and define specific values:

M // ClearAll
M // declareAntisymmetric
M[2, 1] = a;
M[3, j_] := 2 j - 6


Which gives expected result for arbitrary mixture of symbolic and numeric arguments:

M[1, 2] (* -a *)
M[3, y] (* -6 + 2 y *)
M[x, 3] (* 6 - 2 x *)
3 M[a, b] + M[b, a] (* 2 M[a, b] *)


You can redefine Set and SetDelayed for this particular variable:

Unprotect[SetDelayed];
Unprotect[Set];
Set[M[i_, j_] /; i > j, val_] := Set[M[j, i], -val];
Protect[SetDelayed];
Protect[Set];


And then it seems to work:

• "You can redefine Set and SetDelayed" - a dangerous tack in general, tho. Commented Jan 26, 2017 at 5:14
• @J.M. That's why I wrote "can" and not "should"... Commented Jan 26, 2017 at 5:25