from __future__ import annotations

from enum import Enum
from typing import Any, Callable, Mapping, Sequence, TypeVar

BlockFnT = TypeVar("BlockFnT", bound=Callable[..., Any])

class ArcoError(Exception): ...
class ModelEmptyError(ArcoError): ...
class VariableInvalidIdError(ArcoError): ...
class VariableInvalidBoundsError(ArcoError): ...
class ConstraintInvalidIdError(ArcoError): ...
class ConstraintInvalidBoundsError(ArcoError): ...
class ObjectiveMissingError(ArcoError): ...
class ObjectiveAlreadySetError(ArcoError): ...
class SlackInvalidPenaltyError(ArcoError): ...
class SolverInfeasibleError(ArcoError): ...
class SolverUnboundedError(ArcoError): ...
class SolverTimeLimitError(ArcoError): ...
class SolverIterationLimitError(ArcoError): ...
class SolverInternalError(ArcoError): ...
class CscInvalidDataError(ArcoError): ...
class ExprDivisionByZeroError(ArcoError): ...
class ExprNotSingleVariableError(ArcoError): ...
class ExprCoefficientError(ArcoError): ...
class ExprConstantOffsetError(ArcoError): ...
class ExprTypeError(ArcoError): ...
class ArrayShapeMismatchError(ArcoError): ...
class ArrayIndexError(ArcoError): ...
class ArrayTypeError(ArcoError): ...
class ArrayDimensionError(ArcoError): ...
class ArrayOverflowError(ArcoError): ...
class ConstraintTypeError(ArcoError): ...
class ConstraintBoundsMissingError(ArcoError): ...
class ConstraintSenseError(ArcoError): ...
class SolverInvalidSettingError(ArcoError): ...
class SolverIndexError(ArcoError): ...
class SolverTypeError(ArcoError): ...
class IndexSetEmptyError(ArcoError): ...
class IndexSetTypeError(ArcoError): ...
class IndexSetArgumentError(ArcoError): ...
class BoundsInvalidError(ArcoError): ...
class SlackBoundError(ArcoError): ...
class CscDtypeError(ArcoError): ...
class CscDimensionError(ArcoError): ...
class CscContiguityError(ArcoError): ...
class CscNegativeIndexError(ArcoError): ...
class ModelBinaryBoundsError(ArcoError): ...
class ObjectiveIndexError(ArcoError): ...

class Sense(Enum):
    MINIMIZE: Sense
    MAXIMIZE: Sense

class SimplifyLevel(Enum):
    NONE: SimplifyLevel
    BASIC: SimplifyLevel
    AGGRESSIVE: SimplifyLevel

class SolutionStatus(Enum):
    OPTIMAL: SolutionStatus
    INFEASIBLE: SolutionStatus
    UNBOUNDED: SolutionStatus
    TIME_LIMIT: SolutionStatus
    ERROR: SolutionStatus

class BoundType(Enum):
    PositiveFloat: BoundType
    NegativeFloat: BoundType
    NonNegativeFloat: BoundType
    NonPositiveFloat: BoundType
    PositiveInt: BoundType
    NegativeInt: BoundType
    NonNegativeInt: BoundType
    NonPositiveInt: BoundType
    Binary: BoundType

PositiveFloat: BoundType
NegativeFloat: BoundType
NonNegativeFloat: BoundType
NonPositiveFloat: BoundType
PositiveInt: BoundType
NegativeInt: BoundType
NonNegativeInt: BoundType
NonPositiveInt: BoundType
Binary: BoundType

class Bounds:
    def __init__(self, lo: Any | None = None, hi: Any | None = None, *, lower: Any | None = None, upper: Any | None = None) -> None: ...
    @property
    def lower(self) -> Any: ...
    @property
    def upper(self) -> Any: ...

class Solver:
    def __init__(self, *, presolve: bool | None = None, threads: int | None = None, tolerance: float | None = None, time_limit: float | None = None, mip_gap: float | None = None, verbosity: int | None = None, log_to_console: bool | None = None) -> None: ...
    @property
    def presolve(self) -> bool | None: ...
    @property
    def threads(self) -> int | None: ...
    @property
    def tolerance(self) -> float | None: ...
    @property
    def time_limit(self) -> float | None: ...
    @property
    def mip_gap(self) -> float | None: ...
    @property
    def verbosity(self) -> int | None: ...
    @property
    def log_to_console(self) -> bool | None: ...
    def copy(self, *, update: Mapping[str, Any] | None = None) -> Solver: ...

class HiGHS(Solver): ...
class Xpress(Solver): ...

class IndexSet:
    def __init__(self, name: str, *, size: int | None = None, members: Sequence[Any] | None = None) -> None: ...
    @property
    def name(self) -> str: ...
    @property
    def size(self) -> int: ...
    @property
    def members(self) -> list[Any]: ...

class Expr:
    def __init__(self) -> None: ...
    def scale(self, *, by: float) -> Expr: ...
    def add(self, *, other: Expr) -> Expr: ...

class ConstraintExpr:
    @property
    def expr(self) -> Expr: ...
    @property
    def sense(self) -> str: ...
    @property
    def rhs(self) -> float: ...

class Variable:
    @property
    def name(self) -> str | None: ...
    @property
    def bounds(self) -> Bounds: ...
    @property
    def is_integer(self) -> bool: ...
    @property
    def is_binary(self) -> bool: ...

class Constraint:
    @property
    def name(self) -> str | None: ...
    @property
    def bounds(self) -> Bounds: ...

class VariableArray:
    @property
    def variables(self) -> list[Variable]: ...
    @property
    def shape(self) -> tuple[int, ...]: ...
    @property
    def index_sets(self) -> tuple[IndexSet, ...]: ...
    @property
    def values(self) -> list[Expr]: ...
    def flatten(self) -> list[Expr]: ...
    def sum(self, *, over: IndexSet | Sequence[IndexSet] | None = None) -> Expr | ExprArray: ...

class ExprArray:
    @property
    def shape(self) -> tuple[int, ...]: ...
    @property
    def index_sets(self) -> tuple[IndexSet, ...]: ...
    @property
    def values(self) -> list[Expr]: ...
    def flatten(self) -> list[Expr]: ...
    def sum(self, *, over: IndexSet | Sequence[IndexSet] | None = None) -> Expr | ExprArray: ...

class ConstraintArray:
    @property
    def sense(self) -> str: ...
    @property
    def rhs(self) -> list[float]: ...
    @property
    def shape(self) -> tuple[int, ...]: ...
    @property
    def index_sets(self) -> tuple[IndexSet, ...]: ...

class ConstraintIterator: ...
class VariableIterator: ...

class SlackHandle:
    @property
    def constraint_id(self) -> int: ...
    @property
    def bound(self) -> str: ...
    @property
    def penalty(self) -> float: ...
    @property
    def name(self) -> str | None: ...
    @property
    def var_ids(self) -> dict[str, int | None]: ...

class ElasticHandle:
    @property
    def lower(self) -> SlackHandle | None: ...
    @property
    def upper(self) -> SlackHandle | None: ...

class SlackVariable:
    @property
    def constraint(self) -> Constraint: ...
    @property
    def bound(self) -> str: ...
    @property
    def penalty(self) -> float: ...
    @property
    def name(self) -> str | None: ...
    @property
    def value(self) -> float: ...

class BlockPort:
    @property
    def block_name(self) -> str: ...
    @property
    def key(self) -> str: ...
    @property
    def kind(self) -> str: ...

class BlockPorts:
    def __getattr__(self, key: str) -> BlockPort: ...
    def keys(self) -> list[str]: ...

class BlockHandle:
    @property
    def name(self) -> str: ...
    @property
    def in_(self) -> BlockPorts: ...
    @property
    def out(self) -> BlockPorts: ...
    def input(self, key: str) -> BlockPort: ...
    def output(self, key: str) -> BlockPort: ...

class BlockResults:
    def __getitem__(self, key: str) -> SolveResult: ...
    def keys(self) -> list[str]: ...
    def values(self) -> list[SolveResult]: ...
    def items(self) -> list[tuple[str, SolveResult]]: ...

class SolveResult:
    @property
    def status(self) -> SolutionStatus: ...
    @property
    def objective_value(self) -> float: ...
    @property
    def primal_values(self) -> list[float]: ...
    @property
    def variable_duals(self) -> list[float]: ...
    @property
    def constraint_duals(self) -> list[float]: ...
    @property
    def blocks(self) -> Any | None: ...
    def get_value(self, variable: Variable | VariableArray) -> float | Any: ...
    def get_dual(self, constraint: Constraint) -> float: ...
    def get_reduced_cost(self, variable: Variable) -> float: ...
    def get_slack(self, constraint: Constraint) -> float: ...
    def get_primal(self, *, index: int) -> float: ...
    def get_variable_dual(self, *, index: int) -> float: ...
    def get_constraint_dual(self, *, index: int) -> float: ...
    def is_optimal(self) -> bool: ...
    def is_feasible(self) -> bool: ...
    def is_infeasible(self) -> bool: ...
    def is_unbounded(self) -> bool: ...
    def status_string(self) -> str: ...
    def solve_time_seconds(self) -> float: ...

class VariableView:
    @property
    def id(self) -> int: ...
    @property
    def name(self) -> str | None: ...
    @property
    def bounds(self) -> Bounds: ...
    @property
    def is_integer(self) -> bool: ...
    @property
    def is_active(self) -> bool: ...
    @property
    def metadata(self) -> Any | None: ...

class ConstraintView:
    @property
    def id(self) -> int: ...
    @property
    def name(self) -> str | None: ...
    @property
    def bounds(self) -> Bounds: ...
    @property
    def nnz(self) -> int: ...
    @property
    def metadata(self) -> Any | None: ...

class CoefficientView:
    @property
    def variable_id(self) -> int: ...
    @property
    def constraint_id(self) -> int: ...
    @property
    def value(self) -> float: ...

class ObjectiveView:
    @property
    def sense(self) -> str | None: ...
    @property
    def terms(self) -> list[tuple[int, float]]: ...
    @property
    def name(self) -> str | None: ...

class SlackView:
    @property
    def constraint_id(self) -> int: ...
    @property
    def bound(self) -> str: ...
    @property
    def penalty(self) -> float: ...
    @property
    def lower_variable(self) -> int | None: ...
    @property
    def upper_variable(self) -> int | None: ...
    @property
    def name(self) -> str | None: ...

class SnapshotMetadata:
    @property
    def variables(self) -> int: ...
    @property
    def constraints(self) -> int: ...
    @property
    def coefficients(self) -> int: ...

class ModelSnapshot:
    @property
    def variables(self) -> list[VariableView]: ...
    @property
    def constraints(self) -> list[ConstraintView]: ...
    @property
    def coefficients(self) -> list[CoefficientView] | None: ...
    @property
    def objective(self) -> ObjectiveView | None: ...
    @property
    def slacks(self) -> list[SlackView] | None: ...
    @property
    def metadata(self) -> SnapshotMetadata: ...

class Model:
    def __init__(self, *, simplify_level: SimplifyLevel | None = None, solver: Solver | None = None) -> None: ...
    @classmethod
    def from_csc(
        cls,
        *,
        num_constraints: int,
        num_variables: int,
        col_ptrs: Any,
        row_indices: Any,
        values: Any,
        var_lower: Any,
        var_upper: Any,
        con_lower: Any,
        con_upper: Any,
        is_integer: Any,
        simplify_level: SimplifyLevel | None = None,
    ) -> Model: ...
    def add_variable(self, bounds: Bounds | BoundType, *, is_integer: bool = False, is_binary: bool = False, name: str | None = None) -> Variable: ...
    def add_variables(self, index_sets: Sequence[IndexSet], bounds: Any, *, is_integer: bool = False, is_binary: bool = False, name: str | None = None) -> VariableArray: ...
    def add_constraint(self, expr: Any, *, bounds: Bounds | None = None, name: str | None = None) -> Constraint: ...
    def add_constraints(self, expr: ConstraintArray | VariableArray | ExprArray, *, sense: str = "ge", rhs: Any = None, name: str | None = None) -> list[Constraint]: ...
    def add_slack(self, constraint: Constraint | int, *, bound: str, penalty: float, name: str | None = None) -> SlackVariable: ...
    def add_slacks(self, constraints: Sequence[Constraint | int], *, bound: str, penalty: float | Sequence[float], name: str | None = None) -> list[SlackVariable]: ...
    def make_elastic(self, constraint: Constraint | int, *, upper_penalty: float | None = None, lower_penalty: float | None = None, name: str | None = None) -> ElasticHandle: ...
    def set_coefficient(self, *, var_idx: int, constraint_idx: int, coeff: float) -> None: ...
    def set_objective(self, sense: Sense, terms: Sequence[tuple[int, float]], *, name: str | None = None) -> None: ...
    def minimize(self, expr: Any, *, name: str | None = None) -> None: ...
    def maximize(self, expr: Any, *, name: str | None = None) -> None: ...
    def solve(
        self,
        *,
        solver: Solver | None = None,
        log_to_console: bool | None = None,
        primal_start: Sequence[tuple[int, float]] | None = None,
        time_limit: float | None = None,
        mip_gap: float | None = None,
        verbosity: int | None = None,
    ) -> SolveResult: ...
    def inspect(
        self,
        *,
        include_coeffs: bool = False,
        include_slacks: bool = True,
        variable_ids: Sequence[int] | None = None,
        constraint_ids: Sequence[int] | None = None,
    ) -> ModelSnapshot: ...
    def pprint(self) -> None: ...
    def add_block(self, block_fn: Any, *, name: str | None = None, data: Any | None = None, extract: Any) -> BlockHandle: ...
    def link(self, source: BlockPort, target: BlockPort) -> None: ...
    def list_constraints(self) -> ConstraintIterator: ...
    def list_variables(self) -> VariableIterator: ...
    def get_constraint(self, *, name: str) -> Constraint: ...
    def get_variable(self, *, name: str) -> Variable: ...
    def get_columns(self) -> dict[int, list[tuple[int, float]]]: ...
    def export_csc(self) -> Mapping[str, Any]: ...
    def export_crs(self) -> Mapping[str, Any]: ...
    def export_arrow(self) -> Any: ...
    @property
    def num_variables(self) -> int: ...
    @property
    def num_constraints(self) -> int: ...
    @property
    def nnz(self) -> int: ...
    @property
    def variables(self) -> list[Variable]: ...
    @property
    def constraints(self) -> list[Constraint]: ...
    @property
    def has_blocks(self) -> bool: ...

def solution_summary(result: SolveResult, *, verbose: bool = False) -> None: ...
def enable_logging(*, level: str | None = None) -> bool: ...
def solver_info() -> Mapping[str, Any]: ...
def block(func: BlockFnT | None = None, *, name: str | None = None) -> BlockFnT | Callable[[BlockFnT], BlockFnT]: ...
