]>
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.
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 *).
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).
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).
which subsumes bulk(&intersect;). For any relation h, intersect(h) is
known as the intersection
of h.
These involve lots of polymorphism: the types of their operands depend on context.
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.
scalar multiplication
tensor multiplication
tensor-rank multiplication