linopy

repository·master·Indexed 42 days ago

https://github.com/pypsa/linopy

An optimization package that bridges data analysis tools like xarray and pandas with mathematical programming solvers. It enables the definition of linear, integer, mixed-integer, and quadratic programming problems using N-D labeled arrays with coordinates. Key features include the Model class for problem construction, support for continuous and binary variables, and the ability to retrieve solutions as pandas DataFrames.

Tokens
70.2K
Snippets
229
Records
308
Agent score
53%

What's inside linopy

  1. Overview of Linopy

    master

    Linopy is a Python library designed for linear programming (Linear, Integer, Mixed-Integer, and Quadratic Programming). It acts as a bridge between data analysis packages like xarray and pandas and various optimization solvers.

    Key capabilities include:

    • Defining continuous or binary variables with N-dimensional coordinates (e.g., time, geography, consumers).
    • Performing arithmetic operations on variables and linear expressions using xarray broadcasting.
    • Grouping terms of linear expressions by coordinates.
    • Using dask for lazy operations on large-scale linear programs.
    • Fast import/export of models using xarray's NetCDF IO.
    • Support for GPU-accelerated solving.
  2. Performance comparison of linopy

    master

    Linopy is designed for high performance and scalability with large optimization models. When compared to other optimization frameworks using the Gurobi solver, linopy demonstrates the following characteristics:

    • Vs. JuMP (Julia): Overall speed is comparable, but linopy can outperform JuMP in total memory efficiency for large models.
    • Vs. Pyomo (Python): For large problems, linopy typically provides a 4-6x speedup and approximately 50% memory reduction.
  3. Understand coordinate alignment in linopy

    master

    linopy follows an alignment model based on xarray labels rather than positions.

    • Labeled Operands: DataArrays, pandas Series, or DataFrames align by their coordinate labels.
    • Unlabeled Operands: Numpy arrays, lists, or Polars Series carry no labels. They pair with a linopy operand's dimensions based on size. A length-$N$ array will pair with a dimension of length $N$. If multiple dimensions have the same length, or no dimension matches, linopy raises an error to prevent ambiguity. To avoid this, wrap unlabeled arrays in a DataArray to provide explicit dimension names.
    • Scalars: A scalar or 0-d array broadcasts over all dimensions.
    • Shared Dimensions: If two operands share a dimension, their labels must be identical in both set and order. Any difference (missing labels or reordered labels) will raise a ValueError. linopy does not perform silent reindexing.
  4. Work with Variables in linopy

    master

    A linopy.variables.Variable is a subclass of xarray.DataArray that carries labels for a multi-dimensional decision variable.

    Attributes

    • lower, upper: Bounds on the variable.
    • scaling: Scaling factor.
    • type: The variable type (e.g., continuous, binary).
    • solution: The optimal value after solving.

    Modification

    Variable.update is the canonical mutation API. While legacy setters for lower and upper exist, they are deprecated and will be removed.

    • update: The preferred way to change variable attributes.
    • fix / unfix: Fix a variable to a specific value or allow it to vary.
    • relax / unrelax: Relax variable constraints.

    Operations and Conversion

    • sum, where: Array-like operations.
    • to_linexpr: Convert to a LinearExpression.
    • to_polars: Convert to a Polars DataFrame.
  5. Use Linear and Quadratic Expressions

    master

    Expressions are mathematical combinations of variables. Arithmetic operations on Variable or LinearExpression objects return new expression objects.

    LinearExpression

    A linear combination of variables.

    • Operations: sum, where, groupby, rolling.
    • Structure: Access name, vars (variables), coeffs (coefficients), const (constant term), nterm (number of terms), and has_terms.
    • Conversion: to_polars.
    • Construction: from_tuples, merge.
    • Post-solve: solution.

    QuadraticExpression

    A quadratic combination of variables, typically returned when squaring a Variable or LinearExpression.

    • Structure: Access name, vars, coeffs, const, nterm, and has_terms.
    • Conversion: to_matrix, to_polars.
    • Post-solve: solution.
  6. How piecewise formulation methods are selected

    master

    When method="auto" is used, linopy selects a formulation based on the following criteria:

    Propertylpincrementalsos2Disjunctive
    Curve layoutConnectedConnectedConnectedDisconnected
    Supported signone <= or >=all == or one <=/>=all == or one <=/>=all == or one <=/>=
    Number of tuplesExactly 2$\ge 2$ (3+ requires all ==)$\ge 2$ (3+ requires all ==)$\ge 2$ (3+ requires all ==)
    Breakpoint orderStrictly monotonicStrictly monotonicAnyAny (per segment)
    CurvatureConcave (<=) or convex (>=)NoneNoneNone
    Auxiliary varsNoneContinuous + binaryContinuous + SOS2Continuous + binary + SOS2
    Solver req.Any LP solverMIP-capableSOS2-capableSOS2 + MIP

    Note: Disjunctive formulations report method="sos2" via the returned object because they use SOS2 per segment, but they are treated separately due to their unique binary structure.

  7. Core building blocks of a linopy model

    master

    Building a model in linopy involves four primary conceptual steps:

    1. Declaring Variables: Using methods to create decision variables (continuous, integer, binary, or semi-continuous) with specific bounds and N-D coordinates.
    2. Creating Expressions: Combining variables into linear or quadratic expressions using arithmetic, broadcasting, sum, groupby, rolling, and where.
    3. Defining Constraints: Converting expressions into constraints using comparison operators (≤, ≥, ==). For memory-efficient large-scale problems, use CSRConstraint.
    4. Coordinate Alignment: Managing how operands with different coordinates are aligned, which can be controlled using the join method.
  8. Handle ragged breakpoints with NaN masking

    master

    Linopy supports 'ragged' breakpoint arrays where different entities have different numbers of breakpoints. This is achieved by padding the breakpoint arrays with trailing NaN values.

    Trailing NaN values mask the corresponding interpolation variables ($\lambda$ or $\delta$) or chord constraints.

    Warning: Interior NaN values (gaps in the middle of the array) are not supported and will raise an error.

    # gen1 has 3 breakpoints, gen2 has 2 (NaN-padded)
    bp = linopy.breakpoints({"gen1": [0, 50, 100], "gen2": [0, 80]}, dim="gen")
  9. How piecewise inequality geometry works

    master

    When using a single bounded tuple (one "==" and one "<=" or ">="), the formulation constrains the joint variables to a specific geometric region:

    • Hypograph ("<=" on a concave function): The joint $(x, y)$ satisfies $y \le f(x)$. This is used for quantities with a controllable dissipation path (e.g., thermal or electrical curtailment).
    • Epigraph (">=" on a convex function): The joint $(x, y)$ satisfies $y \ge f(x)$. This is used for inputs where over-supply is admissible but wasteful (e.g., fuel), allowing objective pressure to pull the point onto the curve.

    Note on LP formulation: Using the correct sign matching the curvature (e.g., ">=" for convex) allows linopy to use a pure LP chord formulation, which is much cheaper than SOS2 or incremental methods.

  10. How reductions handle absent slots

    master

    Reductions (operations that collapse a dimension) in linopy behave differently than arithmetic operations regarding NaN propagation. Instead of propagating NaNs, reductions skip absent slots.

    • sum and groupby.sum: These add only the present terms. If no terms are present, the result is a zero expression.
    • Objective Functions: The objective totals its terms using the same logic as sum (skipping absent slots).
    • Future Reductions: Operations like mean, resample, and coarsen (to be added under the v1 convention) will also follow this 'skip-absent' rule.
  11. Use NVIDIA cuOpt with linopy: Features and Limitations

    master

    cuOpt provides GPU-accelerated solving for large-scale Linear Programming (LP), Mixed-Integer Programming (MIP), and Convex Quadratic Programming (QP) using a GPU barrier method.

    Key Features:

    • Supports continuous, binary, integer, and semi-continuous variables.
    • Supports inequality and equality constraints.
    • Reports duals for LP models; MIP gap and dual bound are available via model.solver.report.

    Important Limitations:

    • API: Only the direct API is supported. Using io_api (e.g., lp, mps) will still work but will trigger informational logs or warnings as the model is built through the direct API regardless.
    • File I/O: keep_files=True is not supported and will raise NotImplementedError.
    • Model Types: Mixed-Integer Quadratic Programming (MIQP) is not supported and will raise NotImplementedError before solving.
    • Constraints: Quadratic constraints, SOS, and indicator constraints are not supported.
    • Warm Starts: No support for warm start or basis files.
    • Output: Reduced costs are not returned.
    • Tolerances: Default tolerances are 1e-4.

    Solver Behavior Notes:

    • Method Selection: linopy defaults to method=3 (Barrier). For very large sparse LPs, you may want to try method=1 (PDLP).
    • Quadratic Objectives: If the objective is quadratic, cuOpt silently overrides method and crossover to use the barrier method.
    • Termination: Limit terminations (e.g., time_limit) return status ok with the matching condition. If a limit expires before a feasible point is found, linopy returns an empty solution.
  12. How groupers work in groupby operations

    master

    A grouper (which can be a pd.Series, pd.DataArray, pd.DataFrame, or the name of an attached coordinate) labels each position of the dimension being grouped.

    Alignment Rules:

    • The grouper's index must carry the labels of the dimension being grouped.
    • Strict Validation: The grouper is never matched by position and is never silently reindexed. If the label set differs or if labels are in a different order, linopy will raise an error.

    Multi-key Grouping:

    • You can group by a list of coordinate names or a pd.DataFrame (a multi-key grouper).
    • The result is a flat group dimension where the keys are carried as auxiliary coordinates. Note that the stacked group MultiIndex is considered legacy behavior.