Monocurl Essays
Series Download

A matrix is a transformation of space

A 2x2 matrix moves every point of the plane, and its two columns say where the basis arrows land. Linearity is why those four numbers settle everything else.

18 min·Early college·

AssumesWhat is a vector? Arrows, lists of numbers, and adding themThe unit circle: sine and cosine as coordinates

The matrix with rows $(2, 1)$ and $(0, 1)$ acting on the plane. Every point moves at once. The blue arrow, which starts as $(1, 0)$, ends at $(2, 0)$, the first column; the orange arrow, which starts as $(0, 1)$, ends at $(1, 1)$, the second column.
Monocurl source
let Show = |t| [
    Warp(B2, IDENT, A, t),
    MatBox([2.65, 0.1, 0], blend(IDENT, A, t), 2)
]
mesh ground = Ground(B2)
mesh show = Show(t: 0)
mesh label = [center{[2.65, 1.15, 0]} Note("the matrix", 0.74)]

slide "act"
    play Wait(0.9)
    show.t = 1
    play Lerp(3.2, [&show])
    play Wait(2)

Uses the shared definitions for this lesson's figures.

Here is a matrix:

$$ A = \begin{pmatrix} 2 & 1 \\ 0 & 1 \end{pmatrix}. $$

What does it do? A first course usually answers with a recipe. To multiply $A$ by a vector $(x, y)$, pair each row with the vector and add: the result is $(2x + 1y,\ 0x + 1y) = (2x + y,\ y)$. The recipe is correct and says nothing about why anyone would want it. It also hides a puzzle. The rule moves every point of the plane, infinitely many of them, and yet the whole rule is stored in four numbers. Most ways of moving the points of a plane cannot be stored in four numbers, or in four million. What is special about this kind?

We will find out by treating the recipe as what it is, a function that takes a vector in and gives a vector out, and watching what it does. I assume you know from the lesson on vectors that a vector in $\mathbb{R}^2$ is a pair of numbers drawn as an arrow from the origin, that vectors add component by component, that $c\,\mathbf{v}$ scales each component by $c$, and that $(x, y) = x\,\mathbf{i} + y\,\mathbf{j}$ where $\mathbf{i} = (1, 0)$ and $\mathbf{j} = (0, 1)$.

Feeding points to the rule

Call the function $T$, so that $T(x, y) = (2x + y,\ y)$. Before any theory, compute.

Pause and try

Find $T(1, 1)$, $T(-1, 2)$ and $T(2, -1)$. Plot each input and its output on grid paper. Then find $T(1, 0)$ and $T(0, 1)$ and compare them with the matrix $A$.

Show answerHide answer

$T(1, 1) = (2 + 1,\ 1) = (3, 1)$. $T(-1, 2) = (-2 + 2,\ 2) = (0, 2)$. $T(2, -1) = (4 - 1,\ -1) = (3, -1)$. Each point keeps its height and slides sideways. And $T(1, 0) = (2, 0)$, $T(0, 1) = (1, 1)$: these are the two columns of $A$, read downward.

  1. The rule sends (1, 1) to (2 + 1, 1) = (3, 1).
  2. It sends (-1, 2) to (0, 2) and (2, -1) to (3, -1). Heights do not change.
  3. Now move every whole-number point at once.
  4. Join the moved points. The grid lines are still straight, still parallel, still evenly spaced.
The rule $T(x, y) = (2x + y, y)$ applied first to three points and then to every whole-number point in view. Each row of points slides sideways and spreads out, and the lines through the points remain straight, parallel and evenly spaced.
Monocurl source
let Swarm = |t| block {
    let m = blend(IDENT, A, t)
    for (i in range(-4, 6)) {
        for (j in range(-2, 4)) {
            let q = apply(m, [i, j])
            if (inside(B2, q)) {
                . Pt(P(B2, q), SLATE, 0.06)
            }
        }
    }
}
let Hop = |p| [
    Ring(P(B2, p), SLATE, 0.09, 2.5),
    Vec(B2, p, apply(A, p), LEAF, 3.5, 0.17),
    Pt(P(B2, apply(A, p)), LEAF, 0.085)
]
mesh ground = Ground(B2)
mesh lines = []
mesh rule = [
    center{[2.65, 1.45, 0]} Math("(x, y) \mapsto", 0.85, INK),
    center{[2.65, 0.95, 0]} Math("(2x + y,\ y)", 0.85, INK)
]
mesh hops = [Hop([1, 1])]
mesh list = [center{[2.65, 0.1, 0]} Math("(1, 1) \mapsto (3, 1)", 0.8, LEAF)]
mesh swarm = []

slide "The rule sends (1, 1) to (2 + 1, 1) = (3, 1)."
    play Fade(0.6)

slide "It sends (-1, 2) to (0, 2) and (2, -1) to (3, -1). Heights do not change."
    hops .= Hop([-1, 2])
    hops .= Hop([2, -1])
    list .= center{[2.65, -0.5, 0]} Math("(-1, 2) \mapsto (0, 2)", 0.8, LEAF)
    list .= center{[2.65, -1.1, 0]} Math("(2, -1) \mapsto (3, -1)", 0.8, LEAF)
    play Fade(0.6)

slide "Now move every whole-number point at once."
    hops = []
    list = []
    play Fade(0.4, [&hops, &list])
    swarm = Swarm(t: 0)
    play Fade(0.5, [&swarm])
    swarm.t = 1
    play Lerp(2.4, [&swarm])

slide "Join the moved points. The grid lines are still straight, still parallel, still evenly spaced."
    lines = Lines(B2, A)
    play Fade(0.8, [&lines])

Uses the shared definitions for this lesson's figures.

What the grid keeps

Three things survive the move, and you can check each against the last step of the figure. The origin stays where it is, since $T(0, 0) = (0, 0)$. Straight grid lines land on straight lines. And lines that were parallel and evenly spaced are still parallel and evenly spaced, so the squares of the grid have all become copies of one parallelogram.

That last fact gives a way to find where any vector goes without touching the formula. A vector such as $(1, 2)$ is an address on the grid: one step along $\mathbf{i}$, then two steps along $\mathbf{j}$. If the grid moves as a whole and keeps its even spacing, the address should still be valid on the moved grid, read with the moved arrows.

Pause and try

Using only $T(\mathbf{i}) = (2, 0)$ and $T(\mathbf{j}) = (1, 1)$, predict where $(1, 2)$ lands. Then check with the formula $T(x, y) = (2x + y, y)$.

Show answerHide answer

One step of the moved $\mathbf{i}$ and two of the moved $\mathbf{j}$: $1\,(2, 0) + 2\,(1, 1) = (4, 2)$. The formula agrees: $T(1, 2) = (2 + 2,\ 2) = (4, 2)$.

  1. The vector (1, 2) is 1 step of i (blue) and then 2 steps of j (orange).
  2. Apply the matrix. The grid moves, and the path of three arrows moves with it.
  3. It is still 1 step of the moved i and 2 steps of the moved j: 1(2, 0) + 2(1, 1) = (4, 2).
Following the vector $(1, 2)$ through the transformation. Before, it is 1 step of $\mathbf{i}$ and 2 steps of $\mathbf{j}$. Afterwards it is 1 step of the moved $\mathbf{i}$ and 2 steps of the moved $\mathbf{j}$, which is $1(2, 0) + 2(1, 1) = (4, 2)$.
Monocurl source
let Follow = |t| {
    let m = blend(IDENT, A, t)
    let e1 = [m[0], m[2]]
    let e2 = [m[1], m[3]]
    return [
        Lines(B2, m),
        Vec(B2, e1, add(e1, e2), tint(EMBER, 0.75), 4),
        Vec(B2, add(e1, e2), add(e1, times(2, e2)), tint(EMBER, 0.75), 4),
        Vec(B2, [0, 0], e2, EMBER),
        Vec(B2, [0, 0], e1, AZURE),
        Vec(B2, [0, 0], add(e1, times(2, e2)), LEAF, 4),
        Pt(P(B2, add(e1, times(2, e2))), LEAF, 0.085)
    ]
}
mesh ground = Ground(B2)
mesh follow = Follow(t: 0)
mesh notes = [
    center{[2.65, 1.2, 0]} Math("(1, 2) =", 0.9, LEAF),
    center{[2.65, 0.6, 0]} Tex([text_tag{1} "1\,\mathbf{i}", " + ", text_tag{2} "2\,\mathbf{j}"], 0.9)
]

slide "The vector (1, 2) is 1 step of i (blue) and then 2 steps of j (orange)."
    notes = color{AZURE, |tags| 1 in tags} color{EMBER, |tags| 2 in tags} notes
    play Fade(0.6)

slide "Apply the matrix. The grid moves, and the path of three arrows moves with it."
    notes = []
    play Fade(0.3, [&notes])
    follow.t = 1
    play Lerp(2.6, [&follow])

slide "It is still 1 step of the moved i and 2 steps of the moved j: 1(2, 0) + 2(1, 1) = (4, 2)."
    notes = [
        center{[2.65, 1.2, 0]} Math("1\,(2, 0)", 0.9, AZURE),
        center{[2.65, 0.6, 0]} Math("+\ 2\,(1, 1)", 0.9, EMBER),
        center{[2.65, 0.0, 0]} Math("= (4, 2)", 0.9, LEAF)
    ]
    play Fade(0.6, [&notes])

Uses the shared definitions for this lesson's figures.

So the two arrows $T(\mathbf{i})$ and $T(\mathbf{j})$ seem to control everything, which would explain how four numbers can describe the fate of every point. But the argument leaned on a phrase, “the grid moves as a whole and keeps its even spacing”, that we read off a picture. To turn it into a proof we have to say exactly which property of $T$ we used.

The property behind the picture

Look at what the prediction for $(1, 2)$ assumed. We split the input as $1\,\mathbf{i} + 2\,\mathbf{j}$ and claimed

$$ T(1\,\mathbf{i} + 2\,\mathbf{j}) = 1\,T(\mathbf{i}) + 2\,T(\mathbf{j}). $$

Two separate things happened there. A sum inside $T$ became a sum outside, and a scalar inside $T$ became a scalar outside. Those are the two properties to demand.

In pictures, additivity says that a parallelogram with sides $\mathbf{u}$ and $\mathbf{v}$ is carried to the parallelogram with sides $T(\mathbf{u})$ and $T(\mathbf{v})$, diagonal to diagonal. Homogeneity says that points along a line through the origin keep their relative spacing: the point twice as far out lands twice as far out. Taking $c = 0$ in the second property gives $T(\mathbf{0}) = \mathbf{0}$, so a linear map always fixes the origin.

Plenty of reasonable-looking maps fail. The shift $S(x, y) = (x + 1, y)$ keeps every line straight, but $S(0, 0) = (1, 0)$, so it is not linear. A subtler failure is $N(x, y) = (x,\ y + 0.3x^2)$, which fixes the origin. Here $N(1, 0) = (1, 0.3)$ and $N(2, 0) = (2, 1.2)$, while homogeneity would require $N(2, 0) = 2\,N(1, 0) = (2, 0.6)$.

The map $N(x, y) = (x, y + 0.3x^2)$, which is not linear. The origin stays put, but horizontal grid lines bend into parabolas, and $N(2, 0)$ (black dot) misses the point $2N(1, 0)$ (red ring) where homogeneity would put it.
Monocurl source
let Bend = |t| {
    let f = |x, y| [x, y + 0.3 * t * x * x]
    var out = []
    for (k in range(-2, 6)) {
        var w = 1.8
        if (k == 0) {
            w = 3
        }
        out .= Cut(B2, [k, -9], [k, 9], GRIDC, w)
    }
    for (k in range(-9, 4)) {
        var w = 1.8
        if (k == 0) {
            w = 3
        }
        var run = []
        for (x in sample(-2, 5, 280)) {
            let q = f(x, k)
            if (q[1] >= -2 and q[1] <= 3) {
                run .= P(B2, q)
            }
            if (q[1] < -2 or q[1] > 3) {
                if (len(run) > 1) {
                    out .= stroke{GRIDC, w} Polyline(run)
                }
                run = []
            }
        }
        if (len(run) > 1) {
            out .= stroke{GRIDC, w} Polyline(run)
        }
    }
    out .= Vec(B2, [0, 0], f(0, 1), EMBER)
    out .= Vec(B2, [0, 0], f(1, 0), AZURE)
    out .= Ring(P(B2, times(2, f(1, 0))), ROSE, 0.1, 3)
    out .= Pt(P(B2, f(2, 0)), INK, 0.085)
    return out
}
mesh ground = Ground(B2)
mesh bend = Bend(t: 0)
mesh rule = [
    center{[2.65, 1.45, 0]} Math("(x, y) \mapsto", 0.85, INK),
    center{[2.65, 0.95, 0]} Math("(x,\ y + 0.3x^2)", 0.85, INK)
]
mesh verdict = []

slide "bend"
    play Wait(0.9)
    bend.t = 1
    play Lerp(3, [&bend])
    verdict = [
        center{[2.65, -0.1, 0]} Math("N(2, 0)", 0.85, INK),
        center{[2.65, -0.6, 0]} Math("\neq 2\,N(1, 0)", 0.85, ROSE),
        center{[2.65, -1.25, 0]} Cap("not linear", 0.76, ROSE)
    ]
    play Fade(0.5, [&verdict])
    play Wait(2)

Uses the shared definitions for this lesson's figures.

Our $T$ passes both tests, and the check is worth doing once by hand. For $\mathbf{u} = (u_1, u_2)$ and $\mathbf{v} = (v_1, v_2)$,

$$ T(\mathbf{u} + \mathbf{v}) = \bigl(2(u_1 + v_1) + (u_2 + v_2),\ u_2 + v_2\bigr) = (2u_1 + u_2,\ u_2) + (2v_1 + v_2,\ v_2) = T(\mathbf{u}) + T(\mathbf{v}), $$

and $T(c\,\mathbf{v}) = (2cv_1 + cv_2,\ cv_2) = c\,(2v_1 + v_2,\ v_2) = c\,T(\mathbf{v})$. It worked because each output component is a sum of constant multiples of the inputs, with no squares, no products $xy$ and no added constants.

Two arrows determine everything

Now the observation from the grid can be proved, for every linear map at once.

The theorem says a linear map has no freedom left once $T(\mathbf{i})$ and $T(\mathbf{j})$ are chosen. Name the choices: say $T(\mathbf{i}) = (a, c)$ and $T(\mathbf{j}) = (b, d)$. Then

$$ T(x, y) = x\begin{pmatrix} a \\ c \end{pmatrix} + y\begin{pmatrix} b \\ d \end{pmatrix} = \begin{pmatrix} ax + by \\ cx + dy \end{pmatrix}. $$

The recipe from the first paragraph has appeared on its own, and its four numbers are the components of the two landing spots. It remains to check that any four numbers are allowed.

The two theorems together say that linear maps of the plane and $2 \times 2$ matrices are the same objects in two notations. Every matrix gives a linear map $\mathbf{v} \mapsto A\mathbf{v}$, every linear map comes from a matrix, and different matrices give different maps because their columns are the images of $\mathbf{i}$ and $\mathbf{j}$.

This answers the puzzle from the start. Four numbers suffice because linearity is a severe restriction: once you know where two arrows go, additivity and homogeneity dictate the rest.

Reading and writing matrices

The key statement works in both directions. Given a matrix, read its columns to see the motion. Given a motion that you know to be linear, find where $\mathbf{i}$ and $\mathbf{j}$ go and write those down as columns.

That example used the claim that a rotation is linear, and the claim needs a reason. A rotation about the origin is a rigid motion: it carries every figure to a congruent figure. So it carries the parallelogram with sides $\mathbf{u}, \mathbf{v}$ and diagonal $\mathbf{u} + \mathbf{v}$ to a parallelogram with sides $R(\mathbf{u}), R(\mathbf{v})$, whose diagonal is therefore $R(\mathbf{u}) + R(\mathbf{v})$; that is additivity. And it carries the point $c$ times as far along a ray to the point $c$ times as far along the rotated ray (for negative $c$, along the opposite ray, which rotates to the opposite of the rotated ray), which is homogeneity. The argument is geometric: it rests on the properties of rigid motions, which we take as known from geometry, and it is complete once those are granted.

For a rotation by a general angle $\theta$, the unit circle supplies the columns. The point reached by turning $(1, 0)$ through $\theta$ is $(\cos\theta, \sin\theta)$ by the definition of cosine and sine. And $\mathbf{j}$ is a quarter turn ahead of $\mathbf{i}$, so it lands a quarter turn ahead of $(\cos\theta, \sin\theta)$, at $(-\sin\theta, \cos\theta)$, using the quarter-turn rule $(x, y) \mapsto (-y, x)$ from the example. Hence

$$ R_\theta = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix}. $$
Rotation of the plane by an angle that grows to $30^\circ$ and then to $90^\circ$. The blue arrow is at $(\cos\theta, \sin\theta)$ and the orange one at $(-\sin\theta, \cos\theta)$, and those are the columns of the matrix shown.
Monocurl source
let B0 = Board([-0.85, 0, 0], 0.8, -3, 3, -2, 2)
let Turn = |deg| {
    let th = deg * PI / 180
    let m = [cos(th), -sin(th), sin(th), cos(th)]
    var out = [Lines(B0, m)]
    if (deg > 2) {
        out .= stroke{SLATE, 2.5} Polyline(map(sample(0, th, 24), |s| P(B0, [0.45 * cos(s), 0.45 * sin(s)])))
    }
    out .= Vec(B0, [0, 0], [m[1], m[3]], EMBER)
    out .= Vec(B0, [0, 0], [m[0], m[2]], AZURE)
    out .= MatBox([2.75, -0.55, 0], m, 2)
    out .= center{[2.75, 0.95, 0]} scale{1.15} color{INK} Number(deg, 0)
    return out
}
mesh ground = Ground(B0)
mesh turn = Turn(deg: 0)
mesh label = [center{[2.75, 1.45, 0]} Note("angle (degrees)", 0.74)]

slide "turn"
    play Wait(0.7)
    turn.deg = 30
    play Lerp(1.8, [&turn])
    play Wait(1.2)
    turn.deg = 90
    play Lerp(2.4, [&turn])
    play Wait(1.8)

Uses the shared definitions for this lesson's figures.

Here are four more transformations to read from their columns.

Pause and try

Write down the matrix of (a) the reflection across the line $y = x$, which swaps the two coordinates of every point, and (b) the projection onto the horizontal axis, $(x, y) \mapsto (x, 0)$. For each, decide first where $\mathbf{i}$ and $\mathbf{j}$ land.

Show answerHide answer

(a) Swapping coordinates sends $\mathbf{i} = (1, 0)$ to $(0, 1)$ and $\mathbf{j} = (0, 1)$ to $(1, 0)$, so the matrix is $\begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}$. (b) $\mathbf{i}$ is already on the axis and stays at $(1, 0)$; $\mathbf{j}$ drops to $(0, 0)$. The matrix is $\begin{pmatrix} 1 & 0 \\ 0 & 0 \end{pmatrix}$. Both appear in the last two steps of the next figure.

  1. A shear: i stays at (1, 0) and j leans over to (1, 1). Each point slides sideways by its height.
  2. A scaling: i stretches to (2, 0) and j shrinks to (0, 0.5).
  3. A reflection across the line y = x: i lands on (0, 1) and j on (1, 0). The F is now mirrored.
  4. A projection onto the horizontal axis: i stays and j goes to (0, 0). The plane is flattened onto a line.
Four linear maps and their matrices, applied to the grid and to a letter F: a shear, a scaling with different factors along the two axes, a reflection, and a projection that flattens the plane onto a line. In the last step the grey outline is where the F started and the thick green segment is all that is left of it.
Monocurl source
let Show = |a, b, c, d| [
    Lines(B2, [a, b, c, d]),
    FShape(B2, [a, b, c, d]),
    Vec(B2, [0, 0], [b, d], EMBER),
    Vec(B2, [0, 0], [a, c], AZURE),
    MatBox([2.65, 0.1, 0], [a, b, c, d], 1)
]
let go = |&m, a, b, c, d| anim {
    m.a = a
    m.b = b
    m.c = c
    m.d = d
    play Lerp(2.2, [&m])
}
mesh ground = Ground(B2)
mesh before = []
mesh flat = []
mesh show = Show(a: 1, b: 0, c: 0, d: 1)

slide "A shear: i stays at (1, 0) and j leans over to (1, 1). Each point slides sideways by its height."
    play go(&show, 1, 1, 0, 1)

slide "A scaling: i stretches to (2, 0) and j shrinks to (0, 0.5)."
    play go(&show, 2, 0, 0, 0.5)

slide "A reflection across the line y = x: i lands on (0, 1) and j on (1, 0). The F is now mirrored."
    play go(&show, 0, 1, 1, 0)

slide "A projection onto the horizontal axis: i stays and j goes to (0, 0). The plane is flattened onto a line."
    play go(&show, 1, 0, 0, 0)
    before = [
        Shape(map(FPTS, |p| P(B2, p)), SLATE, 0.1, 2),
        Dash(P(B2, [0.4, 0.3]), P(B2, [0.4, 0]), SLATE, 2),
        Dash(P(B2, [1.6, 1.9]), P(B2, [1.6, 0]), SLATE, 2)
    ]
    flat = [Seg(P(B2, [0.4, 0]), P(B2, [1.6, 0]), LEAF, 9)]
    play Fade(0.6, [&before, &flat])

Uses the shared definitions for this lesson's figures.

The procedure also works when the information given is about vectors other than $\mathbf{i}$ and $\mathbf{j}$.

Lines go to lines

We saw grid lines stay straight. The definition of linearity mentions sums and scalars, not lines, so this deserves a proof, and the proof shows the one way it can go wrong.

A line in the plane can be described by a point $\mathbf{p}$ on it and a nonzero direction vector $\mathbf{d}$: it is the set of all points $\mathbf{p} + t\,\mathbf{d}$ as $t$ runs through the real numbers.

The formula $T(\mathbf{p}) + t\,T(\mathbf{d})$ carries more than the statement. The parameter $t$ is unchanged, so equally spaced points on $L$ go to equally spaced points on the image. And two parallel lines share a direction $\mathbf{d}$, so their images share the direction $T(\mathbf{d})$ and are parallel as well. That is the even, parallel grid we observed.

The line through $(0, -1)$ with direction $(0.5, 1)$, and its image under $A$. The four marked points, at $t = 0, 1, 2, 3$, stay evenly spaced, and the image is the line through $A(0, -1) = (-1, -1)$ with direction $A(0.5, 1) = (2, 1)$.
Monocurl source
let p0 = [0, -1]
let d0 = [0.5, 1]
let Carry = |t| {
    let m = blend(IDENT, A, t)
    var out = [
        Lines(B2, m),
        Cut(B2, apply(m, add(p0, times(-9, d0))), apply(m, add(p0, times(9, d0))), LEAF, 4)
    ]
    for (k in range(0, 4)) {
        out .= Pt(P(B2, apply(m, add(p0, times(k, d0)))), LEAF, 0.09)
    }
    return out
}
mesh ground = Ground(B2)
mesh carry = Carry(t: 0)
mesh ghost = flatten([
    [Cut(B2, add(p0, times(-9, d0)), add(p0, times(9, d0)), SLATE, 2.5)],
    map(range(0, 4), |k| Ring(P(B2, add(p0, times(k, d0))), SLATE, 0.09, 2.5))
])
mesh names = [
    center{[2.65, 0.9, 0]} Math("\mathbf{p} + t\,\mathbf{d}", 0.9, SLATE),
    center{[2.65, 0.3, 0]} Math("\downarrow", 0.9, SLATE),
    center{[2.65, -0.3, 0]} Math("T(\mathbf{p}) + t\,T(\mathbf{d})", 0.85, LEAF)
]

slide "carry"
    play Wait(0.9)
    carry.t = 1
    play Lerp(3, [&carry])
    play Wait(2)

Uses the shared definitions for this lesson's figures.

The exceptional case really occurs. For the projection $P = \begin{pmatrix} 1 & 0 \\ 0 & 0 \end{pmatrix}$ from the last step of the gallery, $P(x, y) = (x, 0)$, so the direction $\mathbf{d} = \mathbf{j}$ has $P(\mathbf{d}) = \mathbf{0}$, and every vertical line is crushed to one point of the horizontal axis. So the accurate statement is “lines go to lines or to points”, and the second happens exactly for directions that the map sends to zero.

Step back to see what was hard. Computing a matrix times a vector was the easy part. The work was in finding the property, linearity, that makes the recipe inevitable and lets two arrows speak for a whole plane. From here on, a matrix can be read as a picture: look at the columns, imagine the grid following them. The next lesson uses that picture to explain what it means to multiply two matrices.

Check yourself

A linear map sends $\mathbf{i}$ to $(1, 3)$ and $\mathbf{j}$ to $(-2, 0)$. Where does it send $(2, 1)$?

Problems

The first three are direct practice, the next three need linearity used with some thought, and the last two ask for short proofs.

Problem 1

Let $M = \begin{pmatrix} 1 & 2 \\ 3 & -1 \end{pmatrix}$. Where does $M$ send $\mathbf{i}$ and $\mathbf{j}$? Compute $M(2, 1)$ and $M(-1, 3)$.

Show solutionHide solution

The columns give $M\mathbf{i} = (1, 3)$ and $M\mathbf{j} = (2, -1)$. Then $M(2, 1) = 2\,(1, 3) + 1\,(2, -1) = (4, 5)$ and $M(-1, 3) = -1\,(1, 3) + 3\,(2, -1) = (-1 + 6,\ -3 - 3) = (5, -6)$. By rows, as a check: $(1 \cdot 2 + 2 \cdot 1,\ 3 \cdot 2 - 1 \cdot 1) = (4, 5)$.

Problem 2

A linear map sends $\mathbf{i}$ to $(0, 2)$ and $\mathbf{j}$ to $(-1, 1)$. Write its matrix and find the image of $(3, 2)$.

Show solutionHide solution

The landing spots are the columns: $\begin{pmatrix} 0 & -1 \\ 2 & 1 \end{pmatrix}$. The image of $(3, 2)$ is $3\,(0, 2) + 2\,(-1, 1) = (-2,\ 6 + 2) = (-2, 8)$.

Problem 3

Describe in words what each matrix does to the plane: (a) $\begin{pmatrix} -1 & 0 \\ 0 & 1 \end{pmatrix}$, (b) $\begin{pmatrix} 3 & 0 \\ 0 & 3 \end{pmatrix}$, (c) $\begin{pmatrix} 0 & 1 \\ -1 & 0 \end{pmatrix}$.

Show solutionHide solution

(a) $\mathbf{i}$ goes to $(-1, 0)$ and $\mathbf{j}$ stays: $(x, y) \mapsto (-x, y)$, the reflection across the vertical axis. (b) Both basis vectors are tripled: $(x, y) \mapsto (3x, 3y)$, an enlargement by the factor 3 about the origin. (c) $\mathbf{i}$ goes to $(0, -1)$, pointing down, and $\mathbf{j}$ goes to $(1, 0)$, pointing right. Each has turned a quarter turn clockwise, so this is the rotation by $90^\circ$ clockwise, $(x, y) \mapsto (y, -x)$.

Problem 4

Decide whether each map is linear. If it is, give its matrix. If not, show a specific failure. (a) $T(x, y) = (3x - y,\ x)$. (b) $T(x, y) = (x + 2,\ y)$. (c) $T(x, y) = (xy,\ y)$. (d) $T(x, y) = (|x|,\ y)$.

Show solutionHide solution

(a) Linear: it has the form $(ax + by, cx + dy)$ with matrix $\begin{pmatrix} 3 & -1 \\ 1 & 0 \end{pmatrix}$. (b) Not linear: $T(0, 0) = (2, 0) \neq \mathbf{0}$. (c) Not linear: $T(1, 1) = (1, 1)$ but $T(2, 2) = (4, 2)$, which is not $2\,T(1, 1) = (2, 2)$. (d) Not linear: $T(1, 0) + T(-1, 0) = (1, 0) + (1, 0) = (2, 0)$, while $T\bigl((1, 0) + (-1, 0)\bigr) = T(0, 0) = (0, 0)$. Note that (d) fixes the origin and satisfies $T(c\,\mathbf{v}) = c\,T(\mathbf{v})$ for $c \geq 0$, yet additivity fails.

Problem 5

A linear map $T$ satisfies $T(2, 1) = (1, 4)$ and $T(1, 1) = (0, 3)$. Find its matrix.

Show solutionHide solution

Express the basis vectors through the known inputs. $\mathbf{i} = (2, 1) - (1, 1)$, so $T(\mathbf{i}) = (1, 4) - (0, 3) = (1, 1)$. And $\mathbf{j} = (1, 1) - \mathbf{i}$, so $T(\mathbf{j}) = (0, 3) - (1, 1) = (-1, 2)$. The matrix is $\begin{pmatrix} 1 & -1 \\ 1 & 2 \end{pmatrix}$. Check: it sends $(2, 1)$ to $(2 - 1,\ 2 + 2) = (1, 4)$ and $(1, 1)$ to $(1 - 1,\ 1 + 2) = (0, 3)$.

Problem 6

Write the matrix of the rotation by $60^\circ$ counterclockwise. Find the images of $(2, 0)$ and $(0, 2)$, and verify that both images have length 2.

Show solutionHide solution

With $\cos 60^\circ = \frac12$ and $\sin 60^\circ = \frac{\sqrt3}{2}$, the matrix is $\begin{pmatrix} \frac12 & -\frac{\sqrt3}{2} \\ \frac{\sqrt3}{2} & \frac12 \end{pmatrix}$. The image of $(2, 0)$ is twice the first column, $(1, \sqrt3)$, of length $\sqrt{1 + 3} = 2$. The image of $(0, 2)$ is twice the second column, $(-\sqrt3, 1)$, of length $\sqrt{3 + 1} = 2$. A rotation changes no lengths, as expected.

Problem 7

Find the equation of the image of the line $y = x + 1$ under $A = \begin{pmatrix} 2 & 1 \\ 0 & 1 \end{pmatrix}$. Then find a line whose image under the projection $P = \begin{pmatrix} 1 & 0 \\ 0 & 0 \end{pmatrix}$ is the single point $(4, 0)$.

Show solutionHide solution

The line $y = x + 1$ passes through $\mathbf{p} = (0, 1)$ with direction $\mathbf{d} = (1, 1)$. Its image passes through $A\mathbf{p} = (1, 1)$ with direction $A\mathbf{d} = (3, 1)$, so it has slope $\frac13$ and equation $y - 1 = \frac13(x - 1)$, that is, $y = \frac13 x + \frac23$. Check with another point: $(1, 2)$ is on the original line and goes to $(4, 2)$, and $\frac43 + \frac23 = 2$. For the second part we need a direction with $P\mathbf{d} = \mathbf{0}$; since $P(x, y) = (x, 0)$, that means $\mathbf{d} = (0, 1)$ up to scaling, a vertical line. The vertical line $x = 4$ consists of the points $(4, t)$, all of which go to $(4, 0)$.

Problem 8

Let $T$ be a linear map of $\mathbb{R}^2$ whose two columns $T(\mathbf{i})$ and $T(\mathbf{j})$ are not parallel. Prove that $T$ never sends two different vectors to the same place. (Use the fact from the lesson on vectors: if two vectors are not parallel, the only combination $a\,\mathbf{u} + b\,\mathbf{v}$ equal to $\mathbf{0}$ is the one with $a = b = 0$.) What goes wrong for the projection $P$ of the previous problem?

Show solutionHide solution

Suppose $T(\mathbf{v}) = T(\mathbf{w})$. By linearity $T(\mathbf{v} - \mathbf{w}) = T(\mathbf{v}) + T(-\mathbf{w}) = T(\mathbf{v}) - T(\mathbf{w}) = \mathbf{0}$. Write $\mathbf{v} - \mathbf{w} = (x, y)$. Then $\mathbf{0} = T(x, y) = x\,T(\mathbf{i}) + y\,T(\mathbf{j})$. Since $T(\mathbf{i})$ and $T(\mathbf{j})$ are not parallel, they form a basis, and $\mathbf{0}$ has only the one expression $0\,T(\mathbf{i}) + 0\,T(\mathbf{j})$; hence $x = y = 0$, so $\mathbf{v} = \mathbf{w}$. For $P$ the columns are $(1, 0)$ and $(0, 0)$, which are parallel because the zero vector is a multiple of anything. The argument breaks at the last step, and indeed $P(4, 1) = P(4, 2) = (4, 0)$.

Shared definitions used by this lesson's figures
# house kit: prepended to every essay figure after the std imports

# palette. AZURE and EMBER are the two actors, LEAF marks an answer, ROSE a problem
let PAPER = [1, 1, 1, 1]
let INK = [0.08, 0.09, 0.11, 1]
let SLATE = [0.40, 0.44, 0.50, 1]
let MIST = [0.85, 0.86, 0.88, 1]
let AZURE = [0.13, 0.42, 0.68, 1]
let EMBER = [0.89, 0.42, 0.12, 1]
let LEAF = [0.13, 0.55, 0.36, 1]
let ROSE = [0.78, 0.22, 0.24, 1]
let PLUM = [0.47, 0.30, 0.66, 1]
let GOLD = [0.85, 0.62, 0.08, 1]

background = PAPER

# an opaque pastel of col; use for fills so overlaps do not darken
let tint = |col, amount = 0.18| [
    1 - (1 - col[0]) * amount,
    1 - (1 - col[1]) * amount,
    1 - (1 - col[2]) * amount,
    1
]

# text: Cap for labels, Note for quiet labels, Math for typeset maths
let Cap = |txt, size = 0.75, col = INK| color{col} Text(txt, size, "Charter")
let Note = |txt, size = 0.65| color{SLATE} Text(txt, size, "Charter")
let Math = |tex, size = 0.9, col = INK| color{col} Tex(tex, size)

# a paper rectangle to sit behind text that crosses lines
let Plate = |pos, size| center{pos} fill{PAPER} stroke{alpha{0} PAPER, 0} Rect(size)

# shapes with fill and stroke both set, so no stray black appears
let Pt = |pos, col = INK, r = 0.075| center{pos} fill{col} stroke{col, 1} Circle(r, 48)
let Ring = |pos, col = INK, r = 0.1, w = 3| center{pos} fill{PAPER} stroke{col, w} Circle(r, 48)
let Seg = |a, b, col = INK, w = 3| stroke{col, w} Line(a, b)
let Path = |pts, col = INK, w = 3| stroke{col, w} Polyline(pts)
let Region = |pts, col| fill{col} stroke{alpha{0} col, 0} Polygon(pts)
let Outline = |pts, col = INK, w = 3| fill{alpha{0} PAPER} stroke{col, w} Polygon(pts)
let Shape = |pts, col, amount = 0.18, w = 3| fill{tint(col, amount)} stroke{col, w} Polygon(pts)
let Disc = |pos, r, col, amount = 0.18, w = 3| center{pos} fill{tint(col, amount)} stroke{col, w} Circle(r, 96)
let Box = |pos, size, col, amount = 0.18, w = 3| center{pos} fill{tint(col, amount)} stroke{col, w} Rect(size)
# a line from a to b ending in a small solid arrowhead
let Tip = |a, b, col = INK, w = 3, head = 0.17| {
    let d = normalize([b[0] - a[0], b[1] - a[1], 0])
    let n = [-d[1], d[0], 0]
    let base = [b[0] - d[0] * head, b[1] - d[1] * head, 0]
    return [
        stroke{col, w} Line(a, base),
        fill{col} stroke{col, 1} Polygon([
            b,
            [base[0] + n[0] * head * 0.42, base[1] + n[1] * head * 0.42, 0],
            [base[0] - n[0] * head * 0.42, base[1] - n[1] * head * 0.42, 0]
        ])
    ]
}

# plots. a frame is [x0, x1, y0, y1, centre, width, height]: a data window and the scene box it fills
let Frame = |x0, x1, y0, y1, c = [0, 0, 0], w = 6.4, h = 3.6| [x0, x1, y0, y1, c, w, h]
let fx = |fr, x| fr[4][0] + (x - (fr[0] + fr[1]) / 2) * fr[5] / (fr[1] - fr[0])
let fy = |fr, y| fr[4][1] + (y - (fr[2] + fr[3]) / 2) * fr[6] / (fr[3] - fr[2])
let at = |fr, x, y| [fx(fr, x), fy(fr, y), 0]

# axes through the data origin (or the nearest edge of the window), with optional names
let Axes = |fr, x_name = "", y_name = "", col = SLATE| {
    let ox = clamp(fr[0], 0, fr[1])
    let oy = clamp(fr[2], 0, fr[3])
    var parts = [
        Tip(at(fr, fr[0], oy), [fx(fr, fr[1]) + 0.25, fy(fr, oy), 0], col, 2.5, 0.15),
        Tip(at(fr, ox, fr[2]), [fx(fr, ox), fy(fr, fr[3]) + 0.25, 0], col, 2.5, 0.15)
    ]
    if (x_name != "") {
        parts .= center{[fx(fr, fr[1]) + 0.5, fy(fr, oy), 0]} Math(x_name, 0.8, col)
    }
    if (y_name != "") {
        parts .= center{[fx(fr, ox), fy(fr, fr[3]) + 0.5, 0]} Math(y_name, 0.8, col)
    }
    return parts
}

# tick marks with numbers at the listed data values
let XTicks = |fr, xs, col = SLATE, places = 0| block {
    let oy = fy(fr, clamp(fr[2], 0, fr[3]))
    for (x in xs) {
        . Seg([fx(fr, x), oy - 0.07, 0], [fx(fr, x), oy + 0.07, 0], col, 2)
        . center{[fx(fr, x), oy - 0.33, 0]} Math(to_string(x, places), 0.72, col)
    }
}
let YTicks = |fr, ys, col = SLATE, places = 0| block {
    let ox = fx(fr, clamp(fr[0], 0, fr[1]))
    for (y in ys) {
        . Seg([ox - 0.07, fy(fr, y), 0], [ox + 0.07, fy(fr, y), 0], col, 2)
        . center{[ox - 0.36, fy(fr, y), 0]} Math(to_string(y, places), 0.72, col)
    }
}

# faint grid lines at the listed data values
let GridLines = |fr, xs, ys, col = MIST| block {
    for (x in xs) {
        . Seg(at(fr, x, fr[2]), at(fr, x, fr[3]), col, 1.5)
    }
    for (y in ys) {
        . Seg(at(fr, fr[0], y), at(fr, fr[1], y), col, 1.5)
    }
}

# the graph of f over [a, b], drawn in the frame. values are clamped to the window
let Graph = |fr, f, a, b, col = AZURE, w = 4, n = 160|
    stroke{col, w} Polyline(map(sample(a, b, n), |x| at(fr, x, clamp(fr[2], f(x), fr[3]))))

# the region between the graph of f and the x axis over [a, b]
let AreaUnder = |fr, f, a, b, col = AZURE, amount = 0.2, n = 80| {
    var pts = [at(fr, a, 0)]
    for (x in sample(a, b, n)) {
        pts .= at(fr, x, clamp(fr[2], f(x), fr[3]))
    }
    pts .= at(fr, b, 0)
    return fill{tint(col, amount)} stroke{alpha{0} col, 0} Polygon(pts)
}

# vectors are pairs [x, y]. a board is [o, u, x0, x1, y0, y1]: the scene point of the origin,
# the unit length, and the window of whole numbers that is drawn
let Board = |o, u, x0, x1, y0, y1| [o, u, x0, x1, y0, y1]
let P = |pl, v| [pl[0][0] + pl[1] * v[0], pl[0][1] + pl[1] * v[1], 0]
let add = |v, w| [v[0] + w[0], v[1] + w[1]]
let times = |c, v| [c * v[0], c * v[1]]
# matrices are [a, b, c, d] with rows (a b) and (c d), so the columns are (a, c) and (b, d)
let IDENT = [1, 0, 0, 1]
let apply = |m, v| [m[0] * v[0] + m[1] * v[1], m[2] * v[0] + m[3] * v[1]]
let blend = |m, n, t| [
    m[0] + (n[0] - m[0]) * t,
    m[1] + (n[1] - m[1]) * t,
    m[2] + (n[2] - m[2]) * t,
    m[3] + (n[3] - m[3]) * t
]
let GRIDC = tint(AZURE, 0.42)
# faint gridlines, both axes, and numbers along the bottom and left edges every `step`
let Ground = |pl, step = 1, mult = 1| {
    var out = []
    let lo = P(pl, [pl[2], pl[4]])
    let hi = P(pl, [pl[3], pl[5]])
    for (x in range(pl[2], pl[3] + 1)) {
        let sx = P(pl, [x, 0])[0]
        out .= Seg([sx, lo[1], 0], [sx, hi[1], 0], MIST, 1.5)
        if (mod(x, step) == 0) {
            out .= center{[sx, lo[1] - 0.27, 0]} Math(to_string(x * mult), 0.72, SLATE)
        }
    }
    for (y in range(pl[4], pl[5] + 1)) {
        let sy = P(pl, [0, y])[1]
        out .= Seg([lo[0], sy, 0], [hi[0], sy, 0], MIST, 1.5)
        if (mod(y, step) == 0) {
            out .= center{[lo[0] - 0.38, sy, 0]} Math(to_string(y * mult), 0.72, SLATE)
        }
    }
    if (pl[4] <= 0 and pl[5] >= 0) {
        out .= Seg(P(pl, [pl[2], 0]), P(pl, [pl[3], 0]), SLATE, 2.5)
    }
    if (pl[2] <= 0 and pl[3] >= 0) {
        out .= Seg(P(pl, [0, pl[4]]), P(pl, [0, pl[5]]), SLATE, 2.5)
    }
    return out
}
# the part of the segment from scene point p to q that lies in the box lo..hi
let ClipSeg = |p, q, lo, hi, col, w| {
    let d = [q[0] - p[0], q[1] - p[1]]
    var t0 = 0
    var t1 = 1
    for (k in [0, 1]) {
        if (abs(d[k]) < 0.00001) {
            if (p[k] < lo[k] - 0.0001 or p[k] > hi[k] + 0.0001) {
                t1 = -1
            }
        }
        if (abs(d[k]) >= 0.00001) {
            let ta = (lo[k] - p[k]) / d[k]
            let tb = (hi[k] - p[k]) / d[k]
            t0 = max(t0, min(ta, tb))
            t1 = min(t1, max(ta, tb))
        }
    }
    if (t1 - t0 < 0.002) {
        return []
    }
    return stroke{col, w} Line(
        [p[0] + t0 * d[0], p[1] + t0 * d[1], 0],
        [p[0] + t1 * d[0], p[1] + t1 * d[1], 0]
    )
}
# a segment between two points of the board, cut off at the window
let Cut = |pl, a, b, col = SLATE, w = 2|
    ClipSeg(P(pl, a), P(pl, b), P(pl, [pl[2], pl[4]]), P(pl, [pl[3], pl[5]]), col, w)
# the whole-number grid after the matrix m: lines along the first column in col_a, along the second in col_b
let Lines = |pl, m, col_a = GRIDC, col_b = GRIDC, n = 8| block {
    for (k in range(-n, n + 1)) {
        var w = 1.8
        if (k == 0) {
            w = 3
        }
        . Cut(pl, apply(m, [-n, k]), apply(m, [n, k]), col_a, w)
        . Cut(pl, apply(m, [k, -n]), apply(m, [k, n]), col_b, w)
    }
}
# an arrow between two points of the board
let Vec = |pl, a, b, col = INK, w = 4.5, head = 0.2| {
    let p = P(pl, a)
    let q = P(pl, b)
    if (sqrt((q[0] - p[0]) ^ 2 + (q[1] - p[1]) ^ 2) < head * 1.3) {
        return Seg(p, q, col, w)
    }
    return Tip(p, q, col, w, head)
}
# transform the grid: the matrix is t of the way from m0 to m1; the first basis arrow is blue, the second orange
let Warp = |pl, m0, m1, t| {
    let m = blend(m0, m1, t)
    return [
        Lines(pl, m),
        Vec(pl, [0, 0], [m[0], m[2]], AZURE),
        Vec(pl, [0, 0], [m[1], m[3]], EMBER)
    ]
}
let Dash = |a, b, col = SLATE, w = 2.5| stroke{col, w} dashed{[0.1, 0.08]} Line(a, b)
let clean = |x| {
    if (abs(x) < 0.005) {
        return 0
    }
    return x
}
# a 2x2 matrix readout with brackets, first column blue and second orange
let MatBox = |c, m, places = 1, s = 0.9| {
    let dx = 0.5
    let dy = 0.3
    let bx = 1.0
    let by = 0.62
    let lip = 0.13
    let q = |x, y| [c[0] + x, c[1] + y, 0]
    return [
        stroke{INK, 2.5} Polyline([q(-bx + lip, by), q(-bx, by), q(-bx, -by), q(-bx + lip, -by)]),
        stroke{INK, 2.5} Polyline([q(bx - lip, by), q(bx, by), q(bx, -by), q(bx - lip, -by)]),
        center{q(-dx, dy)} scale{s} color{AZURE} Number(clean(m[0]), places),
        center{q(dx, dy)} scale{s} color{EMBER} Number(clean(m[1]), places),
        center{q(-dx, -dy)} scale{s} color{AZURE} Number(clean(m[2]), places),
        center{q(dx, -dy)} scale{s} color{EMBER} Number(clean(m[3]), places)
    ]
}
let matmul = |m, n| [
    m[0] * n[0] + m[1] * n[2],
    m[0] * n[1] + m[1] * n[3],
    m[2] * n[0] + m[3] * n[2],
    m[2] * n[1] + m[3] * n[3]
]
# an F, so that turning and mirroring can be told apart
let FPTS = [[0.4, 0.3], [0.8, 0.3], [0.8, 1.1], [1.3, 1.1], [1.3, 1.5], [0.8, 1.5], [0.8, 1.9], [1.6, 1.9], [1.6, 2.3], [0.4, 2.3]]
let FShape = |pl, m, col = LEAF| Shape(map(FPTS, |p| P(pl, apply(m, p))), col, 0.22, 2.5)
let A = [2, 1, 0, 1]
let B2 = Board([-1.94, -0.24, 0], 0.68, -2, 5, -2, 3)
let inside = |pl, q| q[0] >= pl[2] - 0.01 and q[0] <= pl[3] + 0.01 and q[1] >= pl[4] - 0.01 and q[1] <= pl[5] + 0.01