# Bilinear Dot Function

In mathematics the matrix product is a bilinear operation $$\alpha A \cdot(\beta B + \gamma C) = \alpha\beta ( A \cdot B )+ \alpha \gamma (A\cdot C ),$$ where capital letters denote matrices and greek letters scalars.

Therefore $$A \cdot B + A\cdot (-B) = 0.$$

But it seems this relation is not implemented in Mathematicas Dot function, especially

Dot[a,b]+Dot[a,-b]


does not evaluate to 0. So, how can I define a bilinear matrix product in Mathematica?

Mathematica is "aware" of linearity of Dot in all its arguments, but to exploit it you need to tell Mathematica which expressions represent Matrices, and explicitly ask to expand expression using TensorExpand function:

ClearAll[α, β, γ, δ, a, b, c, d, k, l, m, n]
TensorExpand[
Dot[α a, β b + γ c, δ d],
Assumptions ->
a ∈ Matrices[{k, l}] && (b|c) ∈ Matrices[{l, m}] && d ∈ Matrices[{m, n}]
]
(* α β δ a.b.d + α γ δ a.c.d *)


You can also use it to exploit $a \cdot b + a\cdot (-b) = 0$ identity:

TensorExpand[
Dot[a, b] + Dot[a, -b],
Assumptions -> a ∈ Matrices[{m, n}] && b ∈ Matrices[{n, k}]
]
(* 0 *)


Mathematica is "aware" of $a \cdot b + a\cdot (-b) = 0$ identity for matrices, but you need to tell Mathematica that a and b represent Matrices, and explicitly ask for "canonical form" using TensorReduce:

ClearAll[a, b, m, n, k]
$Assumptions = a ∈ Matrices[{m, n}] && b ∈ Matrices[{n, k}]; Dot[a, b] + Dot[a, -b] % // TensorReduce (* a.(-b) + a.b *) (* 0 *)  As with any function taking Assumptions option defaulting to $Assumptions, you can localize assumptions by passing them explicitly to TensorReduce:

TensorReduce[
Dot[a, b] + Dot[a, -b],
Assumptions -> a ∈ Matrices[{m, n}] && b ∈ Matrices[{n, k}]
]
(* 0 *)


or by using Assuming, as suggested in comment by Jason B:

Assuming[
a ∈ Matrices[{m, n}] && b ∈ Matrices[{n, k}],
Dot[a, b] + Dot[a, -b] // TensorReduce
]
(* 0 *)

• You could use Assuming[a \[Element] Matrices[{m, n}] && b \[Element] Matrices[{n, k}], Dot[a, b] + Dot[a, -b] // TensorReduce ] to avoid modifying the global $Assumptions Commented Mar 8, 2016 at 13:42 • @JasonB Thanks, added it to the answer. Commented Mar 8, 2016 at 14:08 In raw symbolic form, Mathematica, simply doesn't know what a and b in a.b + a.-bare, so it doesn't evaluate the expression. However, given a hint ... With[{a = {x, y}, b = {u, y}}, a.b + a.-b]]  0 • Slightly simpler: With[{a = {x, y}, b = {u, y}}, a.b + a.-b] Commented Mar 8, 2016 at 13:22 • But Mathematica doesn't have to know anything about a and b, because the relation holds for all a and b. Much like a-a=0. Commented Mar 8, 2016 at 13:36 • @murphy, but from the documentation "When its arguments are not lists or sparse arrays, Dot remains unevaluated." Commented Mar 8, 2016 at 13:38 • @DavidG.Stork. Good catch. My brain doesn't seem to be fully functional today. Commented Mar 8, 2016 at 13:42 • @murphy : So, when$a$is a 4-by-3 matrix and$b$is a 17 element vector, this relation holds? Remember, if I don't tell you anything about the types of$a$and$b\$, they can be anything. Commented Mar 8, 2016 at 21:55

There are small number of rules that make a function bilinear, so why not just implement them directly?

ClearAll@blDot;
Attributes[blDot] = {OneIdentity, Flat, Orderless};
blDot[Plus[a_, b_], c_] := blDot[a, c] + blDot[b, c];
blDot[Times[a_, b_], c_] := Times[a, blDot[b, c]];
blDot[a_, b_] := Dot[a, b]


It works on these examples,

blDot[a, (b + c)]
blDot[(a + d), (b + c)]
blDot[a, b] + blDot[a, -b]
(* a.b + a.c *)
(* a.b + a.c + b.d + c.d *)
(* 0 *)


But you have to be careful, since Times still has the attribute Orderless (and I wouldn't recommend changing that), it has no way of knowing which of the multiplied items is a number and which a vector. So you get this,

blDot[A, -α B]
(* -B A.α *)


when you might have wanted this

(* -α A.B *)