SigmaField
Mathematical Foundations for Quant Finance
0 of 256 lessons
      1. 3.1.1 Vectors and their arithmeticConcept · 30 min
      2. 3.1.2 The dot product, length and angleConcept · 35 min
      3. 3.1.3 Practice set: vectorsPractice set · 20 min
      4. 3.1.4 Case study: portfolio returns and correlation as an angleCase study · 35 min

Level 3, Linear algebra 3.1 Vectors Lesson 3 of 4

Practice setLesson 3.1.3 in Level 3, Linear algebra. About 20 minutes.

Practice set: vectors

Vectors and their arithmetic

Vectors and their arithmetic (lesson 3.1.1)

0 of 7 correct

  1. 1.
  2. 2.
  3. 3.
  4. 4.
  5. 5.
  6. 6.
  7. 7.
How to type answers
  • Powers with ^: x^7, 2^(1/3), a^-2.
  • Multiply with * or by writing side by side: 3x^2, 2(x+1).
  • ln(x) is the natural log, log(x, 2) is log base 2, e is Euler's number, sqrt(x) is a square root.
  • sin(x), cos(x) and tan(x) take radians; write pi for π and sin(x)^2 for sin²x.
  • Your first answer to each question is saved: it counts towards your score and brings the question back for review.
  • Exact answers like ln(20)/ln(3) are best. Decimals need about 4 significant figures.

The dot product, length and angle

The dot product, length and angle (lesson 3.1.2)

0 of 7 correct

  1. 1.
  2. 2.
  3. 3.
  4. 4.
  5. 5.
  6. 6.
  7. 7.
How to type answers
  • Powers with ^: x^7, 2^(1/3), a^-2.
  • Multiply with * or by writing side by side: 3x^2, 2(x+1).
  • ln(x) is the natural log, log(x, 2) is log base 2, e is Euler's number, sqrt(x) is a square root.
  • sin(x), cos(x) and tan(x) take radians; write pi for π and sin(x)^2 for sin²x.
  • Your first answer to each question is saved: it counts towards your score and brings the question back for review.
  • Exact answers like ln(20)/ln(3) are best. Decimals need about 4 significant figures.

Coding exercise

Exercise

Unit vectors, angles and shadows

Write three functions, using lesson 3.1.2. Each takes NumPy arrays or plain lists; turn them into float arrays first with np.asarray(x, dtype=float).

  1. unit(u) returns 1∥u∥u\frac{1}{\lVert \mathbf{u} \rVert}\mathbf{u}. Raise ValueError for the zero vector.
  2. angle_deg(u, v) returns the angle between u\mathbf{u} and v\mathbf{v} in degrees. Raise ValueError if the sizes differ or either vector is zero.
  3. shadow(v, u) returns the signed length of the shadow of v\mathbf{v} on the line through u\mathbf{u}, u⋅v∥u∥\frac{\mathbf{u} \cdot \mathbf{v}}{\lVert \mathbf{u} \rVert}. Raise ValueError if the sizes differ or u\mathbf{u} is zero.

The tests include parallel and opposite vectors whose computed cosine comes out just past 1 or −1-1, so clip it into [−1,1][-1, 1] before np.arccos. They also pass lists, for which + and * would join and repeat rather than add and scale.

See the tests
import math

import numpy as np


def _raises_value_error(f, *args):
    try:
        f(*args)
    except ValueError:
        return True
    return False


def test_unit():
    """The unit vector of (3, 4) is (0.6, 0.8)"""
    expect_close(unit(np.array([3, 4])), np.array([0.6, 0.8]), what="unit((3, 4))")


def test_unit_length_one():
    """The unit vector of (2, −3, 6) has length 1 and points the same way"""
    e = unit(np.array([2, -3, 6]))
    expect_close(np.linalg.norm(e), 1.0, what="length of unit((2, −3, 6))")
    expect_close(e, np.array([2, -3, 6]) / 7, what="unit((2, −3, 6))")


def test_unit_zero():
    """The zero vector has no unit vector: ValueError"""
    assert _raises_value_error(unit, np.array([0.0, 0.0])), "expected ValueError for unit((0, 0))"


def test_angles():
    """(3, 1) makes 45° with (1, 2), 90° with (−1, 3) and 135° with (−2, 1)"""
    u = np.array([3, 1])
    expect_close(angle_deg(u, np.array([1, 2])), 45.0, what="angle between (3, 1) and (1, 2)")
    expect_close(angle_deg(u, np.array([-1, 3])), 90.0, what="angle between (3, 1) and (−1, 3)")
    expect_close(angle_deg(u, np.array([-2, 1])), 135.0, what="angle between (3, 1) and (−2, 1)")


def test_angle_r3():
    """In three dimensions, (1, 1, 0) and (0, 1, 1) make 60°"""
    expect_close(angle_deg(np.array([1, 1, 0]), np.array([0, 1, 1])), 60.0, what="angle between (1, 1, 0) and (0, 1, 1)")


def test_angle_lists():
    """Plain lists work too: [3, 1] and [1, 2] make 45°"""
    expect_close(angle_deg([3, 1], [1, 2]), 45.0, what="angle_deg([3, 1], [1, 2])")


def test_parallel():
    """Parallel vectors give 0° and opposite ones 180°, even when rounding pushes the cosine past ±1"""
    for given, c in [([3, 1], 0.1), ([3, 1], 1.3), ([1, 2, 3], 1.1), ([2, 3, 6], 0.3), ([1, 1, 1], 1.3)]:
        u = np.array(given, dtype=float)
        same = angle_deg(u, c * u)
        assert not math.isnan(same), f"the angle between {given} and {c} times it came out as nan: clip the cosine into [−1, 1]"
        expect_close(same, 0.0, what=f"angle between {given} and {c} times it", abs_tol=1e-6)
        opposite = angle_deg(u, -c * u)
        assert not math.isnan(opposite), f"the angle between {given} and −{c} times it came out as nan: clip the cosine into [−1, 1]"
        expect_close(opposite, 180.0, what=f"angle between {given} and −{c} times it", abs_tol=1e-6)


def test_angle_zero_vector():
    """A zero vector has no angle: ValueError"""
    assert _raises_value_error(angle_deg, np.array([0, 0]), np.array([1, 2])), "expected ValueError when u is (0, 0)"
    assert _raises_value_error(angle_deg, np.array([3, 1]), np.array([0, 0])), "expected ValueError when v is (0, 0)"


def test_angle_sizes():
    """Vectors of different sizes have no angle: ValueError"""
    assert _raises_value_error(angle_deg, np.array([1, 2]), np.array([1, 2, 3])), "expected ValueError for (1, 2) and (1, 2, 3)"


def test_shadow():
    """The shadow of (1, 2) on (3, 1) has length 5/√10, and of (−2, 1) it is −5/√10"""
    expect_close(shadow(np.array([1, 2]), np.array([3, 1])), 5 / math.sqrt(10), what="shadow of (1, 2) on (3, 1)")
    expect_close(shadow(np.array([-2, 1]), np.array([3, 1])), -5 / math.sqrt(10), what="shadow of (−2, 1) on (3, 1)")


def test_shadow_divides_by_u():
    """The shadow of (1, 7) on (3, 4) is 6.2: divide by the length of (3, 4)"""
    expect_close(shadow(np.array([1, 7]), np.array([3, 4])), 6.2, what="shadow of (1, 7) on (3, 4)")


def test_shadow_bad_inputs():
    """No line through the zero vector, and no shadow across sizes: ValueError"""
    assert _raises_value_error(shadow, np.array([1, 2]), np.array([0, 0])), "expected ValueError when u is (0, 0)"
    assert _raises_value_error(shadow, np.array([1, 2, 3]), np.array([3, 1])), "expected ValueError for sizes 3 and 2"

Free further reading

Optional. This lesson covers what you need; these add more examples and practice. All are free to read.