# 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 – Jason B. Mar 8 '16 at 13:42 • @JasonB Thanks, added it to the answer. – jkuczm Mar 8 '16 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] – David G. Stork Mar 8 '16 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. – murphy Mar 8 '16 at 13:36 • @murphy, but from the documentation "When its arguments are not lists or sparse arrays, Dot remains unevaluated." – Jason B. Mar 8 '16 at 13:38 • @DavidG.Stork. Good catch. My brain doesn't seem to be fully functional today. – m_goldberg Mar 8 '16 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. – Eric Towers Mar 8 '16 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 *)