diff --git a/doc/api.rst b/doc/api.rst index f817d866..d32c7089 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -4,187 +4,561 @@ API reference ############# -This page provides an auto-generated summary of linopy's API. +Reference for linopy's public API. Most workflows start at +:class:`~linopy.model.Model` — :class:`~linopy.variables.Variable`, +:class:`~linopy.constraints.Constraint`, and +:class:`~linopy.objective.Objective` are all built through +:meth:`Model.add_variables `, +:meth:`Model.add_constraints `, +:meth:`Model.add_objective `, +and accessed through the matching +:attr:`Model.variables `, +:attr:`Model.constraints `, and +:attr:`Model.objective ` accessors. +The supporting classes below cover those types in detail. + +.. contents:: + :local: + :depth: 2 + + +Model +===== + +Central container for an optimization problem. Most of linopy's +surface lives here. +.. autosummary:: + :toctree: generated/ + model.Model -Creating a model -================ +Building a model +---------------- + +.. autosummary:: + :toctree: generated/ + + model.Model.add_variables + model.Model.add_constraints + model.Model.add_objective + model.Model.add_sos_constraints + model.Model.add_piecewise_formulation + +Inspecting a model +------------------ + +.. autosummary:: + :toctree: generated/ + + model.Model.variables + model.Model.constraints + model.Model.objective + model.Model.sense + model.Model.type + model.Model.is_linear + model.Model.is_quadratic + +Modifying a model +----------------- + +.. autosummary:: + :toctree: generated/ + + model.Model.remove_variables + model.Model.remove_constraints + model.Model.remove_objective + model.Model.remove_sos_constraints + model.Model.copy + model.Model.reformulate_sos_constraints + +Solving +------- + +.. autosummary:: + :toctree: generated/ + + model.Model.solve + +Post-solve access +----------------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ - model.Model - model.Model.add_variables - model.Model.add_constraints - model.Model.add_objective - model.Model.add_piecewise_formulation - piecewise.PiecewiseFormulation - piecewise.Slopes - piecewise.breakpoints - piecewise.segments - piecewise.tangent_lines - model.Model.linexpr - model.Model.remove_constraints - model.Model.copy + model.Model.solution + model.Model.dual + model.Model.status + model.Model.termination_condition +Diagnostics +----------- + +.. autosummary:: + :toctree: generated/ + + model.Model.compute_infeasibilities + model.Model.format_infeasibilities + +IO +-- + +.. autosummary:: + :toctree: generated/ + + model.Model.to_file + model.Model.to_netcdf + io.read_netcdf -Classes under the hook -====================== Variable --------- +======== + +Subclass of ``xarray.DataArray`` carrying labels for a multi-dimensional +decision variable. + +.. autosummary:: + :toctree: generated/ + + variables.Variable + +Attributes +---------- + +.. autosummary:: + :toctree: generated/ + + variables.Variable.lower + variables.Variable.upper + variables.Variable.type + variables.Variable.solution + +Modification +------------ + +.. autosummary:: + :toctree: generated/ + + variables.Variable.fix + variables.Variable.unfix + variables.Variable.relax + variables.Variable.unrelax + +Operations +---------- + +.. autosummary:: + :toctree: generated/ -``Variable`` is a subclass of ``xarray.DataArray`` and contains all labels referring to a multi-dimensional variable. + variables.Variable.sum + variables.Variable.where + +Conversion +---------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ + + variables.Variable.to_linexpr + variables.Variable.to_polars - variables.Variable - variables.Variable.lower - variables.Variable.upper - variables.Variable.sum - variables.Variable.where - variables.Variable.sanitize - variables.Variables - variables.ScalarVariable Variables +========= + +Container for the collection of variables on a model. Accessed via +``model.variables``. + +.. autosummary:: + :toctree: generated/ + + variables.Variables + +Attributes +---------- + +.. autosummary:: + :toctree: generated/ + + variables.Variables.lower + variables.Variables.upper + variables.Variables.solution + +Modification +------------ + +.. autosummary:: + :toctree: generated/ + + variables.Variables.fix + variables.Variables.unfix + variables.Variables.relax + variables.Variables.unrelax + +Inventory --------- -``Variables`` is a container for multiple N-D labeled variables. It is automatically added to a ``Model`` instance when initialized. +.. autosummary:: + :toctree: generated/ + + variables.Variables.continuous + variables.Variables.binaries + variables.Variables.integers + variables.Variables.semi_continuous + variables.Variables.sos + + +LinearExpression +================ + +Linear combination of variables. Arithmetic on ``Variable`` / +``LinearExpression`` returns a ``LinearExpression``. + +.. autosummary:: + :toctree: generated/ + + expressions.LinearExpression + +Post-solve access +----------------- + +.. autosummary:: + :toctree: generated/ + + expressions.LinearExpression.solution + +Operations +---------- + +.. autosummary:: + :toctree: generated/ + + expressions.LinearExpression.sum + expressions.LinearExpression.where + expressions.LinearExpression.groupby + expressions.LinearExpression.rolling + +Structure +--------- + +.. autosummary:: + :toctree: generated/ + + expressions.LinearExpression.vars + expressions.LinearExpression.coeffs + expressions.LinearExpression.const + expressions.LinearExpression.nterm + +Conversion +---------- + +.. autosummary:: + :toctree: generated/ + + expressions.LinearExpression.to_polars + +Construction +------------ .. autosummary:: - :toctree: generated/ + :toctree: generated/ - variables.Variables - variables.Variables.add - variables.Variables.remove - variables.Variables.continuous - variables.Variables.integers - variables.Variables.binaries - variables.Variables.integers - variables.Variables.flat + expressions.LinearExpression.from_tuples + expressions.merge -LinearExpressions +QuadraticExpression +=================== + +Quadratic combination of variables, returned when squared +``Variable`` / ``LinearExpression`` arithmetic is performed. + +.. autosummary:: + :toctree: generated/ + + expressions.QuadraticExpression + +Structure +--------- + +.. autosummary:: + :toctree: generated/ + + expressions.QuadraticExpression.vars + expressions.QuadraticExpression.coeffs + expressions.QuadraticExpression.const + expressions.QuadraticExpression.nterm + +Conversion +---------- + +.. autosummary:: + :toctree: generated/ + + expressions.QuadraticExpression.to_matrix + expressions.QuadraticExpression.to_polars + +Post-solve access ----------------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ + + expressions.QuadraticExpression.solution - expressions.LinearExpression - expressions.LinearExpression.sum - expressions.LinearExpression.where - expressions.LinearExpression.groupby - expressions.LinearExpression.rolling - expressions.LinearExpression.from_tuples - expressions.merge - expressions.ScalarLinearExpression Constraint ----------- +========== + +Subclass of ``xarray.DataArray`` carrying labels for a multi-dimensional +constraint. -``Constraint`` is a subclass of ``xarray.DataArray`` and contains all labels referring to a multi-dimensional constraint. +.. autosummary:: + :toctree: generated/ + + constraints.Constraint + +Structure +--------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ - constraints.Constraint - constraints.Constraint.coeffs - constraints.Constraint.vars - constraints.Constraint.lhs - constraints.Constraint.sign - constraints.Constraint.rhs - constraints.Constraint.flat - constraints.Constraint.freeze - constraints.Constraint.mutable + constraints.Constraint.lhs + constraints.Constraint.sign + constraints.Constraint.rhs + constraints.Constraint.coeffs + constraints.Constraint.vars + +Post-solve access +----------------- + +.. autosummary:: + :toctree: generated/ + + constraints.Constraint.dual + +Conversion +---------- + +.. autosummary:: + :toctree: generated/ + + constraints.Constraint.to_polars CSRConstraint -------------- +============= + +Memory-efficient, immutable constraint representation backed by a scipy +CSR sparse matrix. Opt in via ``Model(freeze_constraints=True)`` or +``Model.add_constraints(..., freeze=True)``. See the +:doc:`creating-constraints` guide for usage. + +.. autosummary:: + :toctree: generated/ + + constraints.CSRConstraint -``CSRConstraint`` is a memory-efficient, immutable constraint representation backed by a scipy CSR sparse matrix. See the :doc:`creating-constraints` guide for usage. +Structure +--------- + +.. autosummary:: + :toctree: generated/ + + constraints.CSRConstraint.coeffs + constraints.CSRConstraint.vars + constraints.CSRConstraint.sign + constraints.CSRConstraint.rhs + constraints.CSRConstraint.ncons + constraints.CSRConstraint.nterm + +Post-solve access +----------------- + +.. autosummary:: + :toctree: generated/ + + constraints.CSRConstraint.dual + +Conversion +---------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ - constraints.CSRConstraint - constraints.CSRConstraint.coeffs - constraints.CSRConstraint.vars - constraints.CSRConstraint.sign - constraints.CSRConstraint.rhs - constraints.CSRConstraint.ncons - constraints.CSRConstraint.nterm - constraints.CSRConstraint.freeze - constraints.CSRConstraint.mutable + constraints.CSRConstraint.to_polars Constraints ------------ +=========== + +Container for the collection of constraints on a model. Accessed via +``model.constraints``. + +.. autosummary:: + :toctree: generated/ + + constraints.Constraints + +Inventory +--------- + +.. autosummary:: + :toctree: generated/ + + constraints.Constraints.inequalities + constraints.Constraints.equalities + +Aggregate access +---------------- + +.. autosummary:: + :toctree: generated/ + + constraints.Constraints.coeffs + constraints.Constraints.vars + constraints.Constraints.sign + constraints.Constraints.rhs + constraints.Constraints.dual + +Conversion +---------- + +.. autosummary:: + :toctree: generated/ + + constraints.Constraints.to_matrix + + +Objective +========= + +Wraps the objective expression on a model. Accessed via +``model.objective``. .. autosummary:: - :toctree: generated/ + :toctree: generated/ + + objective.Objective + objective.Objective.expression + objective.Objective.sense + objective.Objective.value + objective.Objective.is_linear + objective.Objective.is_quadratic - constraints.Constraints - constraints.Constraints.add - constraints.Constraints.remove - constraints.Constraints.coefficientrange - constraints.Constraints.inequalities - constraints.Constraints.equalities - constraints.Constraints.sanitize_missings - constraints.Constraints.flat - constraints.Constraints.to_matrix +Piecewise +========= -IO functions -============ +Construction helpers +-------------------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ + + piecewise.breakpoints + piecewise.segments + piecewise.Slopes - model.Model.get_problem_file - model.Model.get_solution_file - model.Model.to_file - model.Model.to_netcdf - io.read_netcdf +PiecewiseFormulation +-------------------- -Solver utilities -================= +Returned by :func:`Model.add_piecewise_formulation`. .. autosummary:: - :toctree: generated/ + :toctree: generated/ - solvers.available_solvers - solvers.quadratic_solvers - solvers.Solver + piecewise.PiecewiseFormulation + piecewise.PiecewiseFormulation.method + piecewise.PiecewiseFormulation.convexity + piecewise.PiecewiseFormulation.variables + piecewise.PiecewiseFormulation.constraints + +Low-level helper +---------------- + +.. autosummary:: + :toctree: generated/ + + piecewise.tangent_lines + +Type aliases +------------ + +.. autosummary:: + :toctree: generated/ + + constants.PWL_METHOD + constants.PWL_METHODS + constants.PWL_CONVEXITY + constants.PWL_CONVEXITIES Solvers ======= .. autosummary:: - :toctree: generated/ + :toctree: generated/ + + solvers.available_solvers + solvers.CBC + solvers.COPT + solvers.Cplex + solvers.GLPK + solvers.Gurobi + solvers.Highs + solvers.Knitro + solvers.MindOpt + solvers.Mosek + solvers.SCIP + solvers.Xpress + solvers.cuPDLPx + + +Remote solving +============== + +.. autosummary:: + :toctree: generated/ - solvers.CBC - solvers.Cplex - solvers.GLPK - solvers.Gurobi - solvers.Highs - solvers.Mosek - solvers.SCIP - solvers.Xpress + remote.RemoteHandler -Solving +Solver status and result types +============================== + +Types returned by or compared against :attr:`Model.status`, +:attr:`Model.termination_condition`, and :attr:`Model.solution`. + +.. autosummary:: + :toctree: generated/ + + constants.SolverStatus + constants.TerminationCondition + constants.Status + constants.Solution + constants.Result + + +Utilities +========= + +.. autosummary:: + :toctree: generated/ + + align + options + + +Warnings ======== +These warning classes can be silenced or filtered via +:func:`warnings.filterwarnings`. + .. autosummary:: - :toctree: generated/ + :toctree: generated/ - model.Model.solve - constants.SolverStatus - constants.TerminationCondition - constants.Status - constants.Solution - constants.Result + EvolvingAPIWarning + PerformanceWarning diff --git a/doc/benchmark.rst b/doc/benchmark.rst index da2a98e9..f56d5dff 100644 --- a/doc/benchmark.rst +++ b/doc/benchmark.rst @@ -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 `_ package written in `Julia `_. It even outperforms `JuMP` in total memory efficiency when it comes to large models. Compared to `Pyomo `_, the common optimization package in python, one can expect @@ -13,9 +13,9 @@ for large problems. The following figure shows the memory usage and speed for so .. math:: - & \min \;\; \sum_{i,j} 2 x_{i,j} \; y_{i,j} \\ + & \min \;\; \sum_{i,j} 2 x_{i,j} + y_{i,j} \\ s.t. & \\ - & x_{i,j} - y_{i,j} \; \ge \; i \qquad \forall \; i,j \in \{1,...,N\} \\ + & x_{i,j} - y_{i,j} \; \ge \; i-1 \qquad \forall \; i,j \in \{1,...,N\} \\ & x_{i,j} + y_{i,j} \; \ge \; 0 \qquad \forall \; i,j \in \{1,...,N\} diff --git a/doc/conf.py b/doc/conf.py index 5525d366..e28bde83 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -18,7 +18,7 @@ # -- Project information ----------------------------------------------------- project = "linopy" -copyright = "2021, Fabian Hofmann" +copyright = "2021-2026, Fabian Hofmann" author = "Fabian Hofmann" # The full version, including alpha/beta/rc tags @@ -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 diff --git a/doc/contributing.rst b/doc/contributing.rst index 120683cb..4bb9b60a 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -13,14 +13,13 @@ You are invited to submit pull requests / issues to our Development Setup ================= -For linting, formatting and checking your code contributions -against our guidelines (e.g. we use `Black `_ as code style -and use `pre-commit `_: +For linting and formatting, we use `ruff `_ +and run it via `pre-commit `_: 1. Installation ``conda install -c conda-forge pre-commit`` or ``pip install pre-commit`` 2. Usage: * To automatically activate ``pre-commit`` on every ``git commit``: Run ``pre-commit install`` - * To manually run it: ``pre-commit run --all`` + * To manually run it: ``pre-commit run --all-files`` Running Tests ============= @@ -122,23 +121,25 @@ Then for every notebook: e.g. `Edit -> Clear all output` in JupyterLab. 3. Provide a link to the documentation: - Include a file ``foo.nblink`` located in ``doc/examples/foo.nblink`` + Include a file ``foo.nblink`` located in ``doc/foo.nblink`` with this content - .. code-block: - { - 'path' : '../../examples/foo.ipynb' - } + .. code-block:: json + + { + "path": "../examples/foo.ipynb" + } + + Adjust the path for your file's name. + This ``nblink`` allows us to link your notebook into the documentation. - Adjust the path for your file's name. - This ``nblink`` allows us to link your notebook into the documentation. 4. Link your file in the documentation: Either - * Include your ``examples/foo.nblink`` directly into one of - the documentations toctrees; or - * Tell us where in the documentation you want your example to show up + * Include your ``foo.nblink`` directly into one of + the documentation's toctrees; or + * Tell us where in the documentation you want your example to show up 5. Commit your changes. If the precommit hook you installed above kicks in, confirm diff --git a/doc/coordinate-alignment.nblink b/doc/coordinate-alignment.nblink new file mode 100644 index 00000000..ef588b91 --- /dev/null +++ b/doc/coordinate-alignment.nblink @@ -0,0 +1,3 @@ +{ + "path": "../examples/coordinate-alignment.ipynb" +} diff --git a/doc/index.rst b/doc/index.rst index a4d34ce7..ea61747c 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -23,7 +23,7 @@ Main features `xarray `__ which allows for many flexible data-handling features: -- Define (arrays of) contnuous or binary variables with +- Define (arrays of) continuous or binary variables with **coordinates**, e.g. time, consumers, etc. - Apply **arithmetic operations** on the variables like adding, subtracting, multiplying with all the **broadcasting** potentials of @@ -81,7 +81,7 @@ A BibTeX entry for LaTeX users is License ------- -Copyright 2021-2023 Fabian Hofmann +Copyright 2021-2026 Fabian Hofmann This package is published under MIT license. @@ -112,23 +112,46 @@ 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 @@ -136,7 +159,7 @@ This package is published under MIT license. .. toctree:: :hidden: :maxdepth: 2 - :caption: References + :caption: Reference api release_notes diff --git a/doc/prerequisites.rst b/doc/prerequisites.rst index 97d51296..afb0e8a7 100644 --- a/doc/prerequisites.rst +++ b/doc/prerequisites.rst @@ -36,21 +36,26 @@ CPU-based solvers - `Cbc `__ - open source, free, fast - `GLPK `__ - open source, free, not very fast - `HiGHS `__ - open source, free, fast +- `SCIP `__ - open source (Apache-2.0), fast MIP solver - `Gurobi `__ - closed source, commercial, very fast - `Xpress `__ - closed source, commercial, very fast (GPU acceleration available in v9.8+) - `Cplex `__ - closed source, commercial, very fast -- `MOSEK `__ -- `MindOpt `__ - +- `MOSEK `__ - closed source, commercial, strong on conic/QP +- `MindOpt `__ - closed source, commercial - `COPT `__ - closed source, commercial, very fast -For a subset of the solvers, Linopy provides a wrapper. +The ``linopy[solvers]`` extra installs the Python clients for the +supported solvers (HiGHS, SCIP, Gurobi, CPLEX, MOSEK, MindOpt, COPT, +Xpress, Knitro). For the commercial ones a separate license is still +required: .. code:: bash pip install linopy[solvers] -We recommend to install the HiGHS solver if possible, which is free and open source but not yet available on all platforms. +We recommend installing the HiGHS solver, which is free, open source, and +fast across a wide range of problem sizes: .. code:: bash diff --git a/doc/user-guide.rst b/doc/user-guide.rst index 494ac240..8b7ee5bd 100644 --- a/doc/user-guide.rst +++ b/doc/user-guide.rst @@ -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 ` 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. diff --git a/examples/create-a-model-with-coordinates.ipynb b/examples/create-a-model-with-coordinates.ipynb index f2b12eed..e8021a35 100644 --- a/examples/create-a-model-with-coordinates.ipynb +++ b/examples/create-a-model-with-coordinates.ipynb @@ -150,7 +150,7 @@ "metadata": {}, "outputs": [], "source": [ - "m.solve(solver_name=\"highs\")" + "m.solve(solver_name=\"highs\", output_flag=False)" ] }, { @@ -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": { diff --git a/examples/create-a-model.ipynb b/examples/create-a-model.ipynb index a158e0cf..b6fc9705 100644 --- a/examples/create-a-model.ipynb +++ b/examples/create-a-model.ipynb @@ -215,7 +215,7 @@ "metadata": {}, "outputs": [], "source": [ - "m.solve(solver_name=\"highs\")" + "m.solve(solver_name=\"highs\", output_flag=False)" ] }, { diff --git a/examples/creating-expressions.ipynb b/examples/creating-expressions.ipynb index 1d808b07..d0bf0db4 100644 --- a/examples/creating-expressions.ipynb +++ b/examples/creating-expressions.ipynb @@ -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", @@ -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": {} }, { diff --git a/examples/creating-variables.ipynb b/examples/creating-variables.ipynb index 8e879348..9179a31a 100644 --- a/examples/creating-variables.ipynb +++ b/examples/creating-variables.ipynb @@ -31,6 +31,12 @@ "m = Model()" ] }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "", + "id": "46c4f2824a2ed8aa" + }, { "cell_type": "markdown", "id": "6c6420a7", @@ -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", diff --git a/examples/manipulating-models.ipynb b/examples/manipulating-models.ipynb index 81106ab3..6903386b 100644 --- a/examples/manipulating-models.ipynb +++ b/examples/manipulating-models.ipynb @@ -48,9 +48,9 @@ "con2 = m.add_constraints(5 * x + 2 * y >= 3 * factor, name=\"con2\")\n", "\n", "m.add_objective(x + 2 * y)\n", - "m.solve(solver_name=\"highs\")\n", + "m.solve(solver_name=\"highs\", output_flag=False)\n", "\n", - "m.solve(solver_name=\"highs\")\n", + "m.solve(solver_name=\"highs\", output_flag=False)\n", "sol = m.solution.to_dataframe()\n", "sol.plot(grid=True, ylabel=\"Optimal Value\")" ] @@ -95,7 +95,7 @@ "metadata": {}, "outputs": [], "source": [ - "m.solve(solver_name=\"highs\")\n", + "m.solve(solver_name=\"highs\", output_flag=False)\n", "sol = m.solution.to_dataframe()\n", "sol.plot(grid=True, ylabel=\"Optimal Value\")" ] @@ -137,7 +137,7 @@ "metadata": {}, "outputs": [], "source": [ - "m.solve(solver_name=\"highs\")\n", + "m.solve(solver_name=\"highs\", output_flag=False)\n", "sol = m.solution.to_dataframe()\n", "sol.plot(grid=True, ylabel=\"Optimal Value\")" ] @@ -190,7 +190,7 @@ "metadata": {}, "outputs": [], "source": [ - "m.solve(solver_name=\"highs\")\n", + "m.solve(solver_name=\"highs\", output_flag=False)\n", "sol = m.solution.to_dataframe()\n", "sol.plot(grid=True, ylabel=\"Optimal Value\")" ] @@ -242,7 +242,7 @@ "metadata": {}, "outputs": [], "source": [ - "m.solve(solver_name=\"highs\")\n", + "m.solve(solver_name=\"highs\", output_flag=False)\n", "sol = m.solution.to_dataframe()\n", "sol.plot(grid=True, ylabel=\"Optimal Value\")" ] @@ -276,7 +276,7 @@ "metadata": {}, "outputs": [], "source": [ - "m.solve(solver_name=\"highs\")\n", + "m.solve(solver_name=\"highs\", output_flag=False)\n", "sol = m.solution.to_dataframe()\n", "sol.plot(grid=True, ylabel=\"Optimal Value\")" ] @@ -326,7 +326,7 @@ "# Penalize activation of z in the objective\n", "m.objective = x + 3 * y + 10 * z\n", "\n", - "m.solve(solver_name=\"highs\")" + "m.solve(solver_name=\"highs\", output_flag=False)" ] }, { @@ -346,7 +346,7 @@ "source": [ "m.variables.binaries.fix()\n", "m.variables.binaries.relax()\n", - "m.solve(solver_name=\"highs\")\n", + "m.solve(solver_name=\"highs\", output_flag=False)\n", "\n", "# Dual values are now available on the constraints\n", "m.constraints[\"con1\"].dual" diff --git a/examples/solve-on-remote.ipynb b/examples/solve-on-remote.ipynb index 4e2a1b13..659cf9d6 100644 --- a/examples/solve-on-remote.ipynb +++ b/examples/solve-on-remote.ipynb @@ -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" ] }, { diff --git a/examples/transport-tutorial.ipynb b/examples/transport-tutorial.ipynb index b42e67e8..cd5cdccd 100644 --- a/examples/transport-tutorial.ipynb +++ b/examples/transport-tutorial.ipynb @@ -417,7 +417,7 @@ "outputs": [], "source": [ "# Solve the model\n", - "m.solve(solver_name=\"highs\")" + "m.solve(solver_name=\"highs\", output_flag=False)" ] }, { diff --git a/linopy/config.py b/linopy/config.py index 240eaed6..5d269c4e 100644 --- a/linopy/config.py +++ b/linopy/config.py @@ -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() diff --git a/linopy/constants.py b/linopy/constants.py index 5cc98ce2..09244323 100644 --- a/linopy/constants.py +++ b/linopy/constants.py @@ -60,9 +60,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 :func:`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" diff --git a/linopy/expressions.py b/linopy/expressions.py index 2218eef3..2ab0b8d3 100644 --- a/linopy/expressions.py +++ b/linopy/expressions.py @@ -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 @@ -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 @@ -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 diff --git a/linopy/model.py b/linopy/model.py index 21e4e29c..f9273e83 100644 --- a/linopy/model.py +++ b/linopy/model.py @@ -1233,14 +1233,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): diff --git a/linopy/objective.py b/linopy/objective.py index b1449270..a51b2207 100644 --- a/linopy/objective.py +++ b/linopy/objective.py @@ -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: diff --git a/linopy/piecewise.py b/linopy/piecewise.py index 7497c4bf..ccc265a7 100644 --- a/linopy/piecewise.py +++ b/linopy/piecewise.py @@ -346,11 +346,10 @@ 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. @@ -358,10 +357,12 @@ class PiecewiseFormulation: 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: