Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 1 addition & 15 deletions examples/infeasible-model.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,7 @@
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"\n",
"import linopy\n",
"\n",
"m = linopy.Model()\n",
"\n",
"time = pd.RangeIndex(10, name=\"time\")\n",
"x = m.add_variables(lower=0, coords=[time], name=\"x\")\n",
"y = m.add_variables(lower=0, coords=[time], name=\"y\")\n",
"\n",
"m.add_constraints(x <= 5)\n",
"m.add_constraints(y <= 5)\n",
"m.add_constraints(x + y >= 12)"
]
"source": "import pandas as pd\n\nimport linopy\n\nm = linopy.Model()\n\ntime = pd.RangeIndex(10, name=\"time\")\nx = m.add_variables(lower=0, coords=[time], name=\"x\")\ny = m.add_variables(lower=0, coords=[time], name=\"y\")\n\nm.add_constraints(x <= 5)\nm.add_constraints(y <= 5)\nm.add_constraints(x + y >= 12)\n\n# A trivial objective is required; the model is solved purely to check feasibility.\nm.add_objective(0 * x)"
},
{
"attachments": {},
Expand Down
6 changes: 6 additions & 0 deletions linopy/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1484,6 +1484,12 @@ def solve(
sanitize_zeros=sanitize_zeros, sanitize_infinities=sanitize_infinities
)

if self.objective.expression.empty:
raise ValueError(
"No objective has been set on the model. Use `m.add_objective(...)` "
"first (e.g. `m.add_objective(0 * x)` for a pure feasibility problem)."
)

# clear cached matrix properties potentially present from previous solve commands
self.matrices.clean_cached_properties()

Expand Down
1 change: 1 addition & 0 deletions test/test_infeasibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ def test_unsupported_solver_error(self) -> None:
x = m.add_variables(name="x")
m.add_constraints(x >= 0)
m.add_constraints(x <= -1) # Make it infeasible
m.add_objective(1 * x)

# Use a solver that doesn't support IIS
if "cbc" in available_solvers:
Expand Down
8 changes: 8 additions & 0 deletions test/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ def test_objective() -> None:
m.objective = m.objective + 3


def test_solve_without_objective_raises() -> None:
# https://github.com/PyPSA/linopy/issues/668
m: Model = Model()
m.add_variables(lower=0, upper=10, name="myvar")
with pytest.raises(ValueError, match="No objective has been set"):
m.solve()


def test_remove_variable() -> None:
m: Model = Model()

Expand Down
3 changes: 2 additions & 1 deletion test/test_oetc_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,8 @@ def test_model_solve_forwards_to_oetc() -> None:
from linopy import Model

m = Model()
m.add_variables(lower=0, name="x")
x = m.add_variables(lower=0, name="x")
m.add_objective(1 * x)

handler = MagicMock(spec=OetcHandler)
mock_solved = MagicMock()
Expand Down
Loading