Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f8446d9
docs: silence HiGHS console output in tutorial notebooks
FBumann May 11, 2026
6d61112
docs: silence HiGHS console output in piecewise tutorials too
FBumann May 11, 2026
8d09ba9
Merge remote-tracking branch 'origin/master' into docs/silence-solver…
FBumann May 13, 2026
ae018a3
docs: fix broken toctree, refresh API reference, and clean up references
FBumann May 13, 2026
fe05bb1
docs: reorganize toctree into basic→advanced sections and rewrite use…
FBumann May 13, 2026
ce7c7b1
docs: fix broken admonitions in notebooks and configure intersphinx
FBumann May 13, 2026
e44cbd3
docs: downgrade coordinate-determination admonition from important to…
FBumann May 13, 2026
c5f9d4d
Revert "docs: downgrade coordinate-determination admonition from impo…
FBumann May 13, 2026
95b7e55
ci: empty commit to retrigger CI
FBumann May 13, 2026
94336ac
docs: rename toctree captions and reorder Examples below Solving
FBumann May 13, 2026
15aa6a4
docs: move Examples directly under User Guide
FBumann May 13, 2026
47db4be
docs: bridge Getting Started → User Guide and rename landing page H1
FBumann May 13, 2026
110ad81
docs: fix malformed first cell of solve-on-remote notebook
FBumann May 13, 2026
55867ac
docs: use markdown links for cross-refs in notebook markdown cells
FBumann May 13, 2026
2caac01
docs: collapse "Where to next" to a single pointer at the User Guide …
FBumann May 13, 2026
6cfa229
docs: restructure api.rst — task-oriented top, classes under the hood…
FBumann May 13, 2026
8e3885b
docs: add docstrings for properties surfaced in api.rst autosummary t…
FBumann May 13, 2026
a7efef2
docs: surface PWL_METHOD / PWL_CONVEXITY type aliases in api.rst
FBumann May 13, 2026
d4b20d3
docs: dissolve the api.rst Advanced umbrella; each item gets a natura…
FBumann May 13, 2026
1e33edd
docs: keep page TOC depth 2; expand right-side TOC to L2 site-wide
FBumann May 13, 2026
8954437
docs: rename "Classes and types" → "Other classes and types"
FBumann May 13, 2026
4c64672
docs: standardise H3 subgroup vocabulary across api.rst class sections
FBumann May 13, 2026
db02982
docs: revert show_toc_level=2 in book-theme options
FBumann May 13, 2026
91777fb
docs: restructure api.rst as Model-first and tighten the curated surface
FBumann May 13, 2026
955ef0b
docs: move piecewise construction helpers into the Piecewise section
FBumann May 13, 2026
2455b6c
docs: harmonise Variables container labels with Variable; fix preambl…
FBumann May 13, 2026
d949ec2
fix: api reference link
FBumann May 18, 2026
dda45c3
Merge branch 'master' into docs/reorganize-toctree
FBumann May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
618 changes: 470 additions & 148 deletions doc/api.rst

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions doc/benchmark.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.. _benchmark:

Benchmarks
==========
Performance comparison
======================


Linopy's performance scales well with the problem size. Its overall speed is comparable with the famous `JuMP <https://jump.dev/>`_ package written in `Julia <https://julialang.org/>`_. It even outperforms `JuMP` in total memory efficiency when it comes to large models. Compared to `Pyomo <https://pyomo.org>`_, the common optimization package in python, one can expect
Expand Down
10 changes: 10 additions & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@
autosummary_generate = True
autodoc_typehints = "none"

# Intersphinx — resolve :class:`xarray.DataArray`, :func:`numpy.ndarray`, etc.
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"numpy": ("https://numpy.org/doc/stable", None),
"pandas": ("https://pandas.pydata.org/docs", None),
"xarray": ("https://docs.xarray.dev/en/stable", None),
"scipy": ("https://docs.scipy.org/doc/scipy", None),
"dask": ("https://docs.dask.org/en/stable", None),
}

# Napoleon configurations

napoleon_google_docstring = False
Expand Down
37 changes: 30 additions & 7 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,31 +112,54 @@ This package is published under MIT license.
creating-expressions
creating-constraints
coordinate-alignment
manipulating-models

.. toctree::
:hidden:
:maxdepth: 2
:caption: Examples

transport-tutorial
migrating-from-pyomo

.. toctree::
:hidden:
:maxdepth: 2
:caption: Advanced Features

sos-constraints
piecewise-linear-constraints
manipulating-models
testing-framework
transport-tutorial
infeasible-model

.. toctree::
:hidden:
:maxdepth: 2
:caption: Solving

solve-on-remote
solve-on-oetc
gpu-acceleration
migrating-from-pyomo
gurobi-double-logging

.. toctree::
:hidden:
:maxdepth: 2
:caption: Troubleshooting

infeasible-model
gurobi-double-logging

.. toctree::
:hidden:
:maxdepth: 2
:caption: Benchmarking
:caption: Comparisons

benchmark
syntax

.. toctree::
:hidden:
:maxdepth: 2
:caption: References
:caption: Reference

api
release_notes
Expand Down
56 changes: 52 additions & 4 deletions doc/user-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,58 @@
Overview
========

Welcome to the User Guide for Linopy. This guide is designed to help you understand and effectively use Linopy's features to solve your optimization problems, complementing the ``Getting Started`` section.
In :doc:`Getting Started <prerequisites>` you installed linopy, built
a first scalar model, and saw N-D variables on coordinates. The User
Guide reopens each of those pieces in depth and adds the rest of the
modelling surface.

In the following sections, we will take a closer look at how to create and manipulate models, variables, and constraints, and how to solve these models to find optimal solutions. Each section includes detailed explanations and code examples to help you understand the concepts and apply them to your own projects.
Each page is a runnable Jupyter notebook — read it top to bottom, or
use it as a reference once you know what you're looking for.

If you are completely new to Linopy, consider to first have a look at the `Getting Started` section.

Let's get started!
Core building blocks
--------------------

The four notebooks below cover the model object you'll interact with
most. Read them in order the first time; come back to them whenever
you're unsure what a particular operator or argument does.

- :doc:`creating-variables` — declaring decision variables, with bounds
and coordinates. Continuous, integer, binary, and semi-continuous.
- :doc:`creating-expressions` — combining variables into linear (and
quadratic) expressions; arithmetic, broadcasting, ``sum``,
``groupby``, ``rolling``, ``where``.
- :doc:`creating-constraints` — turning expressions into ``≤`` / ``≥``
/ ``==`` constraints, and the ``CSRConstraint`` memory-efficient
alternative.
- :doc:`coordinate-alignment` — how linopy lines up operands that live
on different coordinates, and how to control it with ``join``.

After these four you can build any LP/MIP/QP linopy supports.


Working with an existing model
------------------------------

Once you've built a model, you'll often want to inspect it, change a
bound, swap a constraint, or copy it for what-if analysis.

- :doc:`manipulating-models` — modifying or removing variables and
constraints in place; ``Model.copy()``; ``fix`` / ``relax`` for
variables.


Where to go next
----------------

- **Examples** — end-to-end problem walkthroughs:
:doc:`transport-tutorial`, :doc:`migrating-from-pyomo`.
- **Advanced features** — :doc:`sos-constraints`,
:doc:`piecewise-linear-constraints`, and the
:doc:`testing-framework` for asserting structural properties of a
model.
- **Solving** — :doc:`solve-on-remote` (SSH),
:doc:`solve-on-oetc` (OET Cloud), :doc:`gpu-acceleration` (cuPDLPx).
- **Troubleshooting** — :doc:`infeasible-model` (diagnosing infeasible
problems), :doc:`gurobi-double-logging` (and other solver quirks).
- **Reference** — the full :doc:`api` listing.
10 changes: 10 additions & 0 deletions examples/create-a-model-with-coordinates.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@
"source": [
"Alright! Now you learned how to set up linopy variables and expressions with coordinates. In the User Guide, which follows, we are going to see, how the representation of variables with coordinates allows us to formulate more advanced operations."
]
},
{
"cell_type": "markdown",
"id": "4db583af",
"metadata": {},
"source": [
"## Where to next\n",
"\n",
"You've now seen the full path from declaring variables on coordinates to solving the model. The [User Guide overview](user-guide.rst) reopens each piece in depth and points you at every topic from here."
]
}
],
"metadata": {
Expand Down
10 changes: 8 additions & 2 deletions examples/creating-expressions.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@
"cell_type": "markdown",
"id": "f7578221",
"metadata": {},
"source": ".. important::\n\n\tWhen combining variables or expression with dimensions of the same name and size, the first object will determine the coordinates of the resulting expression. For example:"
"source": [
".. important::\n",
" When combining variables or expressions with dimensions of the same name and size, the first object determines the coordinates of the resulting expression. For example:"
]
},
{
"cell_type": "code",
Expand Down Expand Up @@ -196,7 +199,10 @@
{
"cell_type": "markdown",
"id": "a8xsfdqrcrn",
"source": ".. tip::\n\n\tFor explicit control over how coordinates are aligned during arithmetic, use the `.add()`, `.sub()`, `.mul()`, and `.div()` methods with a ``join`` parameter (``\"inner\"``, ``\"outer\"``, ``\"left\"``, ``\"right\"``). See the :doc:`coordinate-alignment` guide for details.",
"source": [
".. tip::\n",
" For explicit control over how coordinates are aligned during arithmetic, use the ``.add()``, ``.sub()``, ``.mul()``, and ``.div()`` methods with a ``join`` parameter (``\"inner\"``, ``\"outer\"``, ``\"left\"``, ``\"right\"``). See the :doc:`coordinate-alignment` guide for details."
],
"metadata": {}
},
{
Expand Down
13 changes: 11 additions & 2 deletions examples/creating-variables.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
"m = Model()"
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "",
"id": "46c4f2824a2ed8aa"
},
{
"cell_type": "markdown",
"id": "6c6420a7",
Expand Down Expand Up @@ -465,9 +471,12 @@
},
{
"cell_type": "markdown",
"id": "77e264e2",
"id": "e8249281",
"metadata": {},
"source": ".. important::\n\n **New in version 0.3.6**\n\n As pandas objects always have indexes, the `coords` argument is not required and is ignored is passed. Before, it was used to overwrite the indexes of the pandas objects. A warning is raised if `coords` is passed and if these are not aligned with the pandas object."
"source": [
".. note::\n",
" As pandas objects already carry indexes, the ``coords`` argument is ignored when supplied alongside them. A warning is raised if a ``coords`` value is passed that does not align with the pandas object."
]
},
{
"cell_type": "code",
Expand Down
35 changes: 30 additions & 5 deletions examples/solve-on-remote.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,38 @@
"id": "4db583af",
"metadata": {},
"source": [
"# Remote Solving with SSH",
"# Remote Solving with SSH\n",
"\n",
"This example demonstrates how linopy can solve optimization models on remote machines using SSH connections. This is one of two remote solving options available in linopy",
"This example demonstrates how linopy can solve optimization models on remote machines using SSH connections. This is one of two remote solving options available in linopy:\n",
"\n",
"1. **SSH Remote Solving** (this example) - Connect to your own servers via SSH\\n2. **OETC Cloud Solving** - Use cloud-based optimization services (see `solve-on-oetc.ipynb`)",
"\n\n",
"## SSH Remote Solving\\n\\nSSH remote solving is ideal when you have:\\n* Access to dedicated servers with optimization solvers installed\\n* Full control over the computing environment\\n* Existing infrastructure for optimization workloads\\n\\n## What you need for SSH remote solving:\\n* A running installation of paramiko on your local machine (`pip install paramiko`)\\n* A remote server with a working installation of linopy (e.g., in a conda environment)\\n* SSH access to that machine\\n\\n## How SSH Remote Solving Works\\n\\nThe workflow consists of the following steps, most of which linopy handles automatically:\\n\\n1. Define a model on the local machine\\n2. Save the model on the remote machine via SSH\\n3. Load, solve and write out the model on the remote machine\\n4. Copy the solved model back to the local machine\\n5. Load the solved model on the local machine\\n\\nThe model initialization happens locally, while the actual solving happens remotely.\""
"1. **SSH Remote Solving** (this example) - Connect to your own servers via SSH\n",
"2. **OETC Cloud Solving** - Use cloud-based optimization services (see [OETC notebook](solve-on-oetc.ipynb))\n",
"\n",
"## SSH Remote Solving\n",
"\n",
"SSH remote solving is ideal when you have:\n",
"\n",
"* Access to dedicated servers with optimization solvers installed\n",
"* Full control over the computing environment\n",
"* Existing infrastructure for optimization workloads\n",
"\n",
"## What you need for SSH remote solving\n",
"\n",
"* A running installation of paramiko on your local machine (`pip install paramiko`)\n",
"* A remote server with a working installation of linopy (e.g., in a conda environment)\n",
"* SSH access to that machine\n",
"\n",
"## How SSH Remote Solving Works\n",
"\n",
"The workflow consists of the following steps, most of which linopy handles automatically:\n",
"\n",
"1. Define a model on the local machine\n",
"2. Save the model on the remote machine via SSH\n",
"3. Load, solve and write out the model on the remote machine\n",
"4. Copy the solved model back to the local machine\n",
"5. Load the solved model on the local machine\n",
"\n",
"The model initialization happens locally, while the actual solving happens remotely.\n"
]
},
{
Expand Down
2 changes: 2 additions & 0 deletions linopy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@


class OptionSettings:
"""Runtime configuration knobs (e.g. display widths). Use as a context manager or set values directly via ``options(key=value)``."""

def __init__(self, **kwargs: Any) -> None:
self._defaults = kwargs
self._current_values = kwargs.copy()
Expand Down
7 changes: 7 additions & 0 deletions linopy/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,16 @@ class PerformanceWarning(UserWarning):
PWL_DOMAIN_HI_SUFFIX = "_domain_hi"

PWL_METHOD: TypeAlias = Literal["sos2", "lp", "incremental", "auto"]
"""Allowed values for the ``method`` argument of :meth:`Model.add_piecewise_formulation`."""

PWL_METHODS: frozenset[str] = frozenset(get_args(PWL_METHOD))
"""Set of valid :data:`~linopy.constants.PWL_METHOD` values."""

PWL_CONVEXITY: TypeAlias = Literal["convex", "concave", "linear", "mixed"]
"""Possible values for :attr:`~linopy.piecewise.PiecewiseFormulation.convexity`."""

PWL_CONVEXITIES: frozenset[str] = frozenset(get_args(PWL_CONVEXITY))
"""Set of valid :data:`~linopy.constants.PWL_CONVEXITY` values."""
BREAKPOINT_DIM = "_breakpoint"
SEGMENT_DIM = "_segment"
LP_PIECE_DIM = f"{BREAKPOINT_DIM}_piece"
Expand Down
3 changes: 3 additions & 0 deletions linopy/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,7 @@ def coord_names(self) -> list[str]:

@property
def vars(self) -> DataArray:
"""Variable labels referenced by each term of the expression."""
return self.data.vars

@vars.setter
Expand All @@ -931,6 +932,7 @@ def vars(self, value: DataArray) -> None:

@property
def coeffs(self) -> DataArray:
"""Coefficient applied to each term of the expression."""
return self.data.coeffs

@coeffs.setter
Expand All @@ -939,6 +941,7 @@ def coeffs(self, value: DataArray) -> None:

@property
def const(self) -> DataArray:
"""Constant offset added to the expression."""
return self.data.const

@const.setter
Expand Down
3 changes: 3 additions & 0 deletions linopy/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1260,14 +1260,17 @@ def semi_continuous(self) -> Variables:

@property
def is_linear(self) -> bool:
"""Whether the objective is linear."""
return self.objective.is_linear

@property
def is_quadratic(self) -> bool:
"""Whether the objective is quadratic."""
return self.objective.is_quadratic

@property
def type(self) -> str:
"""Short string identifying the problem type."""
if (
len(self.binaries) or len(self.integers) or len(self.semi_continuous)
) and len(self.continuous):
Expand Down
2 changes: 2 additions & 0 deletions linopy/objective.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,12 @@ def set_value(self, value: float) -> None:

@property
def is_linear(self) -> bool:
"""Whether the objective expression is linear."""
return type(self.expression) is expressions.LinearExpression

@property
def is_quadratic(self) -> bool:
"""Whether the objective expression is quadratic."""
return type(self.expression) is expressions.QuadraticExpression

def to_matrix(self, *args: Any, **kwargs: Any) -> csc_matrix:
Expand Down
11 changes: 6 additions & 5 deletions linopy/piecewise.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,22 +346,23 @@ class PiecewiseFormulation:
name : str
Formulation name (used as prefix for auxiliary variables and
constraints).
method : str
Resolved method — one of ``{"sos2", "incremental", "lp"}``. Never
``"auto"``; if the caller passed ``method="auto"``, this holds the
method actually chosen.
convexity : {"convex", "concave", "linear", "mixed"} or None
method : PWL_METHOD
Resolved method actually used. Never ``"auto"``; if the caller
passed ``method="auto"``, this holds the method that was chosen.
convexity : PWL_CONVEXITY or None
Shape of the piecewise curve along the breakpoint axis when it is
well-defined (exactly two expressions, non-disjunctive, strictly
monotonic ``x`` breakpoints). ``None`` otherwise.
"""

name: str
method: PWL_METHOD
"""Resolved formulation method (see :data:`~linopy.constants.PWL_METHOD`)."""
variable_names: list[str]
constraint_names: list[str]
model: Model
convexity: PWL_CONVEXITY | None = None
"""Shape of the piecewise curve when well-defined (see :data:`~linopy.constants.PWL_CONVEXITY`), else ``None``."""

@property
def variables(self) -> Variables:
Expand Down
Loading