19 Linear transformations with fastmath.matrix
- DRAFT π
In this tutorial we discuss the notion of linear transformations and show how they can be represented as matrices.
Specifically, we will use fastmath.vector
for vectors and fastmath.matrix
for matrices.
19.1 Setup
ns noj-book.fastmath-matrix-intro
(:require [fastmath.vector :as vec]
(:as mat]
[fastmath.matrix :as math])) [fastmath.core
19.2 Vectors
Recall that vectors are abstract entities that live in vector spaces (or linear spaces).
We often represent vectors them as arrays of numbers. The fastmath.vector
API supports a few datatypes of this kind.
3 4) (vec/->Vec2
3.0 4.0] [
3 4 -1) (vec/->Vec3
3.0 4.0 -1.0] [
(vec/vec->RealVector1 3 9 -3]) [
0x70ab88b7 "{1; 3; 9; -3}"] #object[org.apache.commons.math3.linear.ArrayRealVector
What we care about in linear algebra is mostly the structure of vector spaces, which is defined by the operations of addition and multiplication by a βscalarβ (that is, a single number). These operations are just functions which are assumed to satisfy certain axioms.
When we represent vectors as arrays of numbers, there is a standard way to define such operations: element-by-element.
3 1)
(vec/add (vec/->Vec2 2 -2)) (vec/->Vec2
5.0 -1.0] [
3 1)
(vec/mult (vec/->Vec2 5)
15.0 5.0] [
Sometimes, vector spaces are endowed by additional structure, which is defined as additional functions over these spaces.
E.g., we may add a notion of magnitude of vectors, so called norm. When we represent vectors as arrays of numbers, one standard way to define a norm is to compute the distance of the corresponding points from zero.
(vec/mag3 4)) (vec/->Vec2
5.0
(You may verify that 5 is the distance between (0,0)
to (3,4)
in the plane using Pythagoras theorem.)
Another additional operation that is a scalar product operation between vectors. This is a function that takes two vectors and returns a scalar (a number). When we represent vectors as arrays of numbers, one standard way to define it is by multiplying element by element and summing up. This is the so-called dot-product.
(vec/dot1 10 100)
(vec/->Vec3 1 2 3)) (vec/->Vec3
321.0
19.3 Matrices as transformations
Matrices are arrays of numbers of rectangular shape:
0 1 2 0) (mat/->Mat2x2
0.0, 1.0]
#mat2x2 [[2.0, 0.0]] [
(mat/rows->RealMatrix1 3 9]
[[8 -9 7]]) [
0x4a7ab0cd "Array2DRowRealMatrix{{1.0,3.0,9.0},{8.0,-9.0,7.0}}"] #object[org.apache.commons.math3.linear.Array2DRowRealMatrix
Conceptually, we think about matrices as functions, also called mappings or transformations or operators, between vector spaces. As weβll see below, the act as a specific kind of functions, which are linear.
The way to apply the matrix as a function to a vector is called βmultiplying the vector by the matrixβ. We multiply from the left β algebraically, the matrix will be written to the left of the vector.
The multiplication of a \(k \times l\) matrix \(M\) with an \(l\)-dimensional vector \(v\) is an \(k\)-dimensional vector \(Mv\).
Each element of \(Mv\) is a dot product (as defined above) of the corresponding row of \(M\) with \(v\).
19.4 Example: 2x3
- M - 2x3 matrix
- v - 3-dimensional vector
- Mv - 2-dimensional vector
(mat/mulv (mat/rows->RealMatrix1 1 1]
[[1 0 -1]])
[
(vec/vec->RealVector10 20 30])) [
0x23811656 "{60; -20}"] #object[org.apache.commons.math3.linear.ArrayRealVector
Concretely, its elements will be:
1 1 1)
(vec/dot (vec/->Vec3 10 20 30)) (vec/->Vec3
60.0
1 0 -1)
(vec/dot (vec/->Vec3 10 20 30)) (vec/->Vec3
20.0 -
You see, multiplying this 2x3 matrix by a vector of dimension 3 resulted in a vector of dimension 2. This matrix acts as follows:
- The first new element is the sum of three old elements.
- The second new element is the difference of the first and last old elements.
19.4.1 Example: 1x3
The case of a matrix with one row is basically dot product. (but considering the result as a 1-dim vector rather than a number).
(mat/mulv (mat/rows->RealMatrix1 0 -1]])
[[
(vec/vec->RealVector10 20 30])) [
0x4d0ff718 "{-20}"] #object[org.apache.commons.math3.linear.ArrayRealVector
(vec/dot (vec/vec->RealVector1 0 -1])
[
(vec/vec->RealVector10 20 30])) [
20.0 -
19.4.2 Example: 3x2
(mat/mulv (mat/rows->RealMatrix1 1]
[[1 0]
[0 1]])
[
(vec/vec->RealVector10 20])) [
0x2f348c04 "{30; 10; 20}"] #object[org.apache.commons.math3.linear.ArrayRealVector
19.4.3 Application
Assume that our vectors are 2 dimensional and represent our sales: (apples,oranges)
. We wish to add the income. Assume we receive 20 cents for an apple and 30 cents for an orange.
Example sales: 10 apples, 100 oranges.
(mat/mulv (mat/rows->RealMatrix1 0]
[[0 1]
[20 30]])
[
(vec/vec->RealVector10 100])) [
0x57ca8054 "{10; 100; 3,200}"] #object[org.apache.commons.math3.linear.ArrayRealVector
a lot of cents!!
19.4.4 Example: 2x2
A square-shaped matrix can be seen as a transformation from a vector space to itself. For example, a 2x2 matrix takes vectors of dimension 2 to vectors of dimension 2.
(mat/mulv (mat/->Mat2x21 1
1 0)
(vec/->Vec210 20))
30.0 10.0] [
19.4.5 Multiplying by a matrix is a linear transformation
We still need to explain what linear transformations are, and how they can be implemented with matrices.
19.5 Special cases
19.5.1 Identity matrix
This matrix has ones on the main diagonal and zeros elsewhere.
1 0 0 1) (mat/->Mat2x2
1.0, 0.0]
#mat2x2 [[0.0, 1.0]] [
Multiplying by this matrix does nothing (as the identity function in Clojure!).
(mat/mulv1 0 0 1)
(mat/->Mat2x2 3 4)) (vec/->Vec2
3.0 4.0] [
identity
(3 4)) (vec/->Vec2
3.0 4.0] [
19.5.2 Permutation matrix
This is similar to the identity, but the order of rows is changes.
0 1 1 0) (mat/->Mat2x2
0.0, 1.0]
#mat2x2 [[1.0, 0.0]] [
It acts by changing the order of coordinates.
(mat/mulv0 1 1 0)
(mat/->Mat2x2 3 4)) (vec/->Vec2
4.0 3.0] [
19.6 Operations on matrices
fastmath.vector
offers a rich collection of operations that act on matrices themselves.
For example, transposition reverses the roles of columns and rows:
0 1 2 0) (mat/->Mat2x2
0.0, 1.0]
#mat2x2 [[2.0, 0.0]] [
(mat/transpose0 1 2 0)) (mat/->Mat2x2
0.0, 2.0]
#mat2x2 [[1.0, 0.0]] [
19.7 What are linear transformations?
Given a matrix \(M\), the function \(v \mapsto M v\), or in Clojure, (fn [v] (mat/mul m v))
, is of a special kind. It is \(linear\).
Let us discuss what this means.
Given a set of vectors, their linear combinations are all the other vectors one may get from them using addition and multiplication by scalar.
For example, (3,4)
is a linear combination of (1,0)
and (0,1)
:
1 0) 3)
(vec/add (vec/mult (vec/->Vec2 0 1) 4)) (vec/mult (vec/->Vec2
3.0 4.0] [
3 * (1,0) + 4 * (0,1) = (3,4)
Linear transformations are functions vectors->vectors which respect linear combinations.
Example:
defn T [v]
(+ (* -1 (v 0))
[(* 9 (v 1)))
(+ (* 2 (v 0))
(* -5 (v 1)))]) (
1 0]) (T [
1 2] [-
0 1]) (T [
9 -5] [
(T1 0) 3)
(vec/add (vec/mult (vec/->Vec2 0 1) 4))) (vec/mult (vec/->Vec2
33.0 -14.0] [
1 0)) 3)
(vec/add (vec/mult (T (vec/->Vec2 0 1)) 4)) (vec/mult (T (vec/->Vec2
33.0 -14.0] [
You see, it does not matter whether we apply T before or after taking a linear combination. In other words, it respects the linear structure of our vector space.
Another example - rotating a vector by 90 degrees (or Pi/2 radians):
defn R [v]
(/ math/PI 2))) (vec/rotate v (
(R1 0) 3)
(vec/add (vec/mult (vec/->Vec2 0 1) 4))) (vec/mult (vec/->Vec2
4.0 3.0000000000000004] [-
1 0)) 3)
(vec/add (vec/mult (R (vec/->Vec2 0 1)) 4)) (vec/mult (R (vec/->Vec2
4.0 3.0000000000000004] [-
Another example - multiplying by a matrix:
defn M [v]
(
(mat/mulv1 9 2 -5)
(mat/->Mat2x2 - v))
(M1 0) 3)
(vec/add (vec/mult (vec/->Vec2 0 1) 4))) (vec/mult (vec/->Vec2
33.0 -14.0] [
1 0)) 3)
(vec/add (vec/mult (M (vec/->Vec2 0 1)) 4)) (vec/mult (M (vec/->Vec2
33.0 -14.0] [
Actually, note that by the definition of multiplication between matrices and vectors, T
and M
are actually the same function.
19.8 The standard basis
The standard basis of the vector space of \(n\)-dimensional arrays of numbers is the set of vectors which are all 0 except for one 1.
In dimension \(n=3\), for example:
1 0 0)
#{(vec/->Vec3 0 1 0)
(vec/->Vec3 0 0 1)} (vec/->Vec3
0.0 0.0 1.0] [1.0 0.0 0.0] [0.0 1.0 0.0]} #{[
Every vector in these spaces can be expressed as a linear combination of standard basis elements.
For example:
2 3 4) (vec/->Vec3
2.0 3.0 4.0] [
-> (vec/mult (vec/->Vec3 1 0 0) 2)
(0 1 0) 3))
(vec/add (vec/mult (vec/->Vec3 0 0 1) 4))) (vec/add (vec/mult (vec/->Vec3
2.0 3.0 4.0] [
The standard basis vectors are linearly independent: Each of them cannot be expressed as a linear combination of the others.
So: Every vector can be expressed (in a unique way!) as a linear combination of standard basis elements, but we need all of them for that.
E.g., in dimension 3, we need all 3.
19.9 Representing linear transformations as matrices
We have already claimed that matrices act as linear transformations.
Actually, if we represent our vectors as arrays of numbers, any linear transformation \(T\) can be represented as a matrix.
The reason is that, given any vector, we can represent it as a linear combination of standard basis elements, so we can infer the way it is transformed by \(T\), if we look into what \(T\) does to the standard basis elements. But this information can be encoded in a matrix, which acts the same way as \(T\).
19.10 Matrix multiplication
Matrix multiplication is one important operation:
0 1 1 0) (mat/->Mat2x2
0.0, 1.0]
#mat2x2 [[1.0, 0.0]] [
2 0 3 0) (mat/->Mat2x2
2.0, 0.0]
#mat2x2 [[3.0, 0.0]] [
(mat/mulm0 1 1 0)
(mat/->Mat2x2 2 0 3 0)) (mat/->Mat2x2
3.0, 0.0]
#mat2x2 [[2.0, 0.0]] [
The multiplication \(MN\) of a \(k \times l\) matrix \(M\) with an \(l \times m\) matrix \(N\) is defined as a \(k \times m\) matrix. Each of its columns is the matrix-vector multiplication of \(M\) by the corresponding column of \(N\), seen as a vector.
Importantly, if we see matrices as transformations as suggested above, then multiplication is just composition of functions. At the moment, we will not try to explain why this is true.
Matrix multiplication is non-commutative β the order matters:
(mat/mulm0 1 1 0)
(mat/->Mat2x2 2 0 0 3)) (mat/->Mat2x2
0.0, 3.0]
#mat2x2 [[2.0, 0.0]] [
(mat/mulm2 0 0 3)
(mat/->Mat2x2 0 1 1 0)) (mat/->Mat2x2
0.0, 2.0]
#mat2x2 [[3.0, 0.0]] [