]> Bulk Actions and Binary Operators

Bulk Actions and Binary Operators

Here I document the ways I combine values with binary operators and their kin, alongside the symbols I use for various binary operators. See my discussion of symbols for why I use &…; tokens which don't work in any browser even where some browsers do support character entities which display as the orthodox symbol for the binary operator I'm discussing (roughly: even though some shall see ⊗ as an x embedded in the middle of an O, and some shall recognise this orthodox symbol, those who see it as ⊗ get no clue as to what it means, whereas &tensor; announces overtly that it's the tensor combiner, even though I've met no browser which supports &tensor; as a character entity). Allegedly, I can do clever things with DTDs and XML to make my own character entities work properly, but I haven't done it yet.

A binary operator combines two values to produce a value: a bulk action combines potentially many values to produce a value, but does so in some manner compatible with a binary operator. The value produced (in either case) may be ambiguous in the same sense that f(x) is an ambiguous value when f relates several of its left values to x (in which case f isn't a mapping; orthodox usage only allows the denotational form f(x) when f is a mapping, but I extend it so that f(x) denotes an arbitrary value which f relates to x; which will agree with orthodoxy when f is a mapping and there is only one such value for each x; likewise, x*y denotes an arbitrary value which * can produce when given x and y to combine).

An operand of a binary operator, *, is a value, x, for which at least one of x*y and y*x has at least one value for at least some value of y; a compound of a binary operator, *, is a value x*y may take for some operands, x and y, of *. The binary operator, *, associated with a bulk action, f, can always be expressed as a*b = f([a,b]).

A bulk action's right values (inputs) are canonically non-empty lists of operands of an associated binary operator; however, only some such lists may be acceptable. The empty list may also be allowed, as may be various other mappings (or even relations) whose left values (outputs) are operands. The bulk action associated with a binary operator * is bulk(*) – see the first entry below – though particular binary operators may extend this as appropriate (e.g. we can take the union of arbitrarily many relations, not just finitely many). Whenever a binary operator * has an identity (i.e. some e for which e*a = a = a*e for each *-operand, a), its associated bulk action can map empty (in any of its guises, empty list, empty mapping, etc.) to this identity without complications.

Because bulk actions definitively combine lists of values (a list being a mapping from some natural number; i.e. it relates exactly one left values to each member of that natural number) and the values thus combined are the entries in (i.e. left values of) the list, I make more general bulk actions combine the left values of the relations on which they act, even when there is no particular reason to attend to the special case of lists. A bulk action's left value (output) for a given relation as right value (input) is thus the associated binary operator's compound of the relation's left values (though these may be described as its outputs, entries, members or etc., according as it's a mapping, list, collection or etc.); I'll allow (though technically an abuse and nominally potentially confusing) that this compound may be referred to as the compound of the given relation itself; but this should not be thought of as the compound of the collection of the relation's left values – notice that the sum of a list with repeated entries, for instance, is different from the sum of the collection of the list's entries, since the latter doesn't preserve the repetition.

bulk
= (: (: bulk(*, (:f|n)) * bulk(*, (: f(n+i) ←i |m)) ← (:f|n+m) :{lists}) &unite; ({operands of *}: a ← [a] :) ← * :{binary operators})

The grand progenitor of bulk actions. The given formula says the same as bulk(*, [a,…,z]) = a*…*z but more formally: bulk(*) maps any list with one entry, provided that entry is an operand of *, to that one entry, bulk(*,[a]) = a; and, for any two lists to which bulk(*) gives values which * can combine, bulk(*) relates the resulting compound to the result of appending the two lists together, bulk(*,[a,…,m,n,…,z]) = bulk(*,[a,…,m])*bulk(*,[n,…,z]). Where * has an identity, e for which e*a = a = a*e for each operand a of *, bulk(*) naturally extends to allow bulk(*,[]) = e.

Note that ambiguity in bulk(*) can arise either from ambiguity in *, as should be obvious, or by virtue of a*(b*c) and (a*b)*c not always being equal (i.e. non-associativity of *).

compose = bulk(&on;)

Composition of relations – which is unambiguous. For any list [a,…,m] of relations, compose([a,…,m]) relates n to z precisely if a relates n to some value which … relates to some value which m relates to z. For any list h, compose(h) is known as the composite of h (or of its entries).

unite
= (: (: some left value of r relates x to y; x←y :) ← r :{relations})

which subsumes bulk(&unite;). For any relation h, unite(h) is known as the union of h. For any relations n and u, unite([n,u]) is known as the union of n and u and I'll write it n&unite;u (with any luck, &unite; is a centred shrunk sans-serif capital U; as which ∪ might also render).

intersect
= (: (: every left value of r relates x to y; x←y :) ← r :{relations})

which subsumes bulk(&intersect;). For any relation h, intersect(h) is known as the intersection of h.

Linear Algebra's polymorphic combiners

These involve lots of polymorphism: the types of their operands depend on context.

sum = bulk(+)

addition – a generic polymorphic combiner, always implicitly supposed abelian (i.e. a+b = b+a). Induces natural scaling via n.x = sum({x}:|n) giving the sum of n copies of x.

multiply = bulk(.)

scalar multiplication

product = bulk(×)

tensor multiplication

Tensor = bulk(⊗)

tensor-rank multiplication


Valid CSSValid XHTML 1.1 Written by Eddy.