Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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?

share|improve this question
up vote 7 down vote accepted

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 *)

Old answer using TensorReduce

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 *)
share|improve this answer
3  
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 – JasonB Mar 8 at 13:42
    
@JasonB Thanks, added it to the answer. – jkuczm Mar 8 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

share|improve this answer
1  
Slightly simpler: With[{a = {x, y}, b = {u, y}}, a.b + a.-b] – David G. Stork Mar 8 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 at 13:36
3  
@murphy, but from the documentation "When its arguments are not lists or sparse arrays, Dot remains unevaluated." – JasonB Mar 8 at 13:38
    
@DavidG.Stork. Good catch. My brain doesn't seem to be fully functional today. – m_goldberg Mar 8 at 13:42
1  
@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 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 *)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.