Antisymmetric Differentiation

A differential operator on a smooth manifold is a Leibniz operator which coincides with the primitive gradient operator on scalar fields, and for which the derivative of the gradient of a scalar field is everywhere symmetric. Any two differential operators differ by a linear map on each rank of the smooth manifold's tensor bundle. Take G and T to be the mutually dual ranks of tensor which represent gradient- and tangent-valued fields.

Each rank of the tensor bundle is characterized by a list, each entry in which is either G or T: this is a mapping ({G,T}:F|n) = [F(0),…,F(n−1)], with each F(i) in {G,T}, for some natural n, known as the length of F; the rank is obtained by combining the entries in the list using the ⊗ binary operator, which combines linear spaces; tensor(F) = bulk(⊗, F) = F(0)⊗…⊗F(n−1); a typical member of U⊗…⊗W would be a sum of terms, each of form u×…×w with u in U, … and w in W; in which × is a bilinear operator – and that'd better be enough of the underpinning of tensor algebra for here.

For any list, [U,…,W], of linear spaces we can permute the entries in the list, shuffling their order: for each such permutation, there is a linear map from the original list's rank to the permuted list's rank; in general, if the entries in the list aren't all the same and the permutation replaces some entry with a different space, the output of this linear map has different rank from the input. Example: given u and v in U, the permutation [1,0] = (: 0←1, 1←0 :) acts on U⊗U in a way which maps u×v to v×u; in general, a permutation (n|s|n) maps any rank, tensor(:F|n) = F(0)⊗…⊗F(n−1), via the composite F&on;s = [F(s(0)), …, F(s(n−1))], to the permuted rank F(s(0))⊗…⊗F(s(n−1)); each member of tensor(F) is a sum of terms, each of form bulk(×, (:f|n)) = f(0)×…×f(n−1) with f(i) in F(i) for each i; even when F(2) and F(7), say, are the same linear space, f(2) and f(7) may be distinct members of that space; so, even when a permutation only interchanges identical entries in the list of spaces, the way it interchanges members of a space distinguishes the permutation operator from the identity. We can add permutation operators in so far as we accept that the sum is restricted to only act on ranks for which the two permutation operators produce the same rank as output, albeit permuted in each case; we can also scale them. By averaging all the permutations which preserve a given rank, one can obtain a symmetrization operator for that rank. I'll use τ(r) as the operator associated with permutation r;

• τ = (: unite(: (: bulk(×, (U:f&on;r|n)) ← bulk(×, (U:f|n)) :tensor({U}:|n)) ← U |{linear spaces}) ← (n|s|n) |{permutations})

Manifestly, τ(r)&on;τ(s) = τ(r&on;s) for any two permutations, r and s.

Permutations also have a property called signature: this says whether one needs an odd or even number of transpositions to build up the permutation as a product of transpositions; it is +1 for a product of an even number of transpositions, −1 for odd. Composing two permutations, the result's signature is obtained by multiplying the signatures of the two permutations composed; signature is formally a mapping, sign, from a group of permutations to the group {+1,−1} under multiplication – i.e. (: (: +1← +1, −1← −1 :)← +1, (: +1← −1, −1← +1 :)← −1 :) – and the mapping respects the group structure while mapping equally many permutations to each of +1 and −1. If we multiply each permutation operator that preserves a given rank by the signature of the corresponding permutation, we can again average the results: the result is a natural antisymmetrization operator for the rank.

Some ranks only use G in their list, so are of form tensor({G}:|n), the only free variable being the length of the list. If we apply our differential operator to one such rank, the output is another rank of the same form: it just has one more G in the list. Every permutation (n||n) preserves the rank tensor({G}:|n), so the natural symmetrization and antisymmetrization operators for G-only ranks involve sums over all permutations of n. I'll use the name wedge for the antisymmetrization operator, leaving 'til later the details of an overall scaling on it to make various sensible things work out right.

• wedge = unite(:
sum(: sign(s).τ(s) ←s :{permutations of n})/K(n)
←n |{naturals}),

for some (:K:{naturals}); to make the sum an average over all permutations, we should make K(n) the number of permutations of n, which is n!, a.k.a. factorial(n), defined by 0! = 1, (1+n)! = n!.(1+n), so yielding the sequence [1,1,2,6,24,120,720,…]. Since the same choice will, in fact, make wedge&on;wedge = wedge, I'll duly use K(n) = n!.

Composing wedge before or after a permutation operator, τ(r), which only interchanges tensor ranks to which wedge has applied itself, sign(s).τ(s) in wedge's definition becomes sign(s).τ(s&on;r) and sign(s&on;r).sign(r) is sign(s), giving sign(r).sign(s&on;r).τ(s&on;r). Now, we're averaging this over all permutations (n|s|n) for some fixed r; composing each s after r simply re-shuffles the order in which we sum over all permutations; aside from an over-all shared factor of sign(r), our sum(::)/K of sign(s&on;r).τ(s&on;r) is the sum(::)/K of sign(s).τ(s), i.e. wedge; hence wedge&on;τ(r) = sign(r).wedge. By an entirely analogous argument, τ(r)&on;wedge = sign(r).wedge.

In particular, wedge&on;wedge is a sum(::)/K of terms, each of form sign(r).wedge&on;τ(r) = sign(r).sign(r).wedge = wedge since sign(r), being either +1 or −1, is self-inverse. Thus wedge&on;wedge is just wedge times a scaling: the number of permutations of [0,…,n−1], divided by K(n); naturally, we chose to make K(n) be the number of permutations, so that wedge&on;wedge = wedge. This, in turn, lets us replace sum(::)/K with average(::):

• wedge = unite(: average(: sign(s).τ(s) ←s :{permutations of n}) ←n |{naturals})
• wedge&on;wedge = wedge, wedge&on;τ(r) = sign(r).wedge = τ(r)&on;wedge.

The typical member of tensor({G}:|n) is a sum of terms each of which is bulk(×, (G:f|n)), for some list, f, of gradient fields; all linear actions are defined by their action on such terms (as above for wedge on each rank) and inferred on sums of such terms by linear extension, i.e. by defining the action on a sum to be the sum of the action on each term in the original sum. Now, suppose we have a linear dependence among the entries in our list; i.e. there is some i in n for which f(i) is sum(k.f) for some ({scalars}: k :n) with i not in (:k|), i.e. there's no k(i).f(i) term in the sum(k.f) = sum(: k(i).f(i) ←i :{i: i in (:f|) and i in (:g|)}). When we apply bulk(×) to f, we get f(0)×…×f(n−1) and can substitute sum(k.f) in place of f(i) where it appears; as × distributes over addition, we can re-arrange the result as a sum of terms, each of form k(j).f(0)×…×f(n−1) but with f(i) replaced by f(j); since i isn't in (:k|), j isn't i so f(j) already appeared in the term before we replaced f(i) with it; f(j) appears twice. There is a permutation which swaps i and j, acting as the identity on all other members of n; this has signature −1 (it's a transposition); composing permutations with it, it provides a one-to-one correspondence between permutations with signatures −1 and +1; so we can decompose wedge(: :tensor({G}:|n))'s sum over permutations of n into a sum of two sums, one over the even permutations, ({−1}:sign|), the other over the odd ones, ({+1}:sign|); then write each odd permutation as the i/j swap composed after an even one; this has the same effect on our term with f(j) in both positions as the even permutation in question, but the opposite signature; so we can match up terms in the two sub-sums, getting the same permuted value in each pair, but one positive the other negative; hence we can conclude that the term in bulk(×,f)'s expansion, using f(j) in place of f(i), is mapped to zero by wedge; linear dependence in f allows us to write it as a sum of terms each of which wedge maps to zero, wedge must in fact map bulk(×,f) to zero: wedge annihilates linear dependencies. Consequently, indeed, if G has finite dimension, (| wedge :tensor({G}:|n)) will be {zero} of suitable rank for n greater than G's dimension.

Now consider what happens when we combine wedge and D on tensor({G}:|n): we'll get (tensor({G}:|1+n): wedge&on;D :tensor({G}:|n)) respecting addition and mapping a typical member of tensor({G}:|n), u×…×w, to a sum of terms, each of which replaces one of u, …, w with D(u), … or D(w), but then applies a permutation operator to the result, along with a scaling involving the signature of the permutation. Because of the antisymmetrization, if any D(u) is symmetric, and we're passing the result to wedge, the terms in D(u) cancel one another out.

Around any location on the smooth manifold one can find a neighbourhood in which one can define smoothly-varying scalar fields – called coordinates – whose gradients are linearly independent but span the space of gradients – i.e. form a basis of G. Express the scalar fields as a list ({scalar fields}:x|dim(G)), yielding gradients (G:dx|dim(G)) providing a basis of G. This enables us, within our neighbourhood, to write an arbitrary tensor({G}:|n) field as a sum of terms, each having the form a.dx(s(0))×…×dx(s(n−1)) for some (dim(G):s|n) and scalar field a – the bulk(×, dx&on;s) provide a basis for tensor({G}:|n) throughout our neighbourhood. Now x&on;s provides a list of n scalar fields and we can write our typical term as a.du×…×dw for some list [u,…,w] of n scalar fields. Applying D to this, we obtain D(a)×du×…×dw plus a sum of terms, each involving D(du), … or D(dw), which the definition of a differential operator says will be symmetric, so annihilated by wedge. Since a was also a scalar field, like u, …, w, we have D(a) = da, so wedge&on;D maps a.du×…×w to wedge(da×du×…×dw).

Now, if a were constant, da would be zero, so a.du would be d(a.u) and wedge&on;D would annihilate a.du×…×w; so wedge&on;D annihilates any (finite) sum of outputs of (: bulk(×)&on;d&on;f ← f :{lists of scalar fields}); including, in particular, every output of wedge&on;D. At the same time, for any u = bulk(×, (G:f|n)), we have wedge(u): can wedge&on;D distinguish between u and wedge(u) ? We're looking at (: wedge&on;D&on;wedge :tensor({G}:|n)) and D(wedge) is zero (each permutation operator is a constant tensor operator, wedge applies a constant scaling to each and adds the results; so wedge is also constant); it's a sum of terms, each of which is of form sign(s).sign(r).τ(s)&on;D&on;τ(r)/K(n)/K(1+n) with (n|r|n) and (1+n|s|1+n) permutations, τ the mapping from permutations to permutation operators (well, τ will also accept other things than permutations, to do with tracing, but leave that for now) and K giving the the rank-dependent scaling of wedge. Now each of τ's outputs is constant: so, for a given u = bulk(×, (G:f|n)), D&on;τ(r) maps u to the result of performing, on D(u), the permutation corresponding to r but now applied to lists with one more entry, corresponding to D's contribution to rank, which doesn't participate in the permutations, the rest of the list being permuted by r; so D&on;τ(r) is τ(: 0←0, 1+r(i)←1+i :1+n)&on;D. We thus obtain τ(s)&on;D&on;τ(r) as τ(s&on;(: 0<0, 1+r(i)←1+i :1+n))&on;D by combining the two permutations once both are to the left of D. The stretched form of r has the same signature as r, hence the composite's signature is sign(s).sign(r). Thus sign(r).sign(s).τ(s)&on;D&on;τ(r) is just sign(q).τ(q) with q = s&on;(: 0←0, 1+r(i)←1+i :). Now, for fixed r, every permutation (1+n||1+n) may be obtained as q for some choice of s; for contrast, given s and q we can only chose an r for which it works if q(0) = s(0), but for given q and r there's always a suitable s. Thus each permutation (n|r|n) yields, in the sum of terms making up wedge&on;D&on;wedge's restriction to tensor({G}:|n), 1/K(n) times the sum which makes up wedge&on;D's restriction to the same domain; so wedge&on;D&on;wedge = n!/K(n).wedge&on;D and it makes sense to chose K(n) = n!, the number of permutations of n, computable from 0! = 1, (1+i)! = i!.(1+i), yielding the sequence [1,1,2,6,24,120,…]; so really we are averaging, i.e. summing over permutations then dividing by the number of permutations.

With this choice of scaling, wedge&on;D&on;wedge = wedge&on;D; in particular, composing wedge&on;D with itself yields wedge&on;D&on;D; indeed, bulk(&on;, ({wedge&on;D}:|n)) = wedge&on;bulk(&on;, ({D}:|n)) for any natural n. Since we know wedge&on;D annihilates all its outputs, composing it with itself yields the tensor operator (tensor({G}:|2+n): d0×d0×u ← u :tensor({G}:|n)) which yields a zero of rank G⊗G higher than the rank of its input (any constant scalar field, k, could have been used in place of 0 to give dk in place of d0, but 0 is perfectly good constant scalar field, hence d0 is a zero gradient). Thus wedge&on;D&on;D maps every G-only rank of tensor to the zero with two more Gs in its rank.

In particular, wedge&on;D = wedge&on;D&on;wedge tells us that any tensor field which is symmetric under (i.e. a fixed point of) any odd permutation's operator will be annihilated by wedge&on;D. Meanwhile wedge&on;D annihilates its outputs, all of which are sums of terms of form wedge(bulk(×, (: da(i) ←i |n)) for some list, [a(0),…,a(n−1)], of scalar fields.

Valid CSS ? Valid HTML ? Written by Eddy.