tessl install tessl/pypi-ecos@2.0.1Python interface to ECOS, a numerical solver for convex second-order cone programs.
Examples organized by complexity and use case. All examples assume these imports:
import ecos
import numpy as np
import scipy.sparse as spMinimize -x subject to x <= 4.
# Problem: minimize -x subject to x <= 4
c = np.array([-1.0])
G = sp.csc_matrix([[1.0]])
h = np.array([4.0])
dims = {'l': 1, 'q': []}
solution = ecos.solve(c, G, h, dims)
print("Optimal x:", solution['x']) # [4.0]
print("Optimal value:", np.dot(c, solution['x'])) # -4.0Explanation:
Minimize -x subject to x <= 4 and x >= 0.
# Problem: minimize -x subject to x <= 4 and x >= 0
c = np.array([-1.0])
G = sp.csc_matrix([[1.0], [-1.0]])
h = np.array([4.0, 0.0])
dims = {'l': 2, 'q': []}
solution = ecos.solve(c, G, h, dims, verbose=False)
print("Optimal x:", solution['x']) # [4.0]
print("Optimal value:", np.dot(c, solution['x'])) # -4.0Explanation:
Minimize -x1 - x2 subject to linear constraints.
# Problem:
# minimize -x1 - x2
# subject to:
# 2*x1 + x2 <= 4
# x1 + 2*x2 <= 4
# x1 >= 0
# x2 >= 0
c = np.array([-1.0, -1.0])
G = sp.csc_matrix([
[2.0, 1.0], # 2*x1 + x2 <= 4
[1.0, 2.0], # x1 + 2*x2 <= 4
[-1.0, 0.0], # -x1 <= 0 (x1 >= 0)
[0.0, -1.0] # -x2 <= 0 (x2 >= 0)
])
h = np.array([4.0, 4.0, 0.0, 0.0])
dims = {'l': 4, 'q': []}
solution = ecos.solve(c, G, h, dims)
print("Optimal x:", solution['x']) # Approximately [1.33, 1.33]
print("Optimal value:", np.dot(c, solution['x'])) # Approximately -2.67Explanation:
Minimize -x subject to x = 3.
# Problem: minimize -x subject to x = 3 and x <= 4
c = np.array([-1.0])
G = sp.csc_matrix([[1.0]])
h = np.array([4.0])
A = sp.csc_matrix([[1.0]])
b = np.array([3.0])
dims = {'l': 1, 'q': []}
solution = ecos.solve(c, G, h, dims, A, b)
print("Optimal x:", solution['x']) # [3.0]
print("Dual y:", solution['y']) # Lagrange multiplier for equalityExplanation:
Two variables with equality and inequality constraints.
# Problem:
# minimize x1 + x2
# subject to:
# x1 + x2 = 5 (equality)
# x1 - x2 = 1 (equality)
# x1 >= 0, x2 >= 0
c = np.array([1.0, 1.0])
G = sp.csc_matrix([[-1.0, 0.0], [0.0, -1.0]])
h = np.array([0.0, 0.0])
A = sp.csc_matrix([[1.0, 1.0], [1.0, -1.0]])
b = np.array([5.0, 1.0])
dims = {'l': 2, 'q': []}
solution = ecos.solve(c, G, h, dims, A, b)
print("Optimal x:", solution['x']) # [3.0, 2.0]
print("Verification: x1 + x2 =", solution['x'][0] + solution['x'][1]) # 5.0
print("Verification: x1 - x2 =", solution['x'][0] - solution['x'][1]) # 1.0Explanation:
Minimize -x0 subject to (x0, x1) in a second-order cone.
# Problem: minimize -x0 subject to x0 >= ||x1|| (L2 norm)
# This is equivalent to (x0, x1) in Q_2 where Q_2 is 2-dimensional SOC
c = np.array([-1.0, 0.0])
G = sp.csc_matrix([[1.0, 0.0], [0.0, 1.0]])
h = np.array([0.0, 0.0])
dims = {'l': 0, 'q': [2]} # One second-order cone of dimension 2
solution = ecos.solve(c, G, h, dims)
print("Optimal solution:", solution['x'])
print("Verification: x0 >= |x1|:", solution['x'][0], ">=", abs(solution['x'][1]))Explanation:
Minimize the L2 norm of a vector subject to linear constraints.
# Problem: minimize ||x|| subject to sum(x) >= 1, x >= 0
# Reformulate as:
# minimize t
# subject to (t, x) in SOC (t >= ||x||)
# sum(x) >= 1
# x >= 0
# Variables: [t, x1, x2, x3]
n = 4 # 1 for t, 3 for x components
c = np.array([1.0, 0.0, 0.0, 0.0]) # minimize t
# Cone constraint: (t, x1, x2, x3) in Q_4
G_soc = sp.csc_matrix([
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0]
])
# Linear constraints: -(x1 + x2 + x3) <= -1, -x1 <= 0, -x2 <= 0, -x3 <= 0
G_linear = sp.csc_matrix([
[0.0, -1.0, -1.0, -1.0], # sum(x) >= 1
[0.0, -1.0, 0.0, 0.0], # x1 >= 0
[0.0, 0.0, -1.0, 0.0], # x2 >= 0
[0.0, 0.0, 0.0, -1.0] # x3 >= 0
])
G = sp.vstack([G_soc, G_linear], format='csc')
h = np.array([0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0])
dims = {'l': 4, 'q': [4]}
solution = ecos.solve(c, G, h, dims)
t_opt = solution['x'][0]
x_opt = solution['x'][1:]
print("Optimal norm:", t_opt)
print("Optimal x:", x_opt)
print("Verification ||x||:", np.linalg.norm(x_opt))
print("Verification sum(x):", np.sum(x_opt))Explanation:
Problem with multiple SOC constraints.
# Problem with two separate SOC constraints
# Variables: [x1, x2, x3, x4, x5]
# Constraints:
# x1 >= ||(x2, x3)|| (3-dimensional SOC)
# x4 >= ||(x5,)|| (2-dimensional SOC)
# Minimize x1 + x4
c = np.array([1.0, 0.0, 0.0, 1.0, 0.0])
# First SOC: (x1, x2, x3)
# Second SOC: (x4, x5)
G = sp.csc_matrix([
# First SOC
[1.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0, 0.0],
# Second SOC
[0.0, 0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 1.0]
])
h = np.zeros(5)
dims = {'l': 0, 'q': [3, 2]} # Two SOCs: dimension 3 and 2
solution = ecos.solve(c, G, h, dims)
print("Optimal solution:", solution['x'])
print("x1 >= ||(x2, x3)||:", solution['x'][0], ">=", np.linalg.norm(solution['x'][1:3]))
print("x4 >= ||x5||:", solution['x'][3], ">=", abs(solution['x'][4]))Explanation:
Linear program with one boolean variable.
# Problem:
# minimize -x1 - x2
# subject to:
# 2*x1 + x2 <= 4
# 3*x1 + 4*x2 <= 12
# x1 >= 0, x2 >= 0
# x2 in {0, 1} (boolean)
c = np.array([-1.0, -1.0])
G = sp.csc_matrix([
[2.0, 1.0],
[3.0, 4.0],
[-1.0, 0.0],
[0.0, -1.0]
])
h = np.array([4.0, 12.0, 0.0, 0.0])
dims = {'l': 4, 'q': []}
# Specify that x2 (index 1) is boolean
solution = ecos.solve(
c, G, h, dims,
bool_vars_idx=[1],
mi_max_iters=1000,
verbose=False
)
print("Optimal solution:", solution['x'])
print("x2 is boolean:", solution['x'][1] in [0.0, 1.0])
print("Optimal value:", np.dot(c, solution['x']))Explanation:
bool_vars_idx=[1] constrains x2 to be 0 or 1Problem with both boolean and general integer variables.
# Problem:
# minimize x1 + x2 + x3
# subject to:
# x1 + 2*x2 + 3*x3 >= 10
# x1, x2, x3 >= 0
# x1 in {0, 1} (boolean)
# x2 in Z+ (non-negative integer)
# x3 continuous
c = np.array([1.0, 1.0, 1.0])
G = sp.csc_matrix([
[-1.0, -2.0, -3.0], # -(x1 + 2*x2 + 3*x3) <= -10
[-1.0, 0.0, 0.0], # x1 >= 0
[0.0, -1.0, 0.0], # x2 >= 0
[0.0, 0.0, -1.0] # x3 >= 0
])
h = np.array([-10.0, 0.0, 0.0, 0.0])
dims = {'l': 4, 'q': []}
solution = ecos.solve(
c, G, h, dims,
bool_vars_idx=[0], # x1 is boolean
int_vars_idx=[1], # x2 is integer
mi_max_iters=1000,
mi_abs_eps=1e-6,
mi_rel_eps=1e-3,
verbose=False
)
print("Optimal solution:", solution['x'])
print("x1 (boolean):", solution['x'][0])
print("x2 (integer):", solution['x'][1])
print("x3 (continuous):", solution['x'][2])
print("Constraint satisfied:", np.dot([1, 2, 3], solution['x']), ">=", 10)Explanation:
Integer optimization selecting items.
# Knapsack problem:
# maximize value: 5*x1 + 7*x2 + 3*x3
# subject to weight: 2*x1 + 3*x2 + 1*x3 <= 6
# x1, x2, x3 in {0, 1}
c = np.array([-5.0, -7.0, -3.0]) # Negative for maximization
G = sp.csc_matrix([
[2.0, 3.0, 1.0], # Weight constraint
[-1.0, 0.0, 0.0], # x1 >= 0
[0.0, -1.0, 0.0], # x2 >= 0
[0.0, 0.0, -1.0] # x3 >= 0
])
h = np.array([6.0, 0.0, 0.0, 0.0])
dims = {'l': 4, 'q': []}
solution = ecos.solve(
c, G, h, dims,
bool_vars_idx=[0, 1, 2], # All variables are boolean
mi_max_iters=1000,
verbose=False
)
print("Selected items:", solution['x'])
print("Total value:", -np.dot(c, solution['x']))
print("Total weight:", np.dot([2, 3, 1], solution['x']))Explanation:
Solving with tighter convergence criteria.
# Same problem as Example 2, but with custom tolerances
c = np.array([-1.0])
G = sp.csc_matrix([[1.0], [-1.0]])
h = np.array([4.0, 0.0])
dims = {'l': 2, 'q': []}
solution = ecos.solve(
c, G, h, dims,
feastol=1e-9, # Tighter feasibility
abstol=1e-9, # Tighter absolute convergence
reltol=1e-9, # Tighter relative convergence
max_iters=200, # More iterations allowed
verbose=True # Show progress
)
print("Optimal x:", solution['x'])
print("Solver info:", solution['info'])Explanation:
Examining solver behavior.
c = np.array([-1.0])
G = sp.csc_matrix([[1.0], [-1.0]])
h = np.array([4.0, 0.0])
dims = {'l': 2, 'q': []}
solution = ecos.solve(c, G, h, dims, verbose=True)
# Examine solution dictionary
print("\n--- Solution Summary ---")
print("Primal solution x:", solution['x'])
print("Dual solution y:", solution['y'])
print("Slack variables s:", solution['s'])
print("Dual cone vars z:", solution['z'])
print("\n--- Solver Info ---")
info = solution['info']
for key, value in info.items():
print(f" {key}: {value}")Explanation:
verbose=True prints iteration-by-iteration progresssolution['info'] contains detailed solver statisticsUsing more iterative refinement steps for accuracy.
c = np.array([-1.0])
G = sp.csc_matrix([[1.0], [-1.0]])
h = np.array([4.0, 0.0])
dims = {'l': 2, 'q': []}
solution = ecos.solve(
c, G, h, dims,
nitref=20, # More iterative refinement (default ~9)
verbose=False
)
print("Optimal x:", solution['x'])
print("Iterations used:", solution['info'])Explanation:
nitref controls iterative refinement after KKT system solveECOS is a default solver in CVXPY for convex problems.
import cvxpy as cp
# Define variables
x = cp.Variable(2)
# Define objective: minimize ||x||_2 + ||x||_1
objective = cp.Minimize(cp.norm(x, 2) + cp.norm(x, 1))
# Define constraints
constraints = [x >= 2]
# Create and solve problem
problem = cp.Problem(objective, constraints)
problem.solve(solver=cp.ECOS, verbose=True)
print("Optimal value:", problem.value)
print("Optimal x:", x.value)
print("Solver used:", problem.solver_stats.solver_name)Explanation:
Financial application using ECOS.
# Portfolio optimization: minimize risk, achieve target return
# Variables: x (portfolio weights)
# Objective: minimize risk = ||Σ^(1/2) * x||
# Constraints: expected_return' * x >= target, sum(x) = 1, x >= 0
import numpy as np
import scipy.sparse as sp
n_assets = 4
target_return = 0.08
# Expected returns
mu = np.array([0.05, 0.10, 0.08, 0.12])
# Covariance matrix (for simplicity, use diagonal)
Sigma = np.diag([0.01, 0.04, 0.02, 0.06])
Sigma_sqrt = np.sqrt(Sigma) # Element-wise for diagonal
# Reformulate as SOCP:
# minimize t subject to (t, Σ^(1/2) * x) in SOC
# Variables: [t, x1, x2, x3, x4]
c = np.concatenate([[1.0], np.zeros(n_assets)]) # minimize t
# SOC constraint
G_soc = sp.csc_matrix(np.vstack([
np.concatenate([[1.0], np.zeros(n_assets)]),
np.concatenate([[0.0], Sigma_sqrt])
]))
# Linear constraints:
# sum(x) = 1 (equality)
# mu' * x >= target (inequality: -mu'*x <= -target)
# x >= 0
G_linear = sp.csc_matrix([
np.concatenate([[0.0], -mu]), # Expected return constraint
np.concatenate([[0.0], [-1, 0, 0, 0]]), # x1 >= 0
np.concatenate([[0.0], [0, -1, 0, 0]]), # x2 >= 0
np.concatenate([[0.0], [0, 0, -1, 0]]), # x3 >= 0
np.concatenate([[0.0], [0, 0, 0, -1]]) # x4 >= 0
])
G = sp.vstack([G_soc, G_linear], format='csc')
h = np.array([0.0, 0.0, 0.0, 0.0, 0.0, -target_return, 0.0, 0.0, 0.0, 0.0])
A = sp.csc_matrix([np.concatenate([[0.0], np.ones(n_assets)])])
b = np.array([1.0])
dims = {'l': 5, 'q': [5]}
solution = ecos.solve(c, G, h, dims, A, b, verbose=False)
risk = solution['x'][0]
weights = solution['x'][1:]
print("Optimal portfolio risk:", risk)
print("Portfolio weights:", weights)
print("Expected return:", np.dot(mu, weights))
print("Weights sum to 1:", np.sum(weights))Explanation: