Skip to main content

Autodiff Solver API

The autodiff_curvature module provides exact derivative computations for warp metrics using PyTorch's automatic differentiation, eliminating numerical artifacts from finite difference schemes.

Overview​

Traditional finite difference methods introduce discretization errors that become severe for warp metrics with:

  • Stiff bubble walls (σ → ∞)
  • Superluminal velocities (v > c)
  • Sharp spatial transitions

The autodiff solver computes exact analytical derivatives through the computational graph, providing:

  • ✅ Perfect accuracy - no discretization errors
  • ✅ Numerical stability - works for extreme parameters
  • ✅ GPU acceleration - optimized tensor operations
  • ✅ Automatic differentiation - exact chain rule application

Core Classes​

AutodiffCurvatureSolver​

Main solver class for computing curvature tensors using automatic differentiation.

from core.solver.autodiff_curvature import AutodiffCurvatureSolver

solver = AutodiffCurvatureSolver(device=None) # Auto-detect GPU/CPU

Methods​

get_christoffel_symbols_autodiff(g_cov, coords)​

Compute Christoffel symbols of the second kind using exact derivatives.

Formula: Γ^α_βγ = ½ g^αδ (∂_γ g_δβ + ∂_β g_δγ - ∂_δ g_βγ)

Parameters:

  • g_cov (torch.Tensor): Covariant metric tensor (4, 4, T, X, Y, Z)
  • coords (dict): Dictionary of coordinate grids {'t': t_grid, 'x': x_grid, ...}

Returns:

  • gamma (torch.Tensor): Christoffel symbols (4, 4, 4, T, X, Y, Z)

Example:

# Prepare metric with gradient-enabled coordinates
t_grid = torch.linspace(-1, 1, 10, requires_grad=True)
x_grid = torch.linspace(-5, 5, 20, requires_grad=True)
y_grid = torch.linspace(-5, 5, 20, requires_grad=True)
z_grid = torch.linspace(-5, 5, 20, requires_grad=True)

coords = {
't': t_grid.clone().detach(), # Autodiff needs gradient tracking
'x': x_grid.clone().detach(),
'y': y_grid.clone().detach(),
'z': z_grid.clone().detach()
}

# Compute exact Christoffel symbols
gamma = solver.get_christoffel_symbols_autodiff(metric.tensor, coords)
get_ricci_tensor_autodiff(g_cov, coords)​

Compute Ricci tensor using exact derivatives of Christoffel symbols.

Formula: R_μν = ∂_α Γ^α_μν - ∂_ν Γ^α_μα + Γ^α_βα Γ^β_μν - Γ^α_βν Γ^α_μα

Parameters:

  • g_cov (torch.Tensor): Covariant metric tensor
  • coords (dict): Coordinate grids with requires_grad=True

Returns:

  • R_cov (torch.Tensor): Ricci tensor (4, 4, T, X, Y, Z)

Example:

ricci = solver.get_ricci_tensor_autodiff(metric.tensor, coords)

# Analyze curvature invariants
ricci_scalar = solver.get_ricci_scalar_autodiff(metric.tensor, coords)
kretschmann = compute_kretschmann_scalar(ricci, metric)
get_ricci_scalar_autodiff(g_cov, coords)​

Compute Ricci scalar R = g^μν R_μν using autodiff.

Parameters:

  • g_cov (torch.Tensor): Covariant metric tensor
  • coords (dict): Coordinate grids

Returns:

  • R (torch.Tensor): Ricci scalar (T, X, Y, Z)

Convenience Functions​

get_christoffel_symbols()​

Unified interface supporting both autodiff and finite difference methods.

from core.solver.autodiff_curvature import get_christoffel_symbols

# Autodiff method (exact)
gamma_autodiff = get_christoffel_symbols(
g_cov=metric.tensor,
grid_scaling=metric.grid_scaling,
method="autodiff",
coords=coords # Required for autodiff
)

# Finite difference method (traditional)
gamma_fd = get_christoffel_symbols(
g_cov=metric.tensor,
grid_scaling=metric.grid_scaling,
method="finite_diff" # No coords needed
)

Preparing Metrics for Autodiff​

To use autodiff, metric tensors must be computed using gradient-enabled coordinates:

import torch
from core.metrics.alcubierre import shape_function_alcubierre

def create_autodiff_metric(grid_size, v, R, sigma):
"""Create warp metric with autodiff support"""

T, X, Y, Z = grid_size

# Enable gradients for coordinates
t = torch.linspace(0, 1, T, requires_grad=True)
x = torch.linspace(-10, 10, X, requires_grad=True)
y = torch.linspace(-10, 10, Y, requires_grad=True)
z = torch.linspace(-10, 10, Z, requires_grad=True)

# Create meshgrids
t_mesh, x_mesh, y_mesh, z_mesh = torch.meshgrid(
t, x, y, z, indexing='ij'
)

# Compute metric components using these coordinates
x_s = t_mesh * (v * C) # Bubble center movement
r = torch.sqrt((x_mesh - x_s)**2 + y_mesh**2 + z_mesh**2)

# Shape function with autodiff
f_s = shape_function_alcubierre(r, R, sigma)
beta_x = -v * f_s

# Assemble metric tensor
g = torch.zeros((4, 4, T, X, Y, Z))
g[0, 0] = -1.0 + beta_x**2
g[0, 1] = beta_x
g[1, 0] = beta_x
g[1, 1] = 1.0
g[2, 2] = 1.0
g[3, 3] = 1.0

coords = {'t': t_mesh, 'x': x_mesh, 'y': y_mesh, 'z': z_mesh}

return g, coords

# Usage
metric, coords = create_autodiff_metric((4, 16, 16, 16), v=2.5, R=4.0, sigma=50.0)

Performance Comparison​

Accuracy​

Methodσ = 5σ = 20σ = 50σ = 100
Autodiff✅ Exact✅ Exact✅ Exact✅ Exact
Finite Diff✅ Good⚠️ Degraded❌ Unstable❌ Failed

Speed​

MethodSmall Grid (16³)Medium Grid (32³)Large Grid (64³)
Autodiff~120ms~850ms~6.8s
Finite Diff~45ms~180ms~1.2s

Note: Autodiff is slower but provides exact derivatives. Use for validation or critical accuracy requirements.

Usage Guidelines​

When to Use Autodiff​

✅ Recommended for:

  • Stiff bubble walls (σ > 20)
  • Validation of finite difference results
  • Energy condition verification (avoid false positives)
  • Research publications requiring maximum accuracy
  • Novel/untested metric configurations

❌ Use Finite Difference for:

  • Large-scale exploratory simulations
  • Real-time visualization
  • Well-tested metric configurations with moderate σ
  • Performance-critical applications

Best Practices​

  1. Start with finite difference for exploration
  2. Switch to autodiff for production results
  3. Validate both methods for consistency
  4. Use autodiff when energy condition violations are suspected

Troubleshooting​

Common Issues​

"One of the differentiated Tensors appears to not have been used"​

Problem: Metric components don't depend on gradient-enabled coordinates.

Solution: Ensure metric is computed using coordinates with requires_grad=True.

CUDA Out of Memory​

Problem: Autodiff requires more memory for computational graph.

Solution:

  • Reduce grid size
  • Use float32 instead of float64
  • Process in batches

Slow Performance​

Problem: Autodiff is inherently slower than finite differences.

Solution:

  • Use smaller grids during development
  • Only use autodiff for final results
  • Consider mixed-precision computation

Examples​

Complete Example: Energy Analysis​

import torch
from core.solver.autodiff_curvature import AutodiffCurvatureSolver

def analyze_warp_energy():
"""Analyze exotic matter requirements using exact derivatives"""

# Create stiff bubble
g, coords = create_autodiff_metric(
grid_size=(4, 24, 24, 24),
v=2.0, # Superluminal
R=6.0,
sigma=80.0 # Very stiff walls
)

# Compute exact curvature
solver = AutodiffCurvatureSolver()

# Ricci tensor
R_cov = solver.get_ricci_tensor_autodiff(g, coords)

# Einstein tensor: G = R - ½Rg
R_scalar = solver.get_ricci_scalar_autodiff(g, coords)
g_inv = torch.inverse(g.permute(2,3,4,5,0,1)).permute(4,5,0,1,2,3)

G = R_cov - 0.5 * R_scalar * g_inv

# Energy tensor: T = G/(8π)
T = G / (8 * torch.pi)

# Analyze negative energy regions
negative_mask = T[0, 0] < 0 # Energy density T₀₀
negative_energy = T[0, 0][negative_mask]

print(f"Negative energy regions: {negative_mask.sum().item()}")
print(f"Max exotic density: {negative_energy.abs().max().item():.6e}")
print(f"Total exotic mass: {negative_energy.sum().item():.6e}")

return T, negative_mask

# Run analysis
energy_tensor, exotic_regions = analyze_warp_energy()

Validation Example: Method Comparison​

def validate_autodiff_accuracy():
"""Compare autodiff vs finite difference"""

# Test metric
g, coords = create_autodiff_metric((4, 16, 16, 16), v=1.5, R=4.0, sigma=30.0)

# Autodiff result
solver = AutodiffCurvatureSolver()
gamma_autodiff = solver.get_christoffel_symbols_autodiff(g, coords)

# Finite difference result
from core.solver.finite_difference import take_finite_difference_1
# ... (compute gamma_fd)

# Compare
diff = (gamma_autodiff - gamma_fd).abs()
relative_error = diff.max() / gamma_autodiff.abs().max()

print(f"Max difference: {diff.max().item():.6e}")
print(f"Relative error: {relative_error.item():.6%}")

# Autodiff should be more accurate for stiff metrics
if relative_error > 0.01: # 1% threshold
print("⚠️ Significant difference detected - autodiff recommended")
else:
print("✅ Methods agree - finite difference acceptable")

validate_autodiff_accuracy()

References​