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 tensorcoords(dict): Coordinate grids withrequires_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 tensorcoords(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
| Method | Small 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
- Start with finite difference for exploration
- Switch to autodiff for production results
- Validate both methods for consistency
- 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
float32instead offloat64 - 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()