or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/ecos@2.0.x

docs

api-reference.mdexamples.mdindex.mdtroubleshooting.mdtypes-and-formats.md
tile.json

tessl/pypi-ecos

tessl install tessl/pypi-ecos@2.0.1

Python interface to ECOS, a numerical solver for convex second-order cone programs.

troubleshooting.mddocs/

Troubleshooting Guide

Common errors, issues, and solutions when using ECOS.

TypeError Issues

Error: "G must be a sparse matrix"

Cause: The inequality constraint matrix G is not a scipy sparse matrix.

Solution: Convert to scipy.sparse.csc_matrix:

import scipy.sparse as sp

# WRONG: Dense numpy array
G = np.array([[1.0, 2.0], [3.0, 4.0]])

# CORRECT: CSC sparse matrix
G = sp.csc_matrix([[1.0, 2.0], [3.0, 4.0]])

Prevention: Always use sp.csc_matrix() when creating constraint matrices.

Error: "A must be a sparse matrix"

Cause: The equality constraint matrix A is not a scipy sparse matrix.

Solution: Convert to scipy.sparse.csc_matrix:

import scipy.sparse as sp

# WRONG: Dense numpy array
A = np.array([[1.0, 2.0]])

# CORRECT: CSC sparse matrix
A = sp.csc_matrix([[1.0, 2.0]])

Error: "A and b must both be provided or both be None"

Cause: Provided only A without b, or only b without A.

Solution: Provide both or neither:

# WRONG: Only A provided
solution = ecos.solve(c, G, h, dims, A=A)

# CORRECT: Both provided
solution = ecos.solve(c, G, h, dims, A=A, b=b)

# CORRECT: Neither provided (no equality constraints)
solution = ecos.solve(c, G, h, dims)

Error: "Number of columns in A and G don't match"

Cause: A and G have different numbers of columns (different variable counts).

Solution: Ensure both matrices have the same number of columns:

n = 3  # Number of variables

# WRONG: Different column counts
G = sp.csc_matrix(np.zeros((5, 3)))  # 3 columns
A = sp.csc_matrix(np.zeros((2, 4)))  # 4 columns - MISMATCH

# CORRECT: Same column count
G = sp.csc_matrix(np.zeros((5, n)))  # n columns
A = sp.csc_matrix(np.zeros((2, n)))  # n columns
c = np.zeros(n)  # Must also match

Debugging:

print("Variables in c:", len(c))
print("Columns in G:", G.shape[1])
print("Columns in A:", A.shape[1] if A is not None else "N/A")
# All should be equal

Error: "verbose must be bool"

Cause: Keyword argument verbose has wrong type.

Solution: Use boolean values:

# WRONG: String
solution = ecos.solve(c, G, h, dims, verbose="true")

# WRONG: Integer
solution = ecos.solve(c, G, h, dims, verbose=1)

# CORRECT: Boolean
solution = ecos.solve(c, G, h, dims, verbose=True)
solution = ecos.solve(c, G, h, dims, verbose=False)

Error: "max_iters must be int"

Cause: Keyword argument max_iters is float instead of int.

Solution: Use integer values:

# WRONG: Float
solution = ecos.solve(c, G, h, dims, max_iters=100.0)

# CORRECT: Integer
solution = ecos.solve(c, G, h, dims, max_iters=100)

Prevention: All iteration-related parameters must be integers:

  • max_iters
  • nitref
  • mi_max_iters

Error: "dims['l'] must be non-negative integer"

Cause: The linear constraint dimension is negative or not an integer.

Solution: Use non-negative integer:

# WRONG: Negative
dims = {'l': -1, 'q': []}

# WRONG: Float
dims = {'l': 2.0, 'q': []}

# CORRECT: Non-negative integer
dims = {'l': 2, 'q': []}
dims = {'l': 0, 'q': [3]}  # Zero is valid

Error: "dims['q'] must be a list"

Cause: The second-order cone dimensions are specified as integer instead of list.

Solution: Always use a list (even for single cone):

# WRONG: Integer instead of list
dims = {'l': 0, 'q': 3}

# CORRECT: List with one element
dims = {'l': 0, 'q': [3]}

# CORRECT: Empty list (no SOCs)
dims = {'l': 5, 'q': []}

# CORRECT: Multiple cones
dims = {'l': 0, 'q': [3, 4, 2]}

ValueError Issues

Error: "Tolerance must be positive"

Cause: Provided negative or zero tolerance parameter.

Solution: All tolerances must be positive floats:

# WRONG: Negative tolerance
solution = ecos.solve(c, G, h, dims, feastol=-1e-8)

# WRONG: Zero tolerance
solution = ecos.solve(c, G, h, dims, abstol=0.0)

# CORRECT: Positive tolerance
solution = ecos.solve(c, G, h, dims, feastol=1e-8, abstol=1e-8, reltol=1e-8)

Affected parameters:

  • feastol
  • abstol
  • reltol
  • feastol_inacc
  • abstol_inacc
  • reltol_inacc
  • mi_abs_eps
  • mi_rel_eps
  • mi_int_tol

Error: "max_iters must be non-negative"

Cause: Provided negative iteration count.

Solution: Use non-negative integers:

# WRONG: Negative
solution = ecos.solve(c, G, h, dims, max_iters=-10)

# CORRECT: Non-negative
solution = ecos.solve(c, G, h, dims, max_iters=100)
solution = ecos.solve(c, G, h, dims, max_iters=0)  # Zero is valid (no iterations)

Error: "Invalid cone dimension in dims['q']"

Cause: Second-order cone dimension is not a positive integer.

Solution: All SOC dimensions must be >= 1:

# WRONG: Zero dimension
dims = {'l': 0, 'q': [0]}

# WRONG: Negative dimension
dims = {'l': 0, 'q': [3, -2]}

# CORRECT: Positive integers only
dims = {'l': 0, 'q': [3, 4, 2]}

Note: The minimum second-order cone dimension is 1, though typically cones have dimension >= 2 for meaningful constraints.

Error: "Cone dimensions don't match constraint matrix dimensions"

Cause: Total dimensions in dims don't sum to the number of rows in G.

Solution: Ensure dims['l'] + sum(dims['q']) + 3*dims['e'] equals G.shape[0]:

# Example: G has 10 rows
G = sp.csc_matrix(np.zeros((10, 3)))
h = np.zeros(10)

# WRONG: Only accounts for 5 rows
dims = {'l': 5, 'q': []}  # 5 ≠ 10

# WRONG: Accounts for 13 rows
dims = {'l': 5, 'q': [3, 5]}  # 5 + 3 + 5 = 13 ≠ 10

# CORRECT: Exactly 10 rows
dims = {'l': 4, 'q': [3, 3]}  # 4 + 3 + 3 = 10 ✓
dims = {'l': 10, 'q': []}     # 10 + 0 = 10 ✓
dims = {'l': 0, 'q': [10]}    # 0 + 10 = 10 ✓

Debugging:

m = G.shape[0]
dims_total = dims['l'] + sum(dims['q']) + 3 * dims.get('e', 0)
print(f"G rows: {m}, dims total: {dims_total}")
assert m == dims_total, f"Mismatch: {m} != {dims_total}"

Error: "Dimension mismatch between h and G"

Cause: Length of h doesn't match number of rows in G.

Solution: Ensure len(h) == G.shape[0]:

# WRONG: Dimension mismatch
G = sp.csc_matrix(np.zeros((5, 3)))  # 5 rows
h = np.zeros(3)  # Only 3 elements

# CORRECT: Matching dimensions
G = sp.csc_matrix(np.zeros((5, 3)))  # 5 rows
h = np.zeros(5)  # 5 elements

Error: "Dimension mismatch between b and A"

Cause: Length of b doesn't match number of rows in A.

Solution: Ensure len(b) == A.shape[0]:

# WRONG: Dimension mismatch
A = sp.csc_matrix(np.zeros((3, 5)))  # 3 rows
b = np.zeros(5)  # Wrong dimension

# CORRECT: Matching dimensions
A = sp.csc_matrix(np.zeros((3, 5)))  # 3 rows
b = np.zeros(3)  # 3 elements

Solver Convergence Issues

Issue: Solver doesn't converge (max iterations reached)

Symptoms:

  • Solution info shows exit flag indicating iteration limit
  • solution['info']['iter'] equals max_iters

Causes:

  1. Problem is poorly scaled
  2. Tolerance is too tight
  3. Problem is nearly infeasible
  4. Not enough iterations allowed

Solutions:

# Solution 1: Increase iteration limit
solution = ecos.solve(c, G, h, dims, max_iters=200)  # Default is typically 100

# Solution 2: Relax tolerances
solution = ecos.solve(
    c, G, h, dims,
    feastol=1e-6,  # Looser than default 1e-8
    abstol=1e-6,
    reltol=1e-6
)

# Solution 3: Use iterative refinement
solution = ecos.solve(c, G, h, dims, nitref=20)

# Solution 4: Check problem scaling
print("c range:", c.min(), "to", c.max())
print("G range:", G.data.min(), "to", G.data.max())
print("h range:", h.min(), "to", h.max())
# If ranges differ by many orders of magnitude, consider scaling

Scaling example:

# Scale variables and constraints
c_scale = np.max(np.abs(c))
c_scaled = c / c_scale

G_scale = np.max(np.abs(G.data))
G_scaled = G / G_scale

h_scale = np.max(np.abs(h))
h_scaled = h / h_scale

solution = ecos.solve(c_scaled, G_scaled, h_scaled, dims)
# Remember to unscale solution
x_original = solution['x']  # Already in original scale if only c was scaled

Issue: Solver reports infeasible problem

Symptoms:

  • Exit flag indicates infeasibility
  • solution['info'] shows infeasibility status

Causes:

  1. Constraints are contradictory
  2. Problem is actually infeasible
  3. Numerical issues make feasible problem appear infeasible

Debugging:

# Check if constraints can all be satisfied
# Start with equality constraints
if A is not None:
    print("Equality constraints: A*x = b")
    print("A shape:", A.shape)
    print("b:", b)

    # Check if system is consistent
    from scipy.linalg import lstsq
    x_eq, residual, rank, s = lstsq(A.toarray(), b)
    print("Least squares residual:", residual)
    if np.any(residual > 1e-10):
        print("WARNING: Equality constraints may be inconsistent")

# Check individual inequality constraints
print("\nInequality constraint analysis:")
for i in range(min(5, G.shape[0])):  # Check first few
    print(f"Constraint {i}: G[{i},:]*x <= {h[i]}")

Solutions:

# Solution 1: Relax tight constraints
h_relaxed = h + 1e-6  # Add small margin

# Solution 2: Check for redundant or conflicting constraints
# Remove or modify conflicting constraints

# Solution 3: Use inaccurate tolerances (solver tries harder)
solution = ecos.solve(
    c, G, h, dims,
    feastol_inacc=1e-3,
    abstol_inacc=1e-4,
    reltol_inacc=1e-4
)

Issue: Solution is inaccurate

Symptoms:

  • Constraints are violated
  • Objective value doesn't match expected
  • Large residuals in solution['info']

Debugging:

solution = ecos.solve(c, G, h, dims, A, b)
x = solution['x']

# Check constraint violations
if A is not None:
    eq_violation = np.linalg.norm(A @ x - b)
    print("Equality constraint violation:", eq_violation)

ineq_slack = h - G @ x
ineq_violation = np.sum(np.minimum(ineq_slack, 0))  # Negative = violation
print("Inequality constraint violation:", ineq_violation)

# Check optimality
print("Objective value:", c @ x)
print("Solver info:", solution['info'])

Solutions:

# Solution 1: Tighten tolerances
solution = ecos.solve(
    c, G, h, dims,
    feastol=1e-9,
    abstol=1e-9,
    reltol=1e-9,
    max_iters=200
)

# Solution 2: More iterative refinement
solution = ecos.solve(c, G, h, dims, nitref=20)

# Solution 3: Check problem conditioning
# Ill-conditioned problems may need rescaling

Mixed-Integer Issues

Issue: Mixed-integer solver is very slow

Causes:

  1. Too many integer variables
  2. Branch-and-bound tree is large
  3. Gap tolerances are too tight

Solutions:

# Solution 1: Relax gap tolerances
solution = ecos.solve(
    c, G, h, dims,
    bool_vars_idx=bool_idx,
    mi_abs_eps=1e-3,  # Looser than default
    mi_rel_eps=1e-2,
    mi_max_iters=500
)

# Solution 2: Provide good initial bound (if known)
# Solve continuous relaxation first
relaxed = ecos.solve(c, G, h, dims)
print("Relaxed objective:", c @ relaxed['x'])
# Use this information to guide expectations

# Solution 3: Limit branch-and-bound iterations
solution = ecos.solve(
    c, G, h, dims,
    bool_vars_idx=bool_idx,
    mi_max_iters=100,  # Stop early if needed
    mi_verbose=True    # Monitor progress
)

Issue: Integer solution is suboptimal

Symptoms:

  • Solution doesn't match expected integer optimum
  • Integer variables are not exactly 0 or 1

Debugging:

solution = ecos.solve(
    c, G, h, dims,
    bool_vars_idx=bool_idx,
    mi_verbose=True
)

x = solution['x']
for idx in bool_idx:
    print(f"x[{idx}] = {x[idx]}")
    if not (np.isclose(x[idx], 0.0) or np.isclose(x[idx], 1.0)):
        print(f"  WARNING: Not exactly 0 or 1")

Solutions:

# Solution 1: Tighten integer tolerance
solution = ecos.solve(
    c, G, h, dims,
    bool_vars_idx=bool_idx,
    mi_int_tol=1e-6  # Default is typically 1e-4
)

# Solution 2: Round solution manually (use with caution)
x = solution['x']
for idx in bool_idx:
    x[idx] = np.round(x[idx])

# Verify constraints are still satisfied
if A is not None:
    print("Equality violation after rounding:", np.linalg.norm(A @ x - b))
print("Inequality violation after rounding:", np.sum(np.minimum(h - G @ x, 0)))

# Solution 3: Allow more branch-and-bound iterations
solution = ecos.solve(
    c, G, h, dims,
    bool_vars_idx=bool_idx,
    mi_max_iters=2000
)

Performance Issues

Issue: Solver is too slow

Causes:

  1. Problem is very large
  2. Dense constraint matrices
  3. Too many iterative refinement steps
  4. Ill-conditioned problem

Solutions:

# Solution 1: Ensure matrices are sparse
print("G sparsity:", G.nnz / (G.shape[0] * G.shape[1]))
# Should be much less than 1.0 for large problems

# Solution 2: Reduce iterative refinement
solution = ecos.solve(c, G, h, dims, nitref=5)  # Default is ~9

# Solution 3: Loosen tolerances
solution = ecos.solve(
    c, G, h, dims,
    feastol=1e-6,  # Less accurate but faster
    abstol=1e-6,
    reltol=1e-6
)

# Solution 4: Consider if ECOS is the right solver
# For very large problems (>100,000 variables), consider:
# - SCS (larger scale, less accurate)
# - Mosek or Gurobi (commercial, very fast)

Issue: Memory usage is too high

Causes:

  1. Using dense matrices instead of sparse
  2. Problem is too large for available memory

Solutions:

# Solution 1: Verify sparse format
print("G is sparse:", sp.isspmatrix(G))
print("G memory (bytes):", G.data.nbytes + G.indices.nbytes + G.indptr.nbytes)

# If you accidentally created dense:
G_dense = G.toarray()  # DON'T DO THIS for large matrices
# Instead keep in sparse format

# Solution 2: Use CSC format (required by ECOS)
# CSC is optimal for column-wise operations

# Solution 3: For extremely large problems, consider problem decomposition
# Break problem into smaller subproblems if possible

Warning Messages

Warning: "Converting G to CSC format"

Cause: G was provided in a sparse format other than CSC (e.g., CSR, COO).

Impact: Automatic conversion happens but adds overhead.

Solution: Create matrix as CSC from the start:

# CAUSES WARNING: CSR format
G = sp.csr_matrix([[1.0, 2.0], [3.0, 4.0]])
solution = ecos.solve(c, G, h, dims)  # Warning printed

# PREFERRED: CSC format
G = sp.csc_matrix([[1.0, 2.0], [3.0, 4.0]])
solution = ecos.solve(c, G, h, dims)  # No warning

Common Programming Mistakes

Mistake: Forgetting to specify dims['q'] as list

# WRONG
dims = {'l': 0, 'q': 3}  # Integer, not list

# CORRECT
dims = {'l': 0, 'q': [3]}  # List with one element

Mistake: Inconsistent variable indexing

# Setup
n = 3
c = np.array([1.0, 2.0, 3.0])  # 3 variables

# WRONG: G has wrong number of columns
G = sp.csc_matrix([[1.0, 2.0]])  # Only 2 columns

# CORRECT: Consistent dimensions
G = sp.csc_matrix([[1.0, 2.0, 3.0]])  # 3 columns matching c

Mistake: Confusing SOC constraint order

# Second-order cone: (t, x) where t >= ||x||
# First row is the BOUND, remaining rows are the VECTOR

# WRONG interpretation: want x[0] >= ||(x[1], x[2])||
dims = {'l': 0, 'q': [3]}
# Rows 0, 1, 2 of G correspond to (t, x1, x2) of cone
# So G[0,:]*x is the bound, G[1,:]*x and G[2,:]*x are the vector components

# CORRECT setup:
# If variables are [x0, x1, x2] and we want x0 >= ||(x1, x2)||:
G = sp.csc_matrix([
    [1.0, 0.0, 0.0],  # Row 0: x0 (bound)
    [0.0, 1.0, 0.0],  # Row 1: x1 (vector component 1)
    [0.0, 0.0, 1.0]   # Row 2: x2 (vector component 2)
])
h = np.zeros(3)
dims = {'l': 0, 'q': [3]}

Mistake: Not checking solution status

# BAD: Blindly using solution
solution = ecos.solve(c, G, h, dims)
x = solution['x']  # May be infeasible or inaccurate!

# GOOD: Check solver status first
solution = ecos.solve(c, G, h, dims)
info = solution['info']

exit_flag = info.get('exitFlag', None)
if exit_flag == 0:
    print("Optimal solution found")
    x = solution['x']
elif exit_flag == 1:
    print("Inaccurate solution (might be acceptable)")
    x = solution['x']
else:
    print("Solver did not converge properly")
    print("Info:", info)
    # Handle error case

Diagnostic Checklist

When encountering issues, check:

  1. Matrix formats:

    print("G is CSC:", sp.isspmatrix_csc(G))
    print("A is CSC:", sp.isspmatrix_csc(A) if A is not None else "N/A")
  2. Dimension consistency:

    n = len(c)
    m = G.shape[0]
    p = A.shape[0] if A is not None else 0
    
    print(f"Variables: {n}")
    print(f"Inequality constraints: {m}")
    print(f"Equality constraints: {p}")
    print(f"G shape: {G.shape}, expected ({m}, {n})")
    if A is not None:
        print(f"A shape: {A.shape}, expected ({p}, {n})")
    print(f"h shape: {h.shape}, expected ({m},)")
    if b is not None:
        print(f"b shape: {b.shape}, expected ({p},)")
  3. Cone dimensions:

    dims_total = dims['l'] + sum(dims['q']) + 3 * dims.get('e', 0)
    print(f"Total cone dimension: {dims_total}")
    print(f"G rows: {G.shape[0]}")
    print(f"Match: {dims_total == G.shape[0]}")
  4. Data types:

    print(f"c dtype: {c.dtype}")
    print(f"h dtype: {h.dtype}")
    print(f"G dtype: {G.dtype}")
  5. Solution quality:

    solution = ecos.solve(c, G, h, dims, A, b)
    x = solution['x']
    
    print("Objective value:", c @ x)
    if A is not None:
        print("Equality residual:", np.linalg.norm(A @ x - b))
    print("Inequality slack range:", (h - G @ x).min(), "to", (h - G @ x).max())
    print("Exit flag:", solution['info'].get('exitFlag'))
    print("Iterations:", solution['info'].get('iter'))