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.

types-and-formats.mddocs/

Types and Formats Reference

Complete specification of all data types and formats used by ECOS.

Core Data Types

Objective Coefficient Vector: c

Type: numpy.ndarray with dtype float64

Shape: (n,) where n is the number of optimization variables

Purpose: Coefficients for the linear objective function to minimize: c'*x

Requirements:

  • Must be 1-dimensional array
  • Length determines the number of variables in the problem
  • All other matrices must have n columns to match

Creation:

import numpy as np

# From list
c = np.array([1.0, 2.0, 3.0])

# From explicit float values
c = np.array([-1.0])

# With specified dtype (optional but recommended)
c = np.array([1.0, 2.0, 3.0], dtype=np.float64)

# Check shape
print(c.shape)  # (3,) - 1D array with 3 elements

Common Errors:

# ERROR: 2D array instead of 1D
c = np.array([[1.0, 2.0]])  # Shape (1, 2) - WRONG

# CORRECT: 1D array
c = np.array([1.0, 2.0])    # Shape (2,) - CORRECT

# ERROR: Python list (not numpy array)
c = [1.0, 2.0]  # May cause issues

# CORRECT: Convert to numpy array
c = np.array([1.0, 2.0])

Constraint Right-Hand Side Vectors: h and b

Type: numpy.ndarray with dtype float64

Shape:

  • h: (m,) where m is the total cone dimension (number of rows in G)
  • b: (p,) where p is the number of equality constraints (number of rows in A)

Purpose:

  • h: Right-hand side for inequality constraints G*x <=_K h
  • b: Right-hand side for equality constraints A*x = b

Requirements:

  • Must be 1-dimensional arrays
  • Length must match corresponding constraint matrix rows
  • Both or neither of A and b must be provided

Creation:

import numpy as np

# Match constraint dimensions
m = 5  # Number of inequality constraints
p = 2  # Number of equality constraints

h = np.array([1.0, 2.0, 0.0, 0.0, 3.0])  # Length m
b = np.array([5.0, 10.0])                # Length p

# From zeros
h = np.zeros(m)
b = np.ones(p)

Sparse Matrix Format

Constraint Matrices: G and A

Type: scipy.sparse.csc_matrix (Compressed Sparse Column format)

Shape:

  • G: (m, n) where m is total cone dimension, n is number of variables
  • A: (p, n) where p is number of equality constraints, n is number of variables

Purpose:

  • G: Left-hand side of inequality constraints G*x <=_K h
  • A: Left-hand side of equality constraints A*x = b

Critical Requirements:

  • MUST be scipy.sparse.csc_matrix (not dense array, not list, not other sparse formats)
  • Number of columns (n) must match length of c
  • G and A must have the same number of columns if both provided
  • Will be automatically converted from other sparse formats with a warning

Creating CSC Matrices

Method 1: From Dense Array or List

import numpy as np
import scipy.sparse as sp

# From list of lists
G = sp.csc_matrix([[1.0, 2.0], [3.0, 4.0]])

# From numpy array
G_dense = np.array([[1.0, 2.0], [3.0, 4.0]])
G = sp.csc_matrix(G_dense)

# Single row or column
G = sp.csc_matrix([[1.0, 2.0, 3.0]])  # Shape (1, 3)
G = sp.csc_matrix([[1.0], [2.0], [3.0]])  # Shape (3, 1)

Method 2: From Data, Row Indices, Column Pointers

import numpy as np
import scipy.sparse as sp

# CSC format: (data, row_indices, col_pointers)
# Matrix: [[1, 0], [0, 2], [3, 0]]
data = np.array([1.0, 3.0, 2.0])
row_indices = np.array([0, 2, 1])  # Row index of each nonzero
col_pointers = np.array([0, 2, 3])  # Start index of each column

G = sp.csc_matrix((data, row_indices, col_pointers), shape=(3, 2))

Method 3: From Coordinate Format (COO)

import numpy as np
import scipy.sparse as sp

# Specify (row, col, value) for each nonzero
rows = np.array([0, 1, 2])
cols = np.array([0, 1, 0])
data = np.array([1.0, 2.0, 3.0])

G_coo = sp.coo_matrix((data, (rows, cols)), shape=(3, 2))
G = sp.csc_matrix(G_coo)  # Convert to CSC

Method 4: Building Incrementally (LIL format)

import scipy.sparse as sp

# Use LIL (List of Lists) for construction
G_lil = sp.lil_matrix((3, 4))
G_lil[0, 0] = 1.0
G_lil[1, 2] = 2.0
G_lil[2, 1] = 3.0

# Convert to CSC for ECOS
G = sp.csc_matrix(G_lil)

Method 5: Stacking Multiple Matrices

import numpy as np
import scipy.sparse as sp

# Create separate constraint blocks
G_block1 = sp.csc_matrix([[1.0, 2.0], [3.0, 4.0]])
G_block2 = sp.csc_matrix([[5.0, 6.0]])

# Stack vertically
G = sp.vstack([G_block1, G_block2], format='csc')

# Stack horizontally (for more variables)
G_left = sp.csc_matrix([[1.0], [2.0]])
G_right = sp.csc_matrix([[3.0], [4.0]])
G = sp.hstack([G_left, G_right], format='csc')

Common Matrix Format Errors

import numpy as np
import scipy.sparse as sp

# ERROR: Dense numpy array
G = np.array([[1.0, 2.0], [3.0, 4.0]])
solution = ecos.solve(c, G, h, dims)  # TypeError

# ERROR: Python list
G = [[1.0, 2.0], [3.0, 4.0]]
solution = ecos.solve(c, G, h, dims)  # TypeError

# WARNING: CSR format (will be converted with warning)
G = sp.csr_matrix([[1.0, 2.0], [3.0, 4.0]])
solution = ecos.solve(c, G, h, dims)  # Works but prints warning

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

Verifying Matrix Format

import scipy.sparse as sp

# Check if matrix is CSC
print(type(G))  # <class 'scipy.sparse._csc.csc_matrix'>
print(sp.isspmatrix_csc(G))  # True

# Check dimensions
print(G.shape)  # (m, n)

# View as dense (for debugging only)
print(G.toarray())

# Check sparsity
print(G.nnz)  # Number of non-zero elements

Cone Dimensions Dictionary

Structure: dims

Type: dict with specific keys

Required Keys:

  • 'l': Number of linear inequality constraints (positive orthant dimension)
  • 'q': List of second-order cone dimensions

Optional Keys:

  • 'e': Number of exponential cones

Purpose: Specifies the structure of the cone K in the constraint G*x <=_K h

Detailed Specification

Linear Inequalities: dims['l']

Type: int (non-negative integer)

Meaning: Number of linear inequality constraints (positive orthant constraints)

Constraint: First dims['l'] rows of G*x <= h are interpreted as element-wise inequalities

# 3 linear inequalities
dims = {'l': 3, 'q': []}

# Corresponds to:
# G[0,:] * x <= h[0]
# G[1,:] * x <= h[1]
# G[2,:] * x <= h[2]

Requirements:

  • Must be non-negative: dims['l'] >= 0
  • Can be 0 if no linear constraints: dims = {'l': 0, 'q': [...]}

Second-Order Cones: dims['q']

Type: list of positive integers

Meaning: Each element specifies the dimension of one second-order cone

Constraint: Each cone in the list corresponds to consecutive rows in G

# One 3-dimensional SOC, one 4-dimensional SOC
dims = {'l': 0, 'q': [3, 4]}

# Corresponds to:
# (G[0,:]*x, G[1,:]*x, G[2,:]*x) in Q_3  (rows 0-2)
# (G[3,:]*x, G[4,:]*x, G[5,:]*x, G[6,:]*x) in Q_4  (rows 3-6)

Second-Order Cone Definition:

  • Q_n = {(t, x) | t >= ||x||_2} where t is scalar and x is (n-1)-dimensional
  • First component is the bound, remaining components are the vector

Requirements:

  • Must be a list (even if empty): dims = {'l': 5, 'q': []}
  • Each element must be positive integer >= 1
  • Cannot use single integer: dims = {'l': 0, 'q': 3} is WRONG
  • Correct: dims = {'l': 0, 'q': [3]}

Exponential Cones: dims['e']

Type: int (non-negative integer)

Meaning: Number of exponential cones (each has dimension 3)

Constraint: Exponential cone constraints follow linear and SOC constraints in G

# 2 linear, one 3-dim SOC, one exponential cone
dims = {'l': 2, 'q': [3], 'e': 1}

# Total rows in G: 2 + 3 + 3 = 8
# Rows 0-1: linear
# Rows 2-4: SOC
# Rows 5-7: exponential cone

Exponential Cone Definition:

  • K_exp = {(x, y, z) | y*exp(x/y) <= z, y > 0}
  • Used for entropy and exponential constraints

Dimension Matching Rule

Critical Requirement: Total cone dimensions must equal number of rows in G

total_dim = dims['l'] + sum(dims['q']) + 3 * dims.get('e', 0)
assert total_dim == G.shape[0]
assert total_dim == len(h)

Examples:

# Example 1: Only linear
G.shape = (5, 3)
dims = {'l': 5, 'q': []}  # 5 + 0 = 5 ✓

# Example 2: Only SOCs
G.shape = (7, 3)
dims = {'l': 0, 'q': [3, 4]}  # 0 + 3 + 4 = 7 ✓

# Example 3: Mixed
G.shape = (10, 3)
dims = {'l': 2, 'q': [3, 5]}  # 2 + 3 + 5 = 10 ✓

# Example 4: With exponential
G.shape = (11, 3)
dims = {'l': 2, 'q': [3], 'e': 2}  # 2 + 3 + 3*2 = 11 ✓

# ERROR: Dimension mismatch
G.shape = (7, 3)
dims = {'l': 5, 'q': []}  # 5 ≠ 7 ✗

Complete Examples

import scipy.sparse as sp
import numpy as np

# Example 1: Pure LP
n = 3  # variables
m = 5  # constraints

c = np.zeros(n)
G = sp.csc_matrix(np.random.randn(m, n))
h = np.zeros(m)
dims = {'l': 5, 'q': []}  # All linear

# Example 2: Pure SOCP
n = 4
m = 7

c = np.zeros(n)
G = sp.csc_matrix(np.random.randn(m, n))
h = np.zeros(m)
dims = {'l': 0, 'q': [3, 4]}  # Two SOCs

# Example 3: Mixed LP + SOCP
n = 5
m = 10

c = np.zeros(n)
G = sp.csc_matrix(np.random.randn(m, n))
h = np.zeros(m)
dims = {'l': 3, 'q': [4, 3]}  # 3 linear + two SOCs (3 + 4 + 3 = 10)

Solution Dictionary Type

Structure

solution: dict = {
    'x': numpy.ndarray,    # shape (n,)
    'y': numpy.ndarray,    # shape (p,) or (0,)
    's': numpy.ndarray,    # shape (m,)
    'z': numpy.ndarray,    # shape (m,)
    'info': dict
}

Field Specifications

solution['x']: Primal Solution

  • Type: numpy.ndarray with dtype float64
  • Shape: (n,) where n is the number of variables
  • Content: Optimal values of the decision variables
  • Access: optimal_x = solution['x']

solution['y']: Dual Variables (Equality)

  • Type: numpy.ndarray with dtype float64
  • Shape: (p,) if equality constraints exist, (0,) otherwise
  • Content: Lagrange multipliers for A*x = b constraints
  • Access: dual_eq = solution['y']
  • Note: Empty array if A and b were not provided

solution['s']: Slack Variables

  • Type: numpy.ndarray with dtype float64
  • Shape: (m,) where m is total cone dimension
  • Content: Slack variables satisfying s = h - G*x and s in K
  • Access: slack = solution['s']

solution['z']: Dual Variables (Cone)

  • Type: numpy.ndarray with dtype float64
  • Shape: (m,) where m is total cone dimension
  • Content: Lagrange multipliers for G*x <=_K h, lying in dual cone K*
  • Access: dual_cone = solution['z']

solution['info']: Solver Information

  • Type: dict
  • Content: Implementation-specific solver statistics
  • Common Fields:
    • Exit status/flag
    • Iteration count
    • Timing information
    • Residuals and gaps
    • Convergence indicators

Example Access:

info = solution['info']
exit_flag = info.get('exitFlag', None)
iterations = info.get('iter', None)
solve_time = info.get('timing', {}).get('tsolve', None)

Type Validation Examples

Complete Type-Safe Problem Setup

import numpy as np
import scipy.sparse as sp
import ecos

# Problem dimensions
n = 3  # Number of variables
m = 5  # Total cone dimension (inequality constraints)
p = 2  # Number of equality constraints

# Objective (1D float array)
c = np.array([1.0, 2.0, 3.0], dtype=np.float64)
assert c.shape == (n,)
assert c.dtype == np.float64

# Inequality constraint matrix (sparse CSC)
G = sp.csc_matrix(np.random.randn(m, n))
assert sp.isspmatrix_csc(G)
assert G.shape == (m, n)

# Inequality RHS (1D float array)
h = np.zeros(m, dtype=np.float64)
assert h.shape == (m,)
assert h.dtype == np.float64

# Equality constraint matrix (sparse CSC)
A = sp.csc_matrix(np.random.randn(p, n))
assert sp.isspmatrix_csc(A)
assert A.shape == (p, n)

# Equality RHS (1D float array)
b = np.ones(p, dtype=np.float64)
assert b.shape == (p,)
assert b.dtype == np.float64

# Cone dimensions (dict with specific structure)
dims = {'l': 2, 'q': [3]}
assert isinstance(dims, dict)
assert 'l' in dims and 'q' in dims
assert isinstance(dims['l'], int) and dims['l'] >= 0
assert isinstance(dims['q'], list)
assert dims['l'] + sum(dims['q']) == m

# Solve
solution = ecos.solve(c, G, h, dims, A, b)

# Validate solution types
assert isinstance(solution, dict)
assert isinstance(solution['x'], np.ndarray)
assert solution['x'].shape == (n,)
assert isinstance(solution['y'], np.ndarray)
assert solution['y'].shape == (p,)
assert isinstance(solution['s'], np.ndarray)
assert solution['s'].shape == (m,)
assert isinstance(solution['z'], np.ndarray)
assert solution['z'].shape == (m,)
assert isinstance(solution['info'], dict)

Type Conversion Helpers

import numpy as np
import scipy.sparse as sp

def ensure_csc_matrix(M):
    """Convert matrix to CSC format if needed."""
    if M is None:
        return None
    if sp.isspmatrix_csc(M):
        return M
    if sp.isspmatrix(M):
        return sp.csc_matrix(M)
    # Assume dense array or list
    return sp.csc_matrix(M)

def ensure_float_array(v):
    """Convert vector to float64 numpy array."""
    if isinstance(v, np.ndarray):
        return v.astype(np.float64)
    return np.array(v, dtype=np.float64)

# Usage
G = ensure_csc_matrix([[1.0, 2.0], [3.0, 4.0]])
c = ensure_float_array([1.0, 2.0])
h = ensure_float_array([0.0, 0.0])