Private notes
0/8000

Notes stay private to your browser until account sync is configured.

Theory Notebook
3 min read18 headings

Theory Notebook

Converted from theory.ipynb for web reading.

Riemannian Geometry

Riemannian geometry adds smoothly varying inner products to manifolds, making gradients, distances, curvature, and natural-gradient learning coordinate-aware.

This notebook is the executable companion to notes.md. It uses spheres, tangent projections, geodesic interpolation, SPD matrices, and orthogonality constraints as concrete geometry laboratories.

Code cell 2

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

try:
    import seaborn as sns
    sns.set_theme(style="whitegrid", palette="colorblind")
    HAS_SNS = True
except ImportError:
    plt.style.use("seaborn-v0_8-whitegrid")
    HAS_SNS = False

mpl.rcParams.update({
    "figure.figsize":    (10, 6),
    "figure.dpi":         120,
    "font.size":           13,
    "axes.titlesize":      15,
    "axes.labelsize":      13,
    "xtick.labelsize":     11,
    "ytick.labelsize":     11,
    "legend.fontsize":     11,
    "legend.framealpha":   0.85,
    "lines.linewidth":      2.0,
    "axes.spines.top":     False,
    "axes.spines.right":   False,
    "savefig.bbox":       "tight",
    "savefig.dpi":         150,
})
np.random.seed(42)
print("Plot setup complete.")

Code cell 3


COLORS = {
    "primary":   "#0077BB",
    "secondary": "#EE7733",
    "tertiary":  "#009988",
    "error":     "#CC3311",
    "neutral":   "#555555",
    "highlight": "#EE3377",
}

def header(title):
    print("\n" + "=" * 72)
    print(title)
    print("=" * 72)

def check_true(condition, name):
    ok = bool(condition)
    print(f"{'PASS' if ok else 'FAIL'} - {name}")
    assert ok, name

def check_close(value, target, tol=1e-8, name="value"):
    ok = abs(float(value) - float(target)) <= tol
    print(f"{'PASS' if ok else 'FAIL'} - {name}: got {float(value):.6f}, expected {float(target):.6f}")
    assert ok, name

def normalize(x):
    x = np.asarray(x, dtype=float)
    n = np.linalg.norm(x)
    if n == 0:
        raise ValueError("cannot normalize zero vector")
    return x / n

def tangent_projection_sphere(x, v):
    x = normalize(x)
    v = np.asarray(v, dtype=float)
    return v - np.dot(x, v) * x

def exp_sphere(x, v):
    x = normalize(x)
    v = tangent_projection_sphere(x, v)
    n = np.linalg.norm(v)
    if n < 1e-12:
        return x.copy()
    return np.cos(n) * x + np.sin(n) * v / n

def retract_sphere(x, v):
    return normalize(np.asarray(x, dtype=float) + np.asarray(v, dtype=float))

def slerp(x, y, t):
    x = normalize(x)
    y = normalize(y)
    dot = np.clip(np.dot(x, y), -1.0, 1.0)
    theta = np.arccos(dot)
    if theta < 1e-12:
        return x.copy()
    return (np.sin((1 - t) * theta) * x + np.sin(t * theta) * y) / np.sin(theta)

def riemannian_gradient_sphere(x, euclidean_grad):
    return tangent_projection_sphere(x, euclidean_grad)

def sphere_descent(target, steps=20, eta=0.3):
    target = normalize(target)
    x = normalize(np.array([1.0, 0.2, 0.1]))
    values = []
    for _ in range(steps):
        values.append(float(-np.dot(target, x)))
        egrad = -target
        rgrad = riemannian_gradient_sphere(x, egrad)
        x = retract_sphere(x, -eta * rgrad)
    values.append(float(-np.dot(target, x)))
    return x, np.array(values)

def stiefel_tangent_projection(Q, Z):
    Q = np.asarray(Q, dtype=float)
    Z = np.asarray(Z, dtype=float)
    sym = 0.5 * (Q.T @ Z + Z.T @ Q)
    return Z - Q @ sym

def qr_retraction(Y):
    Q, R = np.linalg.qr(Y)
    signs = np.sign(np.diag(R))
    signs[signs == 0] = 1.0
    return Q @ np.diag(signs)

def spd_from_eigs(eigs):
    Q = np.array([[np.cos(0.4), -np.sin(0.4)], [np.sin(0.4), np.cos(0.4)]])
    return Q @ np.diag(eigs) @ Q.T

def mat_log_spd(A):
    vals, vecs = np.linalg.eigh(A)
    return vecs @ np.diag(np.log(vals)) @ vecs.T

def mat_invsqrt_spd(A):
    vals, vecs = np.linalg.eigh(A)
    return vecs @ np.diag(1.0 / np.sqrt(vals)) @ vecs.T

def spd_distance(A, B):
    C = mat_invsqrt_spd(A) @ B @ mat_invsqrt_spd(A)
    return float(np.linalg.norm(mat_log_spd(C), ord="fro"))

print("Differential-geometry helpers ready.")

Demo 1: Adding inner products to tangent spaces

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 5

header("Demo 1 - Adding inner products to tangent spaces: sphere tangent projection")
x = normalize(np.array([1.0, 1.0, 1.0]))
v = np.array([2.0, -1.0, 0.5])
tangent = tangent_projection_sphere(x, v)
print("Point on sphere:", np.round(x, 3).tolist())
print("Projected tangent:", np.round(tangent, 3).tolist())
check_close(np.dot(x, tangent), 0.0, tol=1e-10, name="orthogonal to base point")

Demo 2: Length angle and distance on curved spaces

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 7

header("Demo 2 - Length angle and distance on curved spaces: local chart for circle")
theta = np.linspace(-1.2, 1.2, 200)
circle = np.column_stack([np.cos(theta), np.sin(theta)])
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(circle[:, 0], circle[:, 1], color=COLORS["primary"], label="chart image")
ax.scatter([1], [0], color=COLORS["highlight"], label="base point")
ax.set_title("Local coordinate patch on the circle")
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.axis("equal")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)
print("Chart parameter range:", (float(theta.min()), float(theta.max())))
check_true(circle.shape == (200, 2), "chart maps one coordinate to ambient R^2")

Demo 3: Why Euclidean gradients are coordinate-dependent

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 9

header("Demo 3 - Why Euclidean gradients are coordinate-dependent: spherical geodesic interpolation")
x = normalize(np.array([1.0, 0.0, 0.0]))
y = normalize(np.array([0.0, 1.0, 0.0]))
pts = np.array([slerp(x, y, t) for t in np.linspace(0, 1, 25)])
norms = np.linalg.norm(pts, axis=1)
print("First point:", pts[0].round(3).tolist())
print("Middle point:", pts[len(pts)//2].round(3).tolist())
check_true(np.all(np.abs(norms - 1.0) < 1e-10), "slerp stays on sphere")
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(pts[:, 0], pts[:, 1], color=COLORS["secondary"], marker="o", label="geodesic arc")
ax.set_title("Great-circle interpolation")
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.axis("equal")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)

Demo 4: Curvature as changing geometry

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 11

header("Demo 4 - Curvature as changing geometry: Riemannian gradient on sphere")
x = normalize(np.array([0.7, 0.2, 0.6]))
target = normalize(np.array([0.0, 1.0, 0.0]))
egrad = -target
rgrad = riemannian_gradient_sphere(x, egrad)
print("Euclidean gradient:", np.round(egrad, 3).tolist())
print("Riemannian gradient:", np.round(rgrad, 3).tolist())
check_close(np.dot(x, rgrad), 0.0, tol=1e-10, name="Riemannian gradient is tangent")
print("Interpretation: steepest descent must live in the tangent space.")

Demo 5: Information geometry and natural gradients

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 13

header("Demo 5 - Information geometry and natural gradients: sphere gradient descent")
target = np.array([0.0, 1.0, 0.0])
x_final, values = sphere_descent(target, steps=25, eta=0.25)
print("Final point:", np.round(x_final, 3).tolist())
print("Initial objective:", round(values[0], 4))
print("Final objective:", round(values[-1], 4))
check_true(values[-1] < values[0], "objective decreases on sphere")
fig, ax = plt.subplots()
ax.plot(values, color=COLORS["primary"], label="objective")
ax.set_title("Riemannian gradient descent on the sphere")
ax.set_xlabel("Step")
ax.set_ylabel("$-a^T x$")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)

Demo 6: Riemannian metric gp(,)g_p(\cdot,\cdot)

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 15

header("Demo 6 - Riemannian metric $g_p(\\cdot,\\cdot)$: Stiefel tangent projection")
Q = np.eye(3, 2)
Z = np.array([[0.2, 1.0], [1.5, -0.3], [0.7, 0.4]])
Xi = stiefel_tangent_projection(Q, Z)
constraint = Q.T @ Xi + Xi.T @ Q
print("Tangent constraint matrix:", np.round(constraint, 10))
check_true(np.linalg.norm(constraint) < 1e-10, "Stiefel tangent condition holds")
Y = qr_retraction(Q + 0.2 * Xi)
check_true(np.linalg.norm(Y.T @ Y - np.eye(2)) < 1e-10, "QR retraction returns orthonormal columns")
print("Retracted columns are orthonormal.")

Demo 7: Riemannian manifold (M,g)(M,g)

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 17

header("Demo 7 - Riemannian manifold $(M,g)$: SPD manifold distance")
A = spd_from_eigs([1.0, 3.0])
B = spd_from_eigs([2.0, 5.0])
d_ab = spd_distance(A, B)
d_ba = spd_distance(B, A)
print("Distance A to B:", round(d_ab, 6))
print("Distance B to A:", round(d_ba, 6))
check_close(d_ab, d_ba, tol=1e-10, name="SPD distance symmetry")
check_true(d_ab > 0, "distinct SPD matrices have positive distance")

Demo 8: Length of curves and induced distance

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 19

header("Demo 8 - Length of curves and induced distance: exponential vs retraction")
x = normalize(np.array([1.0, 0.0, 0.0]))
v = tangent_projection_sphere(x, np.array([0.0, 0.2, 0.1]))
exp_point = exp_sphere(x, v)
ret_point = retract_sphere(x, v)
print("Exponential point:", np.round(exp_point, 5).tolist())
print("Retraction point:", np.round(ret_point, 5).tolist())
check_true(abs(np.linalg.norm(exp_point) - 1.0) < 1e-10, "exponential stays on sphere")
check_true(abs(np.linalg.norm(ret_point) - 1.0) < 1e-10, "retraction stays on sphere")
print("Distance between exp and retraction:", round(float(np.linalg.norm(exp_point - ret_point)), 6))

Demo 9: Riemannian gradient gradf\operatorname{grad} f

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 21

header("Demo 9 - Riemannian gradient $\\operatorname{grad} f$: sphere tangent projection")
x = normalize(np.array([1.0, 1.0, 1.0]))
v = np.array([2.0, -1.0, 0.5])
tangent = tangent_projection_sphere(x, v)
print("Point on sphere:", np.round(x, 3).tolist())
print("Projected tangent:", np.round(tangent, 3).tolist())
check_close(np.dot(x, tangent), 0.0, tol=1e-10, name="orthogonal to base point")

Demo 10: Volume forms and integration preview

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 23

header("Demo 10 - Volume forms and integration preview: local chart for circle")
theta = np.linspace(-1.2, 1.2, 200)
circle = np.column_stack([np.cos(theta), np.sin(theta)])
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(circle[:, 0], circle[:, 1], color=COLORS["primary"], label="chart image")
ax.scatter([1], [0], color=COLORS["highlight"], label="base point")
ax.set_title("Local coordinate patch on the circle")
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.axis("equal")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)
print("Chart parameter range:", (float(theta.min()), float(theta.max())))
check_true(circle.shape == (200, 2), "chart maps one coordinate to ambient R^2")

Demo 11: Metric tensor in coordinates

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 25

header("Demo 11 - Metric tensor in coordinates: spherical geodesic interpolation")
x = normalize(np.array([1.0, 0.0, 0.0]))
y = normalize(np.array([0.0, 1.0, 0.0]))
pts = np.array([slerp(x, y, t) for t in np.linspace(0, 1, 25)])
norms = np.linalg.norm(pts, axis=1)
print("First point:", pts[0].round(3).tolist())
print("Middle point:", pts[len(pts)//2].round(3).tolist())
check_true(np.all(np.abs(norms - 1.0) < 1e-10), "slerp stays on sphere")
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(pts[:, 0], pts[:, 1], color=COLORS["secondary"], marker="o", label="geodesic arc")
ax.set_title("Great-circle interpolation")
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.axis("equal")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)

Demo 12: Musical isomorphisms and gradient representation

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 27

header("Demo 12 - Musical isomorphisms and gradient representation: Riemannian gradient on sphere")
x = normalize(np.array([0.7, 0.2, 0.6]))
target = normalize(np.array([0.0, 1.0, 0.0]))
egrad = -target
rgrad = riemannian_gradient_sphere(x, egrad)
print("Euclidean gradient:", np.round(egrad, 3).tolist())
print("Riemannian gradient:", np.round(rgrad, 3).tolist())
check_close(np.dot(x, rgrad), 0.0, tol=1e-10, name="Riemannian gradient is tangent")
print("Interpretation: steepest descent must live in the tangent space.")

Demo 13: Levi-Civita connection preview

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 29

header("Demo 13 - Levi-Civita connection preview: sphere gradient descent")
target = np.array([0.0, 1.0, 0.0])
x_final, values = sphere_descent(target, steps=25, eta=0.25)
print("Final point:", np.round(x_final, 3).tolist())
print("Initial objective:", round(values[0], 4))
print("Final objective:", round(values[-1], 4))
check_true(values[-1] < values[0], "objective decreases on sphere")
fig, ax = plt.subplots()
ax.plot(values, color=COLORS["primary"], label="objective")
ax.set_title("Riemannian gradient descent on the sphere")
ax.set_xlabel("Step")
ax.set_ylabel("$-a^T x$")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)

Demo 14: Covariant derivative intuition

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 31

header("Demo 14 - Covariant derivative intuition: Stiefel tangent projection")
Q = np.eye(3, 2)
Z = np.array([[0.2, 1.0], [1.5, -0.3], [0.7, 0.4]])
Xi = stiefel_tangent_projection(Q, Z)
constraint = Q.T @ Xi + Xi.T @ Q
print("Tangent constraint matrix:", np.round(constraint, 10))
check_true(np.linalg.norm(constraint) < 1e-10, "Stiefel tangent condition holds")
Y = qr_retraction(Q + 0.2 * Xi)
check_true(np.linalg.norm(Y.T @ Y - np.eye(2)) < 1e-10, "QR retraction returns orthonormal columns")
print("Retracted columns are orthonormal.")

Demo 15: Curvature: sectional Ricci scalar preview

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 33

header("Demo 15 - Curvature: sectional Ricci scalar preview: SPD manifold distance")
A = spd_from_eigs([1.0, 3.0])
B = spd_from_eigs([2.0, 5.0])
d_ab = spd_distance(A, B)
d_ba = spd_distance(B, A)
print("Distance A to B:", round(d_ab, 6))
print("Distance B to A:", round(d_ba, 6))
check_close(d_ab, d_ba, tol=1e-10, name="SPD distance symmetry")
check_true(d_ab > 0, "distinct SPD matrices have positive distance")

Demo 16: Fisher metric and natural gradient

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 35

header("Demo 16 - Fisher metric and natural gradient: exponential vs retraction")
x = normalize(np.array([1.0, 0.0, 0.0]))
v = tangent_projection_sphere(x, np.array([0.0, 0.2, 0.1]))
exp_point = exp_sphere(x, v)
ret_point = retract_sphere(x, v)
print("Exponential point:", np.round(exp_point, 5).tolist())
print("Retraction point:", np.round(ret_point, 5).tolist())
check_true(abs(np.linalg.norm(exp_point) - 1.0) < 1e-10, "exponential stays on sphere")
check_true(abs(np.linalg.norm(ret_point) - 1.0) < 1e-10, "retraction stays on sphere")
print("Distance between exp and retraction:", round(float(np.linalg.norm(exp_point - ret_point)), 6))

Demo 17: Hyperbolic embeddings for hierarchies

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 37

header("Demo 17 - Hyperbolic embeddings for hierarchies: sphere tangent projection")
x = normalize(np.array([1.0, 1.0, 1.0]))
v = np.array([2.0, -1.0, 0.5])
tangent = tangent_projection_sphere(x, v)
print("Point on sphere:", np.round(x, 3).tolist())
print("Projected tangent:", np.round(tangent, 3).tolist())
check_close(np.dot(x, tangent), 0.0, tol=1e-10, name="orthogonal to base point")

Demo 18: SPD covariance manifolds

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 39

header("Demo 18 - SPD covariance manifolds: local chart for circle")
theta = np.linspace(-1.2, 1.2, 200)
circle = np.column_stack([np.cos(theta), np.sin(theta)])
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(circle[:, 0], circle[:, 1], color=COLORS["primary"], label="chart image")
ax.scatter([1], [0], color=COLORS["highlight"], label="base point")
ax.set_title("Local coordinate patch on the circle")
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.axis("equal")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)
print("Chart parameter range:", (float(theta.min()), float(theta.max())))
check_true(circle.shape == (200, 2), "chart maps one coordinate to ambient R^2")

Demo 19: Wasserstein and information-geometric intuition

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 41

header("Demo 19 - Wasserstein and information-geometric intuition: spherical geodesic interpolation")
x = normalize(np.array([1.0, 0.0, 0.0]))
y = normalize(np.array([0.0, 1.0, 0.0]))
pts = np.array([slerp(x, y, t) for t in np.linspace(0, 1, 25)])
norms = np.linalg.norm(pts, axis=1)
print("First point:", pts[0].round(3).tolist())
print("Middle point:", pts[len(pts)//2].round(3).tolist())
check_true(np.all(np.abs(norms - 1.0) < 1e-10), "slerp stays on sphere")
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(pts[:, 0], pts[:, 1], color=COLORS["secondary"], marker="o", label="geodesic arc")
ax.set_title("Great-circle interpolation")
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.axis("equal")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)

Demo 20: Geometry-aware regularization

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 43

header("Demo 20 - Geometry-aware regularization: Riemannian gradient on sphere")
x = normalize(np.array([0.7, 0.2, 0.6]))
target = normalize(np.array([0.0, 1.0, 0.0]))
egrad = -target
rgrad = riemannian_gradient_sphere(x, egrad)
print("Euclidean gradient:", np.round(egrad, 3).tolist())
print("Riemannian gradient:", np.round(rgrad, 3).tolist())
check_close(np.dot(x, rgrad), 0.0, tol=1e-10, name="Riemannian gradient is tangent")
print("Interpretation: steepest descent must live in the tangent space.")

Demo 21: Adding inner products to tangent spaces

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 45

header("Demo 21 - Adding inner products to tangent spaces: sphere gradient descent")
target = np.array([0.0, 1.0, 0.0])
x_final, values = sphere_descent(target, steps=25, eta=0.25)
print("Final point:", np.round(x_final, 3).tolist())
print("Initial objective:", round(values[0], 4))
print("Final objective:", round(values[-1], 4))
check_true(values[-1] < values[0], "objective decreases on sphere")
fig, ax = plt.subplots()
ax.plot(values, color=COLORS["primary"], label="objective")
ax.set_title("Riemannian gradient descent on the sphere")
ax.set_xlabel("Step")
ax.set_ylabel("$-a^T x$")
ax.legend()
fig.tight_layout()
plt.show()
plt.close(fig)

Demo 22: Length angle and distance on curved spaces

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 47

header("Demo 22 - Length angle and distance on curved spaces: Stiefel tangent projection")
Q = np.eye(3, 2)
Z = np.array([[0.2, 1.0], [1.5, -0.3], [0.7, 0.4]])
Xi = stiefel_tangent_projection(Q, Z)
constraint = Q.T @ Xi + Xi.T @ Q
print("Tangent constraint matrix:", np.round(constraint, 10))
check_true(np.linalg.norm(constraint) < 1e-10, "Stiefel tangent condition holds")
Y = qr_retraction(Q + 0.2 * Xi)
check_true(np.linalg.norm(Y.T @ Y - np.eye(2)) < 1e-10, "QR retraction returns orthonormal columns")
print("Retracted columns are orthonormal.")

Demo 23: Why Euclidean gradients are coordinate-dependent

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 49

header("Demo 23 - Why Euclidean gradients are coordinate-dependent: SPD manifold distance")
A = spd_from_eigs([1.0, 3.0])
B = spd_from_eigs([2.0, 5.0])
d_ab = spd_distance(A, B)
d_ba = spd_distance(B, A)
print("Distance A to B:", round(d_ab, 6))
print("Distance B to A:", round(d_ba, 6))
check_close(d_ab, d_ba, tol=1e-10, name="SPD distance symmetry")
check_true(d_ab > 0, "distinct SPD matrices have positive distance")

Demo 24: Curvature as changing geometry

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 51

header("Demo 24 - Curvature as changing geometry: exponential vs retraction")
x = normalize(np.array([1.0, 0.0, 0.0]))
v = tangent_projection_sphere(x, np.array([0.0, 0.2, 0.1]))
exp_point = exp_sphere(x, v)
ret_point = retract_sphere(x, v)
print("Exponential point:", np.round(exp_point, 5).tolist())
print("Retraction point:", np.round(ret_point, 5).tolist())
check_true(abs(np.linalg.norm(exp_point) - 1.0) < 1e-10, "exponential stays on sphere")
check_true(abs(np.linalg.norm(ret_point) - 1.0) < 1e-10, "retraction stays on sphere")
print("Distance between exp and retraction:", round(float(np.linalg.norm(exp_point - ret_point)), 6))

Demo 25: Information geometry and natural gradients

This demo turns the approved TOC concept into a small executable geometric calculation.

Code cell 53

header("Demo 25 - Information geometry and natural gradients: sphere tangent projection")
x = normalize(np.array([1.0, 1.0, 1.0]))
v = np.array([2.0, -1.0, 0.5])
tangent = tangent_projection_sphere(x, v)
print("Point on sphere:", np.round(x, 3).tolist())
print("Projected tangent:", np.round(tangent, 3).tolist())
check_close(np.dot(x, tangent), 0.0, tol=1e-10, name="orthogonal to base point")

Skill Check

Test this lesson

Answer 4 quick questions to lock in the lesson and feed your adaptive practice queue.

--
Score
0/4
Answered
Not attempted
Status
1

Which module does this lesson belong to?

2

Which section is covered in this lesson content?

3

Which term is most central to this lesson?

4

What is the best way to use this lesson for real learning?

Your answers save locally first, then sync when account storage is available.
Practice queue