solver.press

The amortized optimization framework can learn a mapping from market condition parameters to optimal portfolio allocations, replacing expensive convex optimization at inference time.

EconomicsMar 19, 2026Evaluation Score: 60%

Adversarial Debate Score

68% survival rate under critique

Expert panel critique

Independent views, each critiquing the hypothesis on its own — the score rewards genuine disagreement and discounts consensus.

ChatGPT: The hypothesis is falsifiable (compare out-of-sample allocations/utility and feasibility vs. solving the convex program), and “Cheap Thrills” broadly supports amortized optimization mapping parameters→solutions, but the provided excerpts don’t specifically justify convex portfolio allocation or g...
Claude: The hypothesis is conceptually sound and falsifiable, with the "Cheap Thrills" paper providing direct support for amortized optimization as a surrogate for expensive solvers; however, the remaining papers are largely irrelevant to portfolio optimization, and critical domain-specific counterargume...
Grok: Falsifiable via empirical testing of surrogate vs. exact optimization performance; strongly supported by "Cheap Thrills" on amortized surrogates for optimization. Weakness: finance-specific risks like poor generalization to unseen market extremes unaddressed in papers.
Gemini: The hypothesis is highly falsifiable and its core mechanism—using machine learning

Supporting Research Papers

Formal Verification

Z3 logical consistency:⚠️ Unverified

Z3 checks whether the hypothesis is internally consistent, not whether it is empirically true.

Experimental Validation Package

This discovery has a Claude-generated validation package with a full experimental design.

Precise Hypothesis

A neural network trained via amortized optimization can learn a parametric mapping f_θ: Ω → Δ^n (where Ω is the space of market condition parameters and Δ^n is the n-asset simplex) such that for any market condition ω ∈ Ω, f_θ(ω) approximates the optimal Markowitz/CVaR portfolio allocation w*(ω) within ε = 1% tracking error (measured by out-of-sample Sharpe ratio degradation), while achieving ≥100× inference speedup over a cold-start convex solver (e.g., CVXPY with OSQP backend) on identical hardware.

Disproof criteria:
  1. PRIMARY DISPROOF: The amortized model's out-of-sample Sharpe ratio is statistically significantly lower (p < 0.05, paired t-test over 252 trading days) than the exact convex solver by more than 5% relative degradation across ≥3 distinct market regimes.
  2. SPEEDUP FAILURE: Inference time of f_θ exceeds 10ms per portfolio on CPU (single-threaded), failing to provide practical speedup over warm-started OSQP (typically 50–200ms).
  3. CONSTRAINT VIOLATION: f_θ(ω) violates portfolio constraints (e.g., weights sum ≠ 1 ± 0.001, negative weights in long-only setting) in >1% of test cases after post-processing.
  4. GENERALIZATION FAILURE: Mean absolute deviation between f_θ(ω) and w*(ω) exceeds 5 percentage points per asset on held-out market regimes not seen during training.
  5. SCALABILITY FAILURE: Model accuracy degrades by >10% relative Sharpe when n scales from 50 to 500 assets without architectural changes.
  6. TRAINING INSTABILITY: Loss fails to converge within 50,000 gradient steps across 3 independent random seeds.

Spine & Adversarial ReadReady for validation

||A neural network trained via amortized optimization can learn a parametric mapping f_θ: Ω → Δ^n (where Ω is the space of market condition parameters and Δ^n is the n-asset simplex) such that for any m

Experimental Protocol

Minimum Viable Test (MVT): Train an amortized optimization network on synthetic market condition parameters drawn from a calibrated multivariate distribution, using exact CVXPY solutions as supervision targets. Evaluate on held-out synthetic data and two real historical periods (2008 financial crisis, 2020 COVID crash) using n=50, 100, 200 assets. Compare Sharpe ratio, turnover, constraint satisfaction, and wall-clock inference time against CVXPY+OSQP baseline.

Full Validation: Extend to n=500 assets, 5 market regimes, rolling walk-forward backtest from 2000–2024, ablation over network architectures (MLP, attention-based, hypernetwork), and comparison against warm-started solvers and differentiable optimization layers (e.g., OptNet, CVXPY layers).

Required datasets:
  1. SYNTHETIC TRAINING DATA: 500,000 market condition parameter vectors sampled from calibrated multivariate normal + Student-t mixture (κ=5 degrees of freedom) with corresponding CVXPY-solved optimal allocations. Generation cost: ~200 CPU hours.
  2. REAL MARKET DATA - EQUITIES: S&P 500 daily returns 2000–2024 from CRSP or Yahoo Finance (free tier); rolling 60-day covariance matrices as input features.
  3. REAL MARKET DATA - FACTORS: Fama-French 5-factor daily data (freely available at mba.tuck.dartmouth.edu) for feature augmentation.
  4. CRISIS REGIME LABELS: NBER recession dates + VIX > 30 periods for regime-stratified evaluation.
  5. PRETRAINED BASELINES: CVXPY 1.4+, OSQP solver, qpth/OptNet implementation (GitHub), cvxpylayers.
  6. COMPUTE ENVIRONMENT: PyTorch 2.x, Python 3.10+, CUDA 12.x for GPU training.
  7. BENCHMARK PORTFOLIOS: 1/n equal-weight, minimum variance, maximum Sharpe (exact solver) as comparison baselines.
Success:
  1. SPEED: Amortized model achieves ≥100× speedup over cold-start CVXPY on CPU for n=50; ≥50× for n=200.
  2. QUALITY: Out-of-sample Sharpe ratio degradation < 5% relative to exact solver across all market regimes (p > 0.05 for degradation being significant).
  3. CONSTRAINT SATISFACTION: Portfolio weight violations < 0.1% of test cases after simplex projection post-processing.
  4. GENERALIZATION: L2 distance ||f_θ(ω) - w*(ω)||_2 < 0.02 (per-asset average deviation < 0.4%) on held-out test set.
  5. SCALABILITY: Model maintains <10% relative Sharpe degradation as n scales from 50 to 200 assets.
  6. TRAINING STABILITY: Convergence achieved in <50,000 steps across all 3 random seeds (variance in final validation loss < 5%).
  7. OBJECTIVE GAP: Portfolio objective value gap < 1 basis point on average across test instances.
Failure:
  1. Sharpe ratio degradation > 5% relative in any single market regime (crisis periods weighted 2×).
  2. Inference time > 10ms per portfolio on CPU (single-threaded, n=50).
  3. Constraint violations > 1% of test cases (even after post-processing).
  4. L2 solution distance > 0.05 on held-out test set.
  5. Training fails to converge (loss plateau within first 20,000 steps) on ≥2 of 3 random seeds.
  6. Sharpe degradation increases monotonically with n (no viable scaling path identified).
  7. Model produces degenerate solutions (e.g., all-cash or single-asset concentration) in >5% of test cases.

48

GPU hours

20d

Time to result

$180

Min cost

$1,400

Full cost

ROI Projection

Commercial:
  1. FINTECH LICENSING: Amortized portfolio engine licensable to robo-advisors (Betterment, Wealthfront scale: $30B+ AUM) — estimated $2–5M annual licensing value per major platform.
  2. CLOUD API PRODUCT: Portfolio optimization-as-a-service API with 100× lower compute costs than exact solver alternatives; addressable market ~$500M (quantitative finance software).
  3. EMBEDDED SYSTEMS: Enables portfolio optimization on edge devices (mobile apps, IoT trading terminals) where convex solvers are computationally infeasible.
  4. REGULATORY COMPLIANCE: Faster optimization enables more frequent compliance-driven rebalancing (ESG constraints, regulatory capital requirements) without proportional cost increase.
  5. DEMOCRATIZATION: Reduces barrier to entry for smaller asset managers who cannot afford dedicated optimization infrastructure.
  6. CROSS-DOMAIN TRANSFER: Methodology directly applicable to supply chain optimization, energy grid dispatch, and resource allocation — total addressable market exceeds $10B.
  7. PATENT POTENTIAL: Novel training procedure (KKT-penalized amortized learning for financial optimization) is patentable; estimated IP value $1–3M.

🔓 If proven, this unlocks

Proving this hypothesis is a prerequisite for the following downstream discoveries and applications:

  • 1real_time_portfolio_rebalancing_system_004
  • 2multi_objective_amortized_portfolio_005
  • 3amortized_risk_parity_optimization_006
  • 4online_learning_portfolio_adaptation_007
  • 5federated_portfolio_optimization_008

Prerequisites

These must be validated before this hypothesis can be confirmed:

  • convex_optimization_approximation_theory_001
  • portfolio_optimization_benchmark_suite_002
  • amortized_inference_convergence_guarantees_003

Implementation Sketch

# AMORTIZED PORTFOLIO OPTIMIZATION - IMPLEMENTATION SKETCH
# Architecture: KKT-Penalized Amortized Network (KPAN)

import torch
import torch.nn as nn
import cvxpy as cp
import numpy as np
from torch.utils.data import DataLoader, TensorDataset

# ============================================================
# 1. DATA GENERATION
# ============================================================
def generate_market_params(n_assets, n_samples, seed=42):
    """Generate synthetic market condition parameters."""
    np.random.seed(seed)
    params, solutions, solve_times = [], [], []
    
    for _ in range(n_samples):
        # Sample expected returns from N(0.08, 0.15^2) annualized
        mu = np.random.normal(0.08, 0.15, n_assets)
        
        # Sample covariance via Wishart distribution
        A = np.random.randn(n_assets, n_assets + 10) * 0.1
        Sigma = A @ A.T / (n_assets + 10) + np.eye(n_assets) * 0.01
        
        # Risk aversion parameter
        lam = np.random.uniform(0.5, 5.0)
        
        # Solve with CVXPY
        w = cp.Variable(n_assets)
        obj = cp.Minimize(lam * cp.quad_form(w, Sigma) - mu @ w)
        constraints = [cp.sum(w) == 1, w >= 0]  # long-only
        prob = cp.Problem(obj, constraints)
        
        import time
        t0 = time.time()
        prob.solve(solver=cp.OSQP, warm_start=True)
        solve_times.append(time.time() - t0)
        
        if prob.status == 'optimal':
            # Encode omega as flattened feature vector
            omega = np.concatenate([mu, Sigma.flatten(), [lam]])
            params.append(omega)
            solutions.append(w.value)
    
    return np.array(params), np.array(solutions), np.array(solve_times)

# ============================================================
# 2. NETWORK ARCHITECTURE
# ============================================================
class AmortizedPortfolioNet(nn.Module):
    def __init__(self, n_assets, hidden_dim=512, n_layers=4):
        super().__init__()
        # Input: mu (n) + Sigma (n^2) + lambda (1)
        input_dim = n_assets + n_assets**2 + 1
        
        layers = [nn.Linear(input_dim, hidden_dim), nn.LayerNorm(hidden_dim), nn.GELU()]
        for _ in range(n_layers - 2):
            layers += [nn.Linear(hidden_dim, hidden_dim), nn.LayerNorm(hidden_dim), nn.GELU(), nn.Dropout(0.1)]
        layers += [nn.Linear(hidden_dim, n_assets)]
        
        self.network = nn.Sequential(*layers)
        self.n_assets = n_assets
    
    def forward(self, omega):
        logits = self.network(omega)
        # Softmax ensures sum-to-1 and non-negativity (long-only)
        weights = torch.softmax(logits, dim=-1)
        return weights

# ============================================================
# 3. LOSS FUNCTION WITH KKT PENALTY
# ============================================================
class KKTPenalizedLoss(nn.Module):
    def __init__(self, alpha_kkt=0.1, alpha_obj=1.0):
        super().__init__()
        self.alpha_kkt = alpha_kkt  # KKT violation penalty weight
        self.alpha_obj = alpha_obj  # Objective gap penalty weight
    
    def forward(self, w_pred, w_star, mu, Sigma, lam):
        # Supervised loss: L2 distance to optimal solution
        supervised_loss = torch.mean(torch.sum((w_pred - w_star)**2, dim=-1))
        
        # KKT violation: sum-to-one constraint (already enforced by softmax)
        sum_violation = torch.mean((torch.sum(w_pred, dim=-1) - 1.0)**2)
        
        # Objective gap: portfolio variance difference
        # w^T Sigma w for predicted vs optimal
        obj_pred = torch.einsum('bi,bij,bj->b', w_pred, Sigma, w_pred)
        obj_star = torch.einsum('bi,bij,bj->b', w_star, Sigma, w_star)
        obj_gap = torch.mean(torch.relu(obj_pred - obj_star))  # penalize only if worse
        
        total_loss = supervised_loss + self.alpha_kkt * sum_violation + self.alpha_obj * obj_gap
        
        return total_loss, {
            'supervised': supervised_loss.item(),
            'kkt_violation': sum_violation.item(),
            'obj_gap': obj_gap.item()
        }

# ============================================================
# 4. TRAINING LOOP
# ============================================================
def train_amortized_model(model, train_loader, val_loader, n_epochs=100, lr=1e-3):
    optimizer = torch.optim.Adam(model.parameters(), lr=lr)
    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=n_epochs)
    loss_fn = KKTPenalizedLoss()
    
    best_val_loss = float('inf')
    patience_counter = 0
    
    for epoch in range(n_epochs):
        model.train()
        for omega, w_star, mu, Sigma, lam in train_loader:
            optimizer.zero_grad()
            w_pred = model(omega)
            loss, metrics = loss_fn(w_pred, w_star, mu, Sigma, lam)
            loss.backward()
            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
            optimizer.step()
        
        # Validation
        val_loss = evaluate(model, val_loader, loss_fn)
        scheduler.step()
        
        # Early stopping
        if val_loss < best_val_loss * 0.99:
            best_val_loss = val_loss
            patience_counter = 0
            torch.save(model.state_dict(), 'best_model.pt')
        else:
            patience_counter += 1
        
        # ABORT CHECKPOINT: no improvement for 10 epochs
        if patience_counter >= 10:
            print(f"Early stopping at epoch {epoch}")
            break
    
    return model

# ============================================================
# 5. EVALUATION & BENCHMARKING
# ============================================================
def benchmark_inference_speed(model, test_params, n_trials=1000):
    import time
    model.eval()
    
    # Amortized model speed
    t0 = time.time()
    with torch.no_grad():
        for i in range(n_trials):
            _ = model(test_params[i:i+1])
    amortized_time = (time.time() - t0) / n_trials
    
    return amortized_time  # seconds per portfolio

def compute_sharpe_degradation(w_amortized, w_optimal, returns_matrix):
    """Compute relative Sharpe ratio degradation."""
    sharpe_amortized = compute_sharpe(w_amortized, returns_matrix)
    sharpe_optimal = compute_sharpe(w_optimal, returns_matrix)
    degradation = (sharpe_optimal - sharpe_amortized) / abs(sharpe_optimal)
    return degradation  # positive = amortized is worse

def compute_sharpe(weights, returns):
    portfolio_returns = returns @ weights
    return np.mean(portfolio_returns) / np.std(portfolio_returns) * np.sqrt(252)

# ============================================================
# 6. MAIN EXPERIMENT RUNNER
# ============================================================
if __name__ == "__main__":
    N_ASSETS = 50  # MVT; scale to 100, 200, 500 in full validation
    N_TRAIN = 400000
    N_VAL = 50000
    N_TEST = 50000
    
    # Generate data
    print("Generating training data...")
    params, solutions, solve_times = generate_market_params(N_ASSETS, N_TRAIN + N_VAL + N_TEST)
    print(f"Mean CVXPY solve time: {np.mean(solve_times)*1000:.1f}ms")
    
    # Train model
    model = AmortizedPortfolioNet(n_assets=N_ASSETS)
    model = train_amortized_model(model, train_loader, val_loader)
    
    # Benchmark
    amortized_ms = benchmark_inference_speed(model, test_params) * 1000
    speedup = np.mean(solve_times) / (amortized_ms / 1000)
    print(f"Amortized inference: {amortized_ms:.2f}ms | Speedup: {speedup:.0f}x")
    
    # Quality evaluation
    degradation = compute_sharpe_degradation(w_amortized, w_optimal, test_returns)
    print(f"Sharpe degradation: {degradation*100:.2f}%")
    
    # SUCCESS/FAILURE determination
    assert speedup >= 100, f"FAIL: Speedup {speedup:.0f}x < 100x threshold"
    assert degradation < 0.05, f"FAIL: Sharpe degradation {degradation:.2%} > 5% threshold"
    print("ALL SUCCESS CRITERIA MET")
Abort checkpoints:
  1. CHECKPOINT A (Day 3, Data Generation): If CVXPY solve time for n=50 assets exceeds 500ms on average (indicating solver issues), abort and diagnose solver configuration before proceeding. Expected: 50–150ms.
  2. CHECKPOINT B (Day 6, Training Epoch 5): If training loss has not decreased by >10% from initialization after 5 epochs, abort and diagnose learning rate, architecture, or data normalization. Expected: >50% loss reduction by epoch 5.
  3. CHECKPOINT C (Day 8, Training Epoch 20): If validation MSE > 0.01 (per-asset average deviation > 10%) after 20 epochs, abort architecture and switch to next candidate. Expected: validation MSE < 0.005.
  4. CHECKPOINT D (Day 9, Speed Benchmark): If amortized inference time > 50ms on CPU for n=50 (less than 3× speedup over CVXPY), abort — the approach provides insufficient practical benefit. Expected: < 1ms (>100× speedup).
  5. CHECKPOINT E (Day 11, Quality Evaluation): If L2 solution distance > 0.05 on test set (per-asset deviation > 1%), abort full backtest and return to architecture/training improvements. Expected: < 0.02.
  6. CHECKPOINT F (Day 13, Backtest Year 2008): If Sharpe degradation during 2008 crisis period exceeds 15% relative, flag as high-risk failure mode and abort scalability experiments — focus on crisis robustness instead. Expected: < 5%.
  7. CHECKPOINT G (Day 16, n=200 Scalability): If approximation error increases by >3× when scaling from n=50 to n=200 (superlinear degradation), abort n=500 experiments and report scalability limitation as primary finding. Expected: <2× degradation.
  8. CHECKPOINT H (Day 18, Statistical Testing): If Diebold-Mariano test shows statistically significant (p < 0.01) underperformance of amortized model vs. exact solver across full backtest period, classify as DISPROOF and halt further validation.

Source

AegisMind Research
Need AI to work rigorously on your problems? AegisMind uses the same multi-model engine for personal and professional use. Get started