Skip to content

Utilities

Helper functions and data structures used internally by solvers, also available for custom implementations.

Overview

Category Contents
Data Structures FenwickTree, UnionFind - efficient structures for algorithms
Validation Input checking functions with clear error messages
Helpers Debugging, evaluation tracking, progress utilities

Quick Examples

from solvor.utils import FenwickTree, UnionFind, debug

# Fenwick tree for prefix sums
ft = FenwickTree([1, 2, 3, 4, 5])
ft.prefix(2)       # 6 (sum of indices 0, 1, 2)
ft.update(1, 10)   # add 10 to index 1
ft.range_sum(1, 3) # sum of indices 1, 2, 3

# Union-Find for connected components
uf = UnionFind(10)
uf.union(0, 1)
uf.union(1, 2)
uf.connected(0, 2)  # True
uf.component_count  # 8

# Debug output (only prints when DEBUG=1)
debug("solving iteration", i)

Validation Functions

Used internally by solvers to validate inputs before solving. Provides clear error messages for common mistakes.

from solvor.utils import check_matrix_dims, check_positive, check_bounds

# Validate LP dimensions
check_matrix_dims(c, A, b)  # Raises if dimensions mismatch

# Validate parameter ranges
check_positive(n_nodes, name="n_nodes")
check_bounds(bounds)  # Validates (low, high) pairs
Function Purpose
check_matrix_dims(c, A, b) LP/MILP dimension consistency
check_positive(val, name) val > 0
check_non_negative(val, name) val >= 0
check_in_range(val, lo, hi, name) lo <= val <= hi
check_bounds(bounds) Valid (low, high) pairs
check_edge_nodes(edges, n_nodes) Edge endpoints valid
check_sequence_lengths(seqs, names) Parallel sequences same length
warn_large_coefficients(A) Warns if max > 1e10

Data Structures

solvor.utils.data_structures

Data structures for optimization algorithms.

Efficient data structures used internally by solvers. Also available for custom implementations requiring these classic structures.

from solvor.utils import UnionFind, FenwickTree

uf = UnionFind(10)        # Disjoint sets for cycle detection
ft = FenwickTree([1,2,3]) # Prefix sums with point updates

FenwickTree

Fenwick Tree (Binary Indexed Tree) for prefix sums with point updates.

Supports O(log n) prefix sum queries and point updates. Useful for cumulative frequency tables, range sum queries, and inversion counting.

ft = FenwickTree([1, 2, 3, 4, 5])
ft.prefix(2)      # 6 (sum of indices 0, 1, 2)
ft.update(1, 10)  # add 10 to index 1
ft.prefix(2)      # 16
ft.range_sum(1, 3)  # sum of indices 1, 2, 3
Source code in solvor/utils/data_structures.py
class FenwickTree:
    """
    Fenwick Tree (Binary Indexed Tree) for prefix sums with point updates.

    Supports O(log n) prefix sum queries and point updates. Useful for
    cumulative frequency tables, range sum queries, and inversion counting.

        ft = FenwickTree([1, 2, 3, 4, 5])
        ft.prefix(2)      # 6 (sum of indices 0, 1, 2)
        ft.update(1, 10)  # add 10 to index 1
        ft.prefix(2)      # 16
        ft.range_sum(1, 3)  # sum of indices 1, 2, 3
    """

    __slots__ = ("_tree", "_n")

    def __init__(self, values: list[float] | int) -> None:
        """Initialize from values list or size (zeros)."""
        if isinstance(values, int):
            self._n = values
            self._tree = [0.0] * values
        else:
            self._n = len(values)
            self._tree = list(values)
            for i in range(self._n):
                j = i | (i + 1)
                if j < self._n:
                    self._tree[j] += self._tree[i]

    def update(self, i: int, delta: float) -> None:
        """Add delta to element at index i."""
        while i < self._n:
            self._tree[i] += delta
            i |= i + 1

    def prefix(self, i: int) -> float:
        """Return sum of elements from index 0 to i (inclusive)."""
        total = 0.0
        while i >= 0:
            total += self._tree[i]
            i = (i & (i + 1)) - 1
        return total

    def range_sum(self, left: int, right: int) -> float:
        """Return sum of elements from left to right (inclusive)."""
        result = self.prefix(right)
        if left > 0:
            result -= self.prefix(left - 1)
        return result

    def __len__(self) -> int:
        """Return number of elements."""
        return self._n

    def __repr__(self) -> str:
        return f"FenwickTree(n={self._n})"

__init__(values)

Initialize from values list or size (zeros).

Source code in solvor/utils/data_structures.py
def __init__(self, values: list[float] | int) -> None:
    """Initialize from values list or size (zeros)."""
    if isinstance(values, int):
        self._n = values
        self._tree = [0.0] * values
    else:
        self._n = len(values)
        self._tree = list(values)
        for i in range(self._n):
            j = i | (i + 1)
            if j < self._n:
                self._tree[j] += self._tree[i]

__len__()

Return number of elements.

Source code in solvor/utils/data_structures.py
def __len__(self) -> int:
    """Return number of elements."""
    return self._n

prefix(i)

Return sum of elements from index 0 to i (inclusive).

Source code in solvor/utils/data_structures.py
def prefix(self, i: int) -> float:
    """Return sum of elements from index 0 to i (inclusive)."""
    total = 0.0
    while i >= 0:
        total += self._tree[i]
        i = (i & (i + 1)) - 1
    return total

range_sum(left, right)

Return sum of elements from left to right (inclusive).

Source code in solvor/utils/data_structures.py
def range_sum(self, left: int, right: int) -> float:
    """Return sum of elements from left to right (inclusive)."""
    result = self.prefix(right)
    if left > 0:
        result -= self.prefix(left - 1)
    return result

update(i, delta)

Add delta to element at index i.

Source code in solvor/utils/data_structures.py
def update(self, i: int, delta: float) -> None:
    """Add delta to element at index i."""
    while i < self._n:
        self._tree[i] += delta
        i |= i + 1

UnionFind

Union-Find (Disjoint Set Union) data structure.

Efficiently tracks connected components with near O(1) operations via path compression and union by rank.

uf = UnionFind(10)
uf.union(0, 1)
uf.union(1, 2)
uf.connected(0, 2)  # True
uf.component_count  # 8 (started with 10, merged 3 into 1)
Source code in solvor/utils/data_structures.py
class UnionFind:
    """
    Union-Find (Disjoint Set Union) data structure.

    Efficiently tracks connected components with near O(1) operations via
    path compression and union by rank.

        uf = UnionFind(10)
        uf.union(0, 1)
        uf.union(1, 2)
        uf.connected(0, 2)  # True
        uf.component_count  # 8 (started with 10, merged 3 into 1)
    """

    __slots__ = ("_parent", "_rank", "_count")

    def __init__(self, n: int) -> None:
        """Initialize n elements, each in its own component."""
        self._parent = list(range(n))
        self._rank = [0] * n
        self._count = n

    def find(self, x: int) -> int:
        """Find root of x with path compression."""
        if self._parent[x] != x:
            self._parent[x] = self.find(self._parent[x])
        return self._parent[x]

    def union(self, x: int, y: int) -> bool:
        """Merge components containing x and y. Returns True if merged."""
        rx, ry = self.find(x), self.find(y)
        if rx == ry:
            return False

        if self._rank[rx] < self._rank[ry]:
            rx, ry = ry, rx
        self._parent[ry] = rx
        if self._rank[rx] == self._rank[ry]:
            self._rank[rx] += 1

        self._count -= 1
        return True

    def connected(self, x: int, y: int) -> bool:
        """Check if x and y are in the same component."""
        return self.find(x) == self.find(y)

    @property
    def component_count(self) -> int:
        """Number of disjoint components."""
        return self._count

    def component_sizes(self) -> list[int]:
        """Return list of component sizes."""
        size_map: dict[int, int] = {}
        for i in range(len(self._parent)):
            root = self.find(i)
            size_map[root] = size_map.get(root, 0) + 1
        return list(size_map.values())

    def get_components(self) -> list[set[int]]:
        """Return list of sets, each containing elements of one component."""
        comp_map: dict[int, set[int]] = {}
        for i in range(len(self._parent)):
            root = self.find(i)
            if root not in comp_map:
                comp_map[root] = set()
            comp_map[root].add(i)
        return list(comp_map.values())

    def __len__(self) -> int:
        """Return number of elements."""
        return len(self._parent)

    def __repr__(self) -> str:
        return f"UnionFind(n={len(self._parent)}, components={self._count})"

component_count property

Number of disjoint components.

__init__(n)

Initialize n elements, each in its own component.

Source code in solvor/utils/data_structures.py
def __init__(self, n: int) -> None:
    """Initialize n elements, each in its own component."""
    self._parent = list(range(n))
    self._rank = [0] * n
    self._count = n

__len__()

Return number of elements.

Source code in solvor/utils/data_structures.py
def __len__(self) -> int:
    """Return number of elements."""
    return len(self._parent)

component_sizes()

Return list of component sizes.

Source code in solvor/utils/data_structures.py
def component_sizes(self) -> list[int]:
    """Return list of component sizes."""
    size_map: dict[int, int] = {}
    for i in range(len(self._parent)):
        root = self.find(i)
        size_map[root] = size_map.get(root, 0) + 1
    return list(size_map.values())

connected(x, y)

Check if x and y are in the same component.

Source code in solvor/utils/data_structures.py
def connected(self, x: int, y: int) -> bool:
    """Check if x and y are in the same component."""
    return self.find(x) == self.find(y)

find(x)

Find root of x with path compression.

Source code in solvor/utils/data_structures.py
def find(self, x: int) -> int:
    """Find root of x with path compression."""
    if self._parent[x] != x:
        self._parent[x] = self.find(self._parent[x])
    return self._parent[x]

get_components()

Return list of sets, each containing elements of one component.

Source code in solvor/utils/data_structures.py
def get_components(self) -> list[set[int]]:
    """Return list of sets, each containing elements of one component."""
    comp_map: dict[int, set[int]] = {}
    for i in range(len(self._parent)):
        root = self.find(i)
        if root not in comp_map:
            comp_map[root] = set()
        comp_map[root].add(i)
    return list(comp_map.values())

union(x, y)

Merge components containing x and y. Returns True if merged.

Source code in solvor/utils/data_structures.py
def union(self, x: int, y: int) -> bool:
    """Merge components containing x and y. Returns True if merged."""
    rx, ry = self.find(x), self.find(y)
    if rx == ry:
        return False

    if self._rank[rx] < self._rank[ry]:
        rx, ry = ry, rx
    self._parent[ry] = rx
    if self._rank[rx] == self._rank[ry]:
        self._rank[rx] += 1

    self._count -= 1
    return True

Helpers

solvor.utils.helpers

Helper functions for optimization tasks, debugging, and evaluation.

Small, stable helpers used across solvers for common operations like objective function wrapping, progress reporting, and solution manipulation.

from solvor.utils import debug, Evaluator, report_progress
from solvor.utils import random_permutation, pairwise_swap_neighbors

Evaluator

Wraps objective function to track evaluations and handle minimize/maximize.

The internal objective values are sign-adjusted so that minimization always means finding smaller values. Use to_user() to convert back for reporting.

Example

evaluator = Evaluator(objective_fn, minimize=True) obj = evaluator(solution) # Internal (signed) value user_obj = evaluator.to_user(obj) # User-facing value print(f"Evaluations: {evaluator.evals}")

Source code in solvor/utils/helpers.py
class Evaluator[T]:
    """Wraps objective function to track evaluations and handle minimize/maximize.

    The internal objective values are sign-adjusted so that minimization always
    means finding smaller values. Use `to_user()` to convert back for reporting.

    Example:
        evaluator = Evaluator(objective_fn, minimize=True)
        obj = evaluator(solution)  # Internal (signed) value
        user_obj = evaluator.to_user(obj)  # User-facing value
        print(f"Evaluations: {evaluator.evals}")
    """

    __slots__ = ("objective_fn", "sign", "evals")

    def __init__(self, objective_fn: Callable[[T], float], minimize: bool = True):
        self.objective_fn = objective_fn
        self.sign = 1 if minimize else -1
        self.evals = 0

    def __call__(self, sol: T) -> float:
        """Evaluate solution, returning internal (signed) value."""
        self.evals += 1
        return self.sign * self.objective_fn(sol)

    def to_user(self, internal_obj: float) -> float:
        """Convert internal objective to user-facing value."""
        return internal_obj * self.sign

__call__(sol)

Evaluate solution, returning internal (signed) value.

Source code in solvor/utils/helpers.py
def __call__(self, sol: T) -> float:
    """Evaluate solution, returning internal (signed) value."""
    self.evals += 1
    return self.sign * self.objective_fn(sol)

to_user(internal_obj)

Convert internal objective to user-facing value.

Source code in solvor/utils/helpers.py
def to_user(self, internal_obj: float) -> float:
    """Convert internal objective to user-facing value."""
    return internal_obj * self.sign

assignment_cost(matrix, assignment)

Compute total cost of an assignment.

Source code in solvor/utils/helpers.py
def assignment_cost(matrix: list[list[float]], assignment: list[int]) -> float:
    """Compute total cost of an assignment."""
    total = 0.0
    for i, j in enumerate(assignment):
        if j != -1 and i < len(matrix) and 0 <= j < len(matrix[i]):
            total += matrix[i][j]
    return total

debug(*args, **kwargs)

Print only when DEBUG=1. Same signature as print().

Source code in solvor/utils/helpers.py
def debug(*args, **kwargs) -> None:
    """Print only when DEBUG=1. Same signature as print()."""
    if _DEBUG:
        print(*args, **kwargs)

default_progress(name='', *, interval=100, time_limit=None)

Create a default progress callback with formatted output.

Parameters:

Name Type Description Default
name str

Solver name prefix for output (optional)

''
interval int

Print every N iterations (default 100)

100
time_limit float | None

Stop after this many seconds (optional)

None
Example

result = solver(func, bounds, on_progress=default_progress("PSO"))

Output: PSO iter=100 obj=1.234 best=0.567 time=0.42s

Source code in solvor/utils/helpers.py
def default_progress(name: str = "", *, interval: int = 100, time_limit: float | None = None) -> ProgressCallback:
    """Create a default progress callback with formatted output.

    Args:
        name: Solver name prefix for output (optional)
        interval: Print every N iterations (default 100)
        time_limit: Stop after this many seconds (optional)

    Example:
        result = solver(func, bounds, on_progress=default_progress("PSO"))
        # Output: PSO iter=100 obj=1.234 best=0.567 time=0.42s
    """
    start = perf_counter()
    prefix = f"{name} " if name else ""

    def callback(progress: Progress) -> bool | None:
        elapsed = perf_counter() - start
        if progress.iteration % interval == 0:
            best = progress.best if progress.best is not None else progress.objective
            print(f"{prefix}iter={progress.iteration} obj={progress.objective:.6g} best={best:.6g} time={elapsed:.2f}s")
        if time_limit is not None and elapsed > time_limit:
            return True
        return None

    return callback

is_feasible(A, b, x, tol=1e-09)

Check if x satisfies A @ x <= b within tolerance.

Source code in solvor/utils/helpers.py
def is_feasible(
    A: list[list[float]],
    b: list[float],
    x: list[float],
    tol: float = 1e-9,
) -> bool:
    """Check if x satisfies A @ x <= b within tolerance."""
    for i, row in enumerate(A):
        lhs = sum(row[j] * x[j] for j in range(min(len(row), len(x))))
        if lhs > b[i] + tol:
            return False
    return True

pairwise_swap_neighbors(perm)

Generate all neighbors by swapping pairs of elements.

Source code in solvor/utils/helpers.py
def pairwise_swap_neighbors(perm: list[int]) -> Iterator[list[int]]:
    """Generate all neighbors by swapping pairs of elements."""
    n = len(perm)
    for i in range(n):
        for j in range(i + 1, n):
            neighbor = perm.copy()
            neighbor[i], neighbor[j] = neighbor[j], neighbor[i]
            yield neighbor

random_permutation(n, seed=None)

Generate a random permutation of [0, 1, ..., n-1].

Source code in solvor/utils/helpers.py
def random_permutation(n: int, seed: int | None = None) -> list[int]:
    """Generate a random permutation of [0, 1, ..., n-1]."""
    rng = Random(seed) if seed is not None else Random()
    perm = list(range(n))
    for i in range(n - 1, 0, -1):
        j = rng.randint(0, i)
        perm[i], perm[j] = perm[j], perm[i]
    return perm

reconstruct_path(parent, current)

Reconstruct path from parent dict, used by pathfinding algorithms.

Source code in solvor/utils/helpers.py
def reconstruct_path[S](parent: dict[S, S], current: S) -> list[S]:
    """Reconstruct path from parent dict, used by pathfinding algorithms."""
    path = [current]
    while current in parent:
        current = parent[current]
        path.append(current)
    path.reverse()
    return path

report_progress(on_progress, progress_interval, iteration, current_obj, best_obj, evals)

Report progress if interval reached. Returns True if callback requested stop.

Parameters:

Name Type Description Default
on_progress ProgressCallback | None

Progress callback or None

required
progress_interval int

Report every N iterations (0 = disabled)

required
iteration int

Current iteration number

required
current_obj float

Current objective value (user-facing)

required
best_obj float

Best objective found so far (user-facing)

required
evals int

Number of objective evaluations

required

Returns:

Type Description
bool

True if callback returned True (stop requested), False otherwise.

Example

if report_progress(on_progress, progress_interval, iteration, evaluator.to_user(obj), evaluator.to_user(best), evaluator.evals): return Result(solution, evaluator.to_user(best), iteration, evaluator.evals, Status.FEASIBLE)

Source code in solvor/utils/helpers.py
def report_progress(
    on_progress: ProgressCallback | None,
    progress_interval: int,
    iteration: int,
    current_obj: float,
    best_obj: float,
    evals: int,
) -> bool:
    """Report progress if interval reached. Returns True if callback requested stop.

    Args:
        on_progress: Progress callback or None
        progress_interval: Report every N iterations (0 = disabled)
        iteration: Current iteration number
        current_obj: Current objective value (user-facing)
        best_obj: Best objective found so far (user-facing)
        evals: Number of objective evaluations

    Returns:
        True if callback returned True (stop requested), False otherwise.

    Example:
        if report_progress(on_progress, progress_interval, iteration,
                          evaluator.to_user(obj), evaluator.to_user(best), evaluator.evals):
            return Result(solution, evaluator.to_user(best), iteration, evaluator.evals, Status.FEASIBLE)
    """
    if not (on_progress and progress_interval > 0 and iteration % progress_interval == 0):
        return False

    progress = Progress(
        iteration,
        current_obj,
        best_obj if best_obj != current_obj else None,
        evals,
    )
    return on_progress(progress) is True

timed_progress(callback)

Wrap a callback to receive elapsed time as second argument.

Use this to add time tracking without modifying solver code.

Example

def my_callback(progress, elapsed): print(f"iter {progress.iteration}, time {elapsed:.2f}s") return elapsed > 60 # Stop after 60 seconds

result = solver(func, bounds, on_progress=timed_progress(my_callback))

Source code in solvor/utils/helpers.py
def timed_progress(
    callback: Callable[[Progress, float], bool | None],
) -> ProgressCallback:
    """Wrap a callback to receive elapsed time as second argument.

    Use this to add time tracking without modifying solver code.

    Example:
        def my_callback(progress, elapsed):
            print(f"iter {progress.iteration}, time {elapsed:.2f}s")
            return elapsed > 60  # Stop after 60 seconds

        result = solver(func, bounds, on_progress=timed_progress(my_callback))
    """
    start = perf_counter()

    def wrapper(progress: Progress) -> bool | None:
        elapsed = perf_counter() - start
        return callback(progress, elapsed)

    return wrapper

Validation Reference

solvor.utils.validate

Input validation utilities for solvers.

Common validation functions to ensure inputs are well-formed before solving. Provides clear error messages for dimension mismatches, invalid values, and other common mistakes.

from solvor.utils import check_matrix_dims, check_bounds, check_positive

Used internally by solvers but also available for custom validation.

check_bounds(bounds, *, name='bounds')

Validate bounds are (low, high) pairs with low <= high. Returns dimension.

Source code in solvor/utils/validate.py
def check_bounds(
    bounds: Sequence[tuple[float, float]],
    *,
    name: str = "bounds",
) -> int:
    """Validate bounds are (low, high) pairs with low <= high. Returns dimension."""
    n = len(bounds)
    for i, (lo, hi) in enumerate(bounds):
        if lo > hi:
            raise ValueError(f"Invalid {name}[{i}]: lower bound {lo} > upper bound {hi}")
    return n

check_edge_nodes(edges, n_nodes, *, name='edges')

Check that edge endpoints are valid node indices.

Source code in solvor/utils/validate.py
def check_edge_nodes(
    edges: Sequence[tuple[int, int, float]],
    n_nodes: int,
    *,
    name: str = "edges",
) -> None:
    """Check that edge endpoints are valid node indices."""
    for i, (u, v, _) in enumerate(edges):
        if u < 0 or u >= n_nodes:
            raise ValueError(f"Invalid node in {name}[{i}]: u={u} (valid range: 0 to {n_nodes - 1})")
        if v < 0 or v >= n_nodes:
            raise ValueError(f"Invalid node in {name}[{i}]: v={v} (valid range: 0 to {n_nodes - 1})")

check_graph_nodes(graph, *nodes)

Check that nodes exist in graph.

Source code in solvor/utils/validate.py
def check_graph_nodes(
    graph: dict,
    *nodes: tuple[object, str],
) -> None:
    """Check that nodes exist in graph."""
    for node, name in nodes:
        if node not in graph:
            raise ValueError(f"{name} '{node}' not found in graph")

check_in_range(value, low, high, *, name='value', inclusive=True)

Check that value is within [low, high] or (low, high).

Source code in solvor/utils/validate.py
def check_in_range(
    value: float,
    low: float,
    high: float,
    *,
    name: str = "value",
    inclusive: bool = True,
) -> None:
    """Check that value is within [low, high] or (low, high)."""
    if inclusive:
        if not (low <= value <= high):
            raise ValueError(f"{name} must be in [{low}, {high}], got {value}")
    else:
        if not (low < value < high):
            raise ValueError(f"{name} must be in ({low}, {high}), got {value}")

check_integers_valid(integers, n_vars, *, name='integers')

Check that integer variable indices are valid and unique.

Source code in solvor/utils/validate.py
def check_integers_valid(
    integers: Sequence[int],
    n_vars: int,
    *,
    name: str = "integers",
) -> None:
    """Check that integer variable indices are valid and unique."""
    seen: set[int] = set()
    for idx in integers:
        if not isinstance(idx, int):
            raise TypeError(f"{name} must contain integers, got {type(idx).__name__}")
        if idx < 0 or idx >= n_vars:
            raise ValueError(f"Invalid index in {name}: {idx} (valid range: 0 to {n_vars - 1})")
        if idx in seen:
            raise ValueError(f"Duplicate index in {name}: {idx}")
        seen.add(idx)

check_matrix_dims(c, A, b, *, name_c='c', name_A='A', name_b='b')

Validate dimensions of LP/MILP inputs: c (n,), A (m, n), b (m,).

Source code in solvor/utils/validate.py
def check_matrix_dims(
    c: Sequence,
    A: Sequence[Sequence],
    b: Sequence,
    *,
    name_c: str = "c",
    name_A: str = "A",
    name_b: str = "b",
) -> None:
    """Validate dimensions of LP/MILP inputs: c (n,), A (m, n), b (m,)."""
    if not A:
        raise ValueError(f"Constraint matrix {name_A} cannot be empty")

    n = len(c)
    m = len(b)

    if len(A) != m:
        raise ValueError(f"Dimension mismatch: {name_b} has {m} constraints but {name_A} has {len(A)} rows")

    for i, row in enumerate(A):
        if len(row) != n:
            raise ValueError(
                f"Dimension mismatch: {name_c} has {n} variables but {name_A} row {i} has {len(row)} columns"
            )

check_non_negative(value, *, name='value')

Check that value is non-negative.

Source code in solvor/utils/validate.py
def check_non_negative(
    value: float,
    *,
    name: str = "value",
) -> None:
    """Check that value is non-negative."""
    if value < 0:
        raise ValueError(f"{name} cannot be negative, got {value}")

check_positive(value, *, name='value')

Check that value is strictly positive.

Source code in solvor/utils/validate.py
def check_positive(
    value: float,
    *,
    name: str = "value",
) -> None:
    """Check that value is strictly positive."""
    if value <= 0:
        raise ValueError(f"{name} must be positive, got {value}")

check_sequence_lengths(*seqs, expected=None)

Check that all sequences have the same length. Returns the length.

Source code in solvor/utils/validate.py
def check_sequence_lengths(
    *seqs: tuple[Sequence, str],
    expected: int | None = None,
) -> int:
    """Check that all sequences have the same length. Returns the length."""
    if not seqs:
        return 0

    if expected is None:
        expected = len(seqs[0][0])

    for seq, name in seqs:
        if len(seq) != expected:
            raise ValueError(f"Length mismatch: expected {expected} elements in {name}, got {len(seq)}")

    return expected

warn_large_coefficients(A, threshold=10000000000.0, *, name='A')

Warn if matrix has very large coefficients that may cause numerical issues.

Source code in solvor/utils/validate.py
def warn_large_coefficients(
    A: Sequence[Sequence[float]],
    threshold: float = 1e10,
    *,
    name: str = "A",
) -> None:
    """Warn if matrix has very large coefficients that may cause numerical issues."""
    max_val = 0.0
    for row in A:
        for val in row:
            abs_val = abs(val)
            if abs_val > max_val:
                max_val = abs_val

    if max_val > threshold:
        warn(
            f"Large coefficients in {name} (max={max_val:.2e}) may cause numerical issues. "
            "Consider scaling your problem.",
            stacklevel=3,
        )