Welcome back to Artintellica’s open-source Reinforcement Learning course with PyTorch! Having mastered creating, reshaping, and visualizing vectors and scalars in the previous post, we’re now ready to perform fundamental operations on them. Today, we’ll explore vector addition, scalar multiplication, and the dot product—operations that are at the heart of nearly every computation in machine learning and reinforcement learning (RL).
In this post, you will:
These operations are building blocks for everything from updating agent parameters in RL to computing rewards or state transitions. Let’s dive in!
Let’s start with the mathematical foundations of the operations we’ll implement. We’ll use vectors in , meaning they have components.
Given two vectors and of the same dimension, their sum is defined element-wise:
Geometrically, this corresponds to placing the tail of at the head of and finding the resulting vector from the tail of to the head of .
Multiplying a vector by a scalar scales each component:
Geometrically, this stretches (if ), shrinks (if ), or reverses (if ) the vector while keeping its direction (or flipping it if negative).
The dot product of two vectors and of the same dimension is a scalar value computed as:
Geometrically, it measures how much one vector “goes in the direction” of another and is related to the angle between them via:
where is the magnitude (Euclidean norm) of . In RL, dot products are often used in similarity measures or projections.
Let’s implement these operations using PyTorch tensors. We’ll work with small vectors for clarity, but these operations scale to any dimension.
import torch
# Define two vectors
u: torch.Tensor = torch.tensor([1.0, 2.0, 3.0])
v: torch.Tensor = torch.tensor([4.0, 5.0, 6.0])
# Element-wise addition
w: torch.Tensor = u + v
print("u:", u)
print("v:", v)
print("u + v:", w)
Expected Output:
u: tensor([1., 2., 3.])
v: tensor([4., 5., 6.])
u + v: tensor([5., 7., 9.])
# Scalar multiplication
c: float = 2.0
scaled_u: torch.Tensor = c * u
print(f"u scaled by {c}:", scaled_u)
Expected Output:
u scaled by 2.0: tensor([2., 4., 6.])
PyTorch uses broadcasting to apply the scalar across all elements, so you don’t need to loop manually.
# Manual dot product using element-wise multiplication and sum
manual_dot: torch.Tensor = (u * v).sum()
print("Manual dot product (u · v):", manual_dot.item())
# Built-in dot product
builtin_dot: torch.Tensor = torch.dot(u, v)
print("Built-in dot product (u · v):", builtin_dot.item())
Expected Output:
Manual dot product (u · v): 32.0
Built-in dot product (u · v): 32.0
Both methods yield the same result: .
Visualization helps build geometric intuition. We’ll use 2D vectors for simplicity.
import matplotlib.pyplot as plt
# 2D vectors
u_2d: torch.Tensor = torch.tensor([1.0, 2.0])
v_2d: torch.Tensor = torch.tensor([2.0, 1.0])
sum_uv: torch.Tensor = u_2d + v_2d
scaled_u: torch.Tensor = 1.5 * u_2d
# Plotting
plt.figure(figsize=(6, 6))
plt.quiver(0, 0, u_2d[0], u_2d[1], angles='xy', scale_units='xy', scale=1, color='b', label='u')
plt.quiver(0, 0, v_2d[0], v_2d[1], angles='xy', scale_units='xy', scale=1, color='r', label='v')
plt.quiver(0, 0, sum_uv[0], sum_uv[1], angles='xy', scale_units='xy', scale=1, color='g', label='u + v')
plt.quiver(0, 0, scaled_u[0], scaled_u[1], angles='xy', scale_units='xy', scale=1, color='purple', label='1.5 * u')
plt.xlim(-1, 4)
plt.ylim(-1, 4)
plt.grid(True)
plt.axhline(0, color='black', linewidth=0.5)
plt.axvline(0, color='black', linewidth=0.5)
plt.title("Vector Addition and Scalar Multiplication in 2D")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.show()
This plots vectors as arrows from the origin, showing how addition forms a parallelogram resultant and how scaling stretches a vector.
Let’s apply what you’ve learned with hands-on coding tasks. Use a new Python script or Jupyter notebook for these exercises.
torch.dot
function.plt.quiver
as arrows from the origin, with different
colors and a legend.import torch
import matplotlib.pyplot as plt
# EXERCISE 1: Vector Addition
a: torch.Tensor = torch.tensor([2.0, 3.0, 4.0, 5.0])
b: torch.Tensor = torch.tensor([1.0, 1.0, 1.0, 1.0])
c: torch.Tensor = a + b
print("a:", a)
print("b:", b)
print("c = a + b:", c)
# EXERCISE 2: Scalar Multiplication
c_scalar: float = 3.0
# Manual scaling (using element-wise operation for simplicity)
manual_scaled_a: torch.Tensor = torch.tensor([c_scalar * x for x in a])
# Broadcasting scaling
broadcast_scaled_a: torch.Tensor = c_scalar * a
print("Manually scaled a:", manual_scaled_a)
print("Broadcast scaled a:", broadcast_scaled_a)
# EXERCISE 3: Dot Product
manual_dot: torch.Tensor = (a * b).sum()
builtin_dot: torch.Tensor = torch.dot(a, b)
print("Manual dot product (a · b):", manual_dot.item())
print("Built-in dot product (a · b):", builtin_dot.item())
# EXERCISE 4: Visualization in 2D
d: torch.Tensor = torch.tensor([1.0, 3.0])
e: torch.Tensor = torch.tensor([2.0, 1.0])
f: torch.Tensor = d + e
scaled_d: torch.Tensor = 0.5 * d
plt.figure(figsize=(6, 6))
plt.quiver(0, 0, d[0], d[1], angles='xy', scale_units='xy', scale=1, color='b', label='d')
plt.quiver(0, 0, e[0], e[1], angles='xy', scale_units='xy', scale=1, color='r', label='e')
plt.quiver(0, 0, f[0], f[1], angles='xy', scale_units='xy', scale=1, color='g', label='d + e')
plt.quiver(0, 0, scaled_d[0], scaled_d[1], angles='xy', scale_units='xy', scale=1, color='purple', label='0.5 * d')
plt.xlim(-1, 4)
plt.ylim(-1, 4)
plt.grid(True)
plt.axhline(0, color='black', linewidth=0.5)
plt.axvline(0, color='black', linewidth=0.5)
plt.title("Vector Operations in 2D")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.show()
In this post, you’ve taken a significant step forward by mastering basic vector operations—addition, scalar multiplication, and the dot product—using PyTorch. These operations are not just mathematical abstractions; they are the foundation of nearly every computation in reinforcement learning, from updating policies to computing value functions.
Next Up: In Part 1.4, we’ll extend these concepts to matrices—2D tensors that represent linear transformations and are critical for neural networks and state transitions in RL. Keep practicing these vector operations, as they’ll be essential for everything to come!
See you in the next post!