Skip to content

Instantly share code, notes, and snippets.

@tang-hi
Created May 18, 2025 14:53
Show Gist options
  • Select an option

  • Save tang-hi/3ef51ddab75961a3a80304aeec348bd9 to your computer and use it in GitHub Desktop.

Select an option

Save tang-hi/3ef51ddab75961a3a80304aeec348bd9 to your computer and use it in GitHub Desktop.
angle-dimension
import numpy as np
import matplotlib.pyplot as plt
def angle_between_vectors(v1, v2):
"""Calculates the angle in degrees between two vectors."""
v1_u = v1 / np.linalg.norm(v1)
v2_u = v2 / np.linalg.norm(v2)
dot_product = np.dot(v1_u, v2_u)
# Clip dot_product to avoid acos domain errors due to floating point inaccuracies
clipped_dot_product = np.clip(dot_product, -1.0, 1.0)
angle_radians = np.arccos(clipped_dot_product)
angle_degrees = np.degrees(angle_radians)
return angle_degrees
# Parameters for the experiment
dimensions = [2, 10, 100, 1000]
num_vector_pairs = 10000 # Number of random vector pairs to generate for each dimension
num_bins = 60 # Number of bins for the histogram
plt.figure(figsize=(12, 7))
for dim in dimensions:
angles = []
for _ in range(num_vector_pairs):
# Generate two random vectors.
# Components are drawn from a standard normal distribution (mean 0, variance 1).
# This ensures that vector directions are uniformly distributed on the hypersphere.
vec1 = np.random.randn(dim)
vec2 = np.random.randn(dim)
# Calculate the angle between the two vectors
if np.linalg.norm(vec1) > 0 and np.linalg.norm(vec2) > 0: # Avoid zero vectors
angle = angle_between_vectors(vec1, vec2)
angles.append(angle)
else:
# This case should be rare with randn but good to be safe
continue
# Plot the histogram of angles for the current dimension
# density=True normalizes the histogram to form a probability density
plt.hist(angles, bins=num_bins, density=True, histtype='step', linewidth=1.5, label=f'Dimension = {dim}')
plt.title('Angle Distribution Between Random Vectors')
plt.xlabel('Angle (Degrees)')
plt.ylabel('Frequency Density')
plt.legend(title='Vector Dimensionality')
plt.grid(True, linestyle='--', alpha=0.6)
plt.xlim(0, 180) # Angles range from 0 to 180 degrees
# Highlight the 90-degree mark
plt.axvline(90, color='black', linestyle='dashed', linewidth=1, label='90 Degrees (Orthogonal)')
# Ensure 90 is a tick on the x-axis for clarity
current_ticks = list(plt.xticks()[0])
if 90 not in current_ticks:
current_ticks.append(90)
current_ticks.sort()
plt.xticks(current_ticks)
# Adjust legend to include the axvline if needed, or ensure it's clear
handles, labels = plt.gca().get_legend_handles_labels()
# The axvline doesn't automatically add to legend this way, so we'll rely on its visual distinctness
# Or, we can add it manually if really needed, but it might clutter.
# For now, the existing legend for dimensions is primary.
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment