diff --git a/results/20260313_Vivaan-Atharva_darwin.jsonl b/results/20260313_Vivaan-Atharva_darwin.jsonl new file mode 100644 index 0000000..bf6b49f --- /dev/null +++ b/results/20260313_Vivaan-Atharva_darwin.jsonl @@ -0,0 +1,20 @@ +{"problem_name": "qp/mean_variance_medium", "solver_name": "CLARABEL", "compilation_time": 0.03724098205566406, "solve_time": 0.029368301, "setup_time": null, "total_time": 0.07185274499897787, "status": "optimal", "objective_value": 0.00014736059085145028, "num_iters": 9, "problem_type": "QP", "num_scalar_variables": 200, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 201, "cvxpy_version": "1.8.1", "solver_version": "CLARABEL", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:27.597102+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_medium", "solver_name": "HIGHS", "compilation_time": 0.014678955078125, "solve_time": 0.037944572992273606, "setup_time": null, "total_time": 0.06337019999955373, "status": "optimal", "objective_value": 0.00014736052948214617, "num_iters": 598, "problem_type": "QP", "num_scalar_variables": 200, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 201, "cvxpy_version": "1.8.1", "solver_version": "HIGHS", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:27.728636+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_medium", "solver_name": "OSQP", "compilation_time": 0.014281988143920898, "solve_time": 0.008496627, "setup_time": null, "total_time": 0.025855489999230485, "status": "optimal", "objective_value": 0.00014736052948203284, "num_iters": 50, "problem_type": "QP", "num_scalar_variables": 200, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 201, "cvxpy_version": "1.8.1", "solver_version": "OSQP", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:27.822486+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_medium", "solver_name": "SCIPY", "compilation_time": null, "solve_time": null, "setup_time": null, "total_time": 0.0003582440003810916, "status": "solver_error", "objective_value": null, "num_iters": null, "problem_type": "QP", "num_scalar_variables": 200, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 201, "cvxpy_version": "1.8.1", "solver_version": "", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:27.891127+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_medium", "solver_name": "SCS", "compilation_time": 0.015867948532104492, "solve_time": 0.0017216689999999999, "setup_time": 0.005375016999999999, "total_time": 0.02506586699928448, "status": "optimal", "objective_value": 0.0001473605238836496, "num_iters": 25, "problem_type": "QP", "num_scalar_variables": 200, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 201, "cvxpy_version": "1.8.1", "solver_version": "SCS", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:27.984579+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_small", "solver_name": "CLARABEL", "compilation_time": 0.006227970123291016, "solve_time": 0.000367496, "setup_time": null, "total_time": 0.007298979000552208, "status": "optimal", "objective_value": 0.0017934865652385655, "num_iters": 8, "problem_type": "QP", "num_scalar_variables": 20, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 21, "cvxpy_version": "1.8.1", "solver_version": "CLARABEL", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:27.996679+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_small", "solver_name": "HIGHS", "compilation_time": 0.005446195602416992, "solve_time": 0.001175248995423317, "setup_time": null, "total_time": 0.007838289999199333, "status": "optimal", "objective_value": 0.0017934865652388938, "num_iters": 61, "problem_type": "QP", "num_scalar_variables": 20, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 21, "cvxpy_version": "1.8.1", "solver_version": "HIGHS", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.008957+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_small", "solver_name": "OSQP", "compilation_time": 0.005428791046142578, "solve_time": 0.000178085, "setup_time": null, "total_time": 0.007376632000159589, "status": "optimal", "objective_value": 0.0017934865652382227, "num_iters": 50, "problem_type": "QP", "num_scalar_variables": 20, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 21, "cvxpy_version": "1.8.1", "solver_version": "OSQP", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.020743+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_small", "solver_name": "SCIPY", "compilation_time": null, "solve_time": null, "setup_time": null, "total_time": 0.0003060220005863812, "status": "solver_error", "objective_value": null, "num_iters": null, "problem_type": "QP", "num_scalar_variables": 20, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 21, "cvxpy_version": "1.8.1", "solver_version": "", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.025484+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/mean_variance_small", "solver_name": "SCS", "compilation_time": 0.005944728851318359, "solve_time": 5.702e-05, "setup_time": 9.9085e-05, "total_time": 0.006940499999473104, "status": "optimal", "objective_value": 0.001793486505635041, "num_iters": 25, "problem_type": "QP", "num_scalar_variables": 20, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 21, "cvxpy_version": "1.8.1", "solver_version": "SCS", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.036641+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/risk_parity_small", "solver_name": "CLARABEL", "compilation_time": 0.009557008743286133, "solve_time": 0.00189623, "setup_time": null, "total_time": 0.012374713000099291, "status": "optimal", "objective_value": 0.0012246413699866913, "num_iters": 14, "problem_type": "QP", "num_scalar_variables": 30, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 31, "cvxpy_version": "1.8.1", "solver_version": "CLARABEL", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.056804+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/risk_parity_small", "solver_name": "HIGHS", "compilation_time": null, "solve_time": null, "setup_time": null, "total_time": 0.0006085780005378183, "status": "solver_error", "objective_value": null, "num_iters": null, "problem_type": "QP", "num_scalar_variables": 30, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 31, "cvxpy_version": "1.8.1", "solver_version": "", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.065426+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/risk_parity_small", "solver_name": "OSQP", "compilation_time": null, "solve_time": null, "setup_time": null, "total_time": 0.00022551900110556744, "status": "solver_error", "objective_value": null, "num_iters": null, "problem_type": "QP", "num_scalar_variables": 30, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 31, "cvxpy_version": "1.8.1", "solver_version": "", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.073888+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/risk_parity_small", "solver_name": "SCIPY", "compilation_time": null, "solve_time": null, "setup_time": null, "total_time": 0.000545770000826451, "status": "solver_error", "objective_value": null, "num_iters": null, "problem_type": "QP", "num_scalar_variables": 30, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 31, "cvxpy_version": "1.8.1", "solver_version": "", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.082626+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "qp/risk_parity_small", "solver_name": "SCS", "compilation_time": 0.009062767028808594, "solve_time": 0.00044021500000000004, "setup_time": 0.000318183, "total_time": 0.011035745999834035, "status": "optimal", "objective_value": 0.0012253139462066462, "num_iters": 50, "problem_type": "QP", "num_scalar_variables": 30, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 31, "cvxpy_version": "1.8.1", "solver_version": "SCS", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.101526+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "socp/cvar_portfolio_small", "solver_name": "CLARABEL", "compilation_time": 0.028500080108642578, "solve_time": 0.090561763, "setup_time": null, "total_time": 0.12949438199939323, "status": "infeasible", "objective_value": Infinity, "num_iters": 8, "problem_type": "LP", "num_scalar_variables": 1051, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 2051, "cvxpy_version": "1.8.1", "solver_version": "CLARABEL", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.234732+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "socp/cvar_portfolio_small", "solver_name": "HIGHS", "compilation_time": 0.020374059677124023, "solve_time": 0.10542935799458064, "setup_time": null, "total_time": 0.13965072799874179, "status": "infeasible", "objective_value": Infinity, "num_iters": null, "problem_type": "LP", "num_scalar_variables": 1051, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 2051, "cvxpy_version": "1.8.1", "solver_version": "HIGHS", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.377310+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "socp/cvar_portfolio_small", "solver_name": "OSQP", "compilation_time": 0.020908832550048828, "solve_time": 0.036454654, "setup_time": null, "total_time": 0.05912847299987334, "status": "infeasible", "objective_value": Infinity, "num_iters": null, "problem_type": "LP", "num_scalar_variables": 1051, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 2051, "cvxpy_version": "1.8.1", "solver_version": "OSQP", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.439875+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "socp/cvar_portfolio_small", "solver_name": "SCIPY", "compilation_time": 0.0256650447845459, "solve_time": null, "setup_time": null, "total_time": 0.1379601080006978, "status": "infeasible", "objective_value": Infinity, "num_iters": null, "problem_type": "LP", "num_scalar_variables": 1051, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 2051, "cvxpy_version": "1.8.1", "solver_version": "SCIPY", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.580866+00:00", "contributor": "Vivaan-Atharva"} +{"problem_name": "socp/cvar_portfolio_small", "solver_name": "SCS", "compilation_time": 0.026215791702270508, "solve_time": 0.024088027, "setup_time": 0.012822304000000001, "total_time": 0.0637434630007192, "status": "infeasible", "objective_value": Infinity, "num_iters": 75, "problem_type": "LP", "num_scalar_variables": 1051, "num_scalar_eq_constr": 1, "num_scalar_leq_constr": 2051, "cvxpy_version": "1.8.1", "solver_version": "SCS", "python_version": "3.12.4", "os_info": "Darwin 25.3.0", "cpu_info": "i386", "timestamp": "2026-03-13T12:16:28.647494+00:00", "contributor": "Vivaan-Atharva"} diff --git a/src/solver_benchmarks/problems/finance.py b/src/solver_benchmarks/problems/finance.py new file mode 100644 index 0000000..73e17ec --- /dev/null +++ b/src/solver_benchmarks/problems/finance.py @@ -0,0 +1,145 @@ +"""Finance benchmark problems using real-world inspired data.""" + +from __future__ import annotations + +import cvxpy as cp +import numpy as np + +from solver_benchmarks.problems import register_problem + + +@register_problem( + "qp/mean_variance_small", + tags=["qp", "small", "finance"], + description="Mean-variance portfolio optimization (20 assets)", +) +def mean_variance_small(seed: int = 0) -> cp.Problem: + """Markowitz mean-variance portfolio optimization. + + Minimizes portfolio variance subject to a minimum return target, + full investment, and no short-selling constraints. + """ + rng = np.random.default_rng(seed) + n = 20 + + # Simulate realistic annual returns (5-15% mean, ~20% vol) + mu = 0.08 + rng.standard_normal(n) * 0.04 + # Factor model for covariance: Sigma = F @ F.T + diag(idio) + F = rng.standard_normal((n, 5)) * 0.1 + idio = rng.uniform(0.01, 0.05, n) + Sigma = F @ F.T + np.diag(idio) + + ret_target = 0.07 + x = cp.Variable(n) + risk = cp.quad_form(x, Sigma) + constraints = [ + mu @ x >= ret_target, + cp.sum(x) == 1, + x >= 0, + ] + return cp.Problem(cp.Minimize(risk), constraints) + + +@register_problem( + "qp/mean_variance_medium", + tags=["qp", "medium", "finance"], + description="Mean-variance portfolio optimization (200 assets)", +) +def mean_variance_medium(seed: int = 0) -> cp.Problem: + """Larger Markowitz mean-variance portfolio optimization.""" + rng = np.random.default_rng(seed) + n = 200 + + mu = 0.08 + rng.standard_normal(n) * 0.04 + F = rng.standard_normal((n, 20)) * 0.1 + idio = rng.uniform(0.01, 0.05, n) + Sigma = F @ F.T + np.diag(idio) + + ret_target = 0.07 + x = cp.Variable(n) + risk = cp.quad_form(x, Sigma) + constraints = [ + mu @ x >= ret_target, + cp.sum(x) == 1, + x >= 0, + ] + return cp.Problem(cp.Minimize(risk), constraints) + + +@register_problem( + "socp/cvar_portfolio_small", + tags=["socp", "small", "finance"], + description="CVaR portfolio optimization (50 assets, 1000 scenarios)", +) +def cvar_portfolio_small(seed: int = 0) -> cp.Problem: + """Conditional Value-at-Risk (CVaR) portfolio optimization. + + CVaR minimization is a standard risk measure in quantitative finance, + used in place of variance when tail risk matters. + Reformulated as an LP/SOCP using the Rockafellar-Uryasev formulation. + """ + rng = np.random.default_rng(seed) + n = 50 # number of assets + S = 1000 # number of scenarios + alpha = 0.95 # confidence level (95% CVaR) + + # Simulate scenario returns: factor model + F = rng.standard_normal((S, 5)) * 0.02 + B = rng.standard_normal((5, n)) * 0.1 + idio = rng.standard_normal((S, n)) * 0.01 + R = F @ B + idio # S x n scenario return matrix + + mu = R.mean(axis=0) + ret_target = 0.005 # 0.5% minimum expected return per scenario + + x = cp.Variable(n) # portfolio weights + z = cp.Variable() # VaR threshold + u = cp.Variable(S) # auxiliary variables for CVaR + + # CVaR = z + 1/((1-alpha)*S) * sum(u) + cvar = z + (1 / ((1 - alpha) * S)) * cp.sum(u) + + constraints = [ + u >= 0, + u >= -R @ x - z, + mu @ x >= ret_target, + cp.sum(x) == 1, + x >= 0, + ] + return cp.Problem(cp.Minimize(cvar), constraints) + + +@register_problem( + "qp/risk_parity_small", + tags=["qp", "small", "finance"], + description="Risk parity portfolio approximation (30 assets)", +) +def risk_parity_small(seed: int = 0) -> cp.Problem: + """Risk parity portfolio via quadratic approximation. + + Risk parity targets equal risk contribution from each asset. + Approximated as a QP following Bruder & Roncalli (2012). + """ + rng = np.random.default_rng(seed) + n = 30 + + F = rng.standard_normal((n, 8)) * 0.1 + idio = rng.uniform(0.01, 0.05, n) + Sigma = F @ F.T + np.diag(idio) + + # Equal risk budget + b = np.ones(n) / n + + x = cp.Variable(n, nonneg=True) + # Minimize variance subject to log-weight budget constraints + # (convex approximation of risk parity) + risk = cp.quad_form(x, Sigma) + constraints = [ + cp.sum(x) == 1, + x >= 1e-4, + ] + # Add risk budget constraint via log barrier approximation + log_constraint = cp.sum(cp.multiply(b, cp.log(x))) >= -10 + constraints.append(log_constraint) + + return cp.Problem(cp.Minimize(risk), constraints)