From f8446d9249b9eee43b7360c3550d4e6b985d7593 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Mon, 11 May 2026 15:09:55 +0200 Subject: [PATCH 1/2] docs: silence HiGHS console output in tutorial notebooks HiGHS prints a banner + progress lines to the Python REPL on every m.solve() call by default. In a tutorial that calls solve many times, this drowns the actual lesson in solver chatter. Pass output_flag=False (a HiGHS solver option forwarded via **solver_options) to suppress it. Touches the four notebooks where solver_name="highs" is the only solver invoked: - create-a-model.ipynb - create-a-model-with-coordinates.ipynb - manipulating-models.ipynb (9 solves) - transport-tutorial.ipynb Left alone: - infeasible-model.ipynb (uses Gurobi, kwarg is OutputFlag there; also showing solver feedback may be pedagogically relevant for infeasibility detection). - solve-on-remote.ipynb / solve-on-oetc.ipynb (remote handler manages its own logging). - piecewise-*.ipynb (already addressed in #677). Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/create-a-model-with-coordinates.ipynb | 2 +- examples/create-a-model.ipynb | 2 +- examples/manipulating-models.ipynb | 18 +++++++++--------- examples/transport-tutorial.ipynb | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/create-a-model-with-coordinates.ipynb b/examples/create-a-model-with-coordinates.ipynb index f2b12eed..e84c21b9 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)" ] }, { 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/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/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)" ] }, { From 6d61112ec588a2b56e8c664a0bcebea9a8c53273 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Mon, 11 May 2026 15:24:47 +0200 Subject: [PATCH 2/2] docs: silence HiGHS console output in piecewise tutorials too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the log-silencing scope to the two piecewise tutorials, which together call m.solve() nine times. Same transformation as the other notebooks — output_flag=False as a HiGHS-specific kwarg forwarded via **solver_options. Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/piecewise-inequality-bounds.ipynb | 40 ++++++++++----------- examples/piecewise-linear-constraints.ipynb | 16 ++++----- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/examples/piecewise-inequality-bounds.ipynb b/examples/piecewise-inequality-bounds.ipynb index a79c612d..101f28d5 100644 --- a/examples/piecewise-inequality-bounds.ipynb +++ b/examples/piecewise-inequality-bounds.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Piecewise inequalities \u2014 per-tuple sign\n", + "# Piecewise inequalities — per-tuple sign\n", "\n", "`add_piecewise_formulation` accepts an optional third tuple element, `\"<=\"` or `\">=\"`, that marks one expression as **bounded** by the piecewise curve instead of pinned to it:\n", "\n", @@ -15,17 +15,17 @@ ")\n", "```\n", "\n", - "This notebook walks through the geometry, the curvature \u00d7 sign matching that lets `method=\"auto\"` skip MIP machinery entirely, and the feasible regions produced by each method (LP, SOS2, incremental). For the formulation math see the [reference page](piecewise-linear-constraints).\n", + "This notebook walks through the geometry, the curvature × sign matching that lets `method=\"auto\"` skip MIP machinery entirely, and the feasible regions produced by each method (LP, SOS2, incremental). For the formulation math see the [reference page](piecewise-linear-constraints).\n", "\n", "## Key points\n", "\n", "| Tuple form | Behaviour |\n", "|---|---|\n", "| `(expr, breaks)` | Pinned: `expr` lies exactly on the curve. |\n", - "| `(expr, breaks, \"<=\")` | Bounded above: `expr \u2264 f(other tuples)`. |\n", - "| `(expr, breaks, \">=\")` | Bounded below: `expr \u2265 f(other tuples)`. |\n", + "| `(expr, breaks, \"<=\")` | Bounded above: `expr ≤ f(other tuples)`. |\n", + "| `(expr, breaks, \">=\")` | Bounded below: `expr ≥ f(other tuples)`. |\n", "\n", - "Currently at most one tuple may carry a non-equality sign, and 3+ tuples must all be equality. Multi-bounded and N\u22653 inequality cases aren't supported yet \u2014 if you have a concrete use case, please open an issue at https://github.com/PyPSA/linopy/issues so we can scope it properly." + "Currently at most one tuple may carry a non-equality sign, and 3+ tuples must all be equality. Multi-bounded and N≥3 inequality cases aren't supported yet — if you have a concrete use case, please open an issue at https://github.com/PyPSA/linopy/issues so we can scope it properly." ] }, { @@ -48,7 +48,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "## Setup \u2014 a concave curve\n\nWe use a concave, monotonically increasing curve. With a tuple bounded `<=`, the LP method is applicable (concave + `<=` is a tight relaxation)." + "source": "## Setup — a concave curve\n\nWe use a concave, monotonically increasing curve. With a tuple bounded `<=`, the LP method is applicable (concave + `<=` is a tight relaxation)." }, { "cell_type": "code", @@ -79,11 +79,11 @@ "\n", "With one tuple bounded `<=` and our concave curve, the three methods give the **same** feasible region within `[x_0, x_n]`:\n", "\n", - "- **`method=\"lp\"`** \u2014 tangent lines + domain bounds. No auxiliary variables.\n", - "- **`method=\"sos2\"`** \u2014 lambdas + SOS2 + split link (pinned equality, bounded signed). Solver picks the piece.\n", - "- **`method=\"incremental\"`** \u2014 delta fractions + binaries + split link. Same mathematics, MIP encoding instead of SOS2.\n", + "- **`method=\"lp\"`** — tangent lines + domain bounds. No auxiliary variables.\n", + "- **`method=\"sos2\"`** — lambdas + SOS2 + split link (pinned equality, bounded signed). Solver picks the piece.\n", + "- **`method=\"incremental\"`** — delta fractions + binaries + split link. Same mathematics, MIP encoding instead of SOS2.\n", "\n", - "`method=\"auto\"` dispatches to `\"lp\"` whenever applicable \u2014 it's always preferable because it's pure LP.\n", + "`method=\"auto\"` dispatches to `\"lp\"` whenever applicable — it's always preferable because it's pure LP.\n", "\n", "Let's verify they produce the same solution at `power=15`." ] @@ -98,17 +98,17 @@ } }, "outputs": [], - "source": "def solve(method, power_val):\n m = linopy.Model()\n power = m.add_variables(lower=0, upper=30, name=\"power\")\n fuel = m.add_variables(lower=0, upper=40, name=\"fuel\")\n m.add_piecewise_formulation(\n (fuel, y_pts, \"<=\"), # bounded\n (power, x_pts), # pinned\n method=method,\n )\n m.add_constraints(power == power_val)\n m.add_objective(-fuel) # maximise fuel to push against the bound\n m.solve()\n return float(m.solution[\"fuel\"]), list(m.variables), list(m.constraints)\n\n\nfor method in [\"lp\", \"sos2\", \"incremental\"]:\n fuel_val, vars_, cons_ = solve(method, 15)\n print(f\"{method:12}: fuel={fuel_val:.2f} vars={vars_} cons={cons_}\")" + "source": "def solve(method, power_val):\n m = linopy.Model()\n power = m.add_variables(lower=0, upper=30, name=\"power\")\n fuel = m.add_variables(lower=0, upper=40, name=\"fuel\")\n m.add_piecewise_formulation(\n (fuel, y_pts, \"<=\"), # bounded\n (power, x_pts), # pinned\n method=method,\n )\n m.add_constraints(power == power_val)\n m.add_objective(-fuel) # maximise fuel to push against the bound\n m.solve(output_flag=False)\n return float(m.solution[\"fuel\"]), list(m.variables), list(m.constraints)\n\n\nfor method in [\"lp\", \"sos2\", \"incremental\"]:\n fuel_val, vars_, cons_ = solve(method, 15)\n print(f\"{method:12}: fuel={fuel_val:.2f} vars={vars_} cons={cons_}\")" }, { "cell_type": "markdown", "metadata": {}, - "source": "All three give `fuel=25` at `power=15` (which is `f(15)` exactly) \u2014 the math is equivalent. The LP method is strictly cheaper: no auxiliary variables, just three chord constraints and two domain bounds.\n\nThe SOS2 and incremental methods create lambdas (or deltas + binaries) and split the link into a pinned-equality constraint plus a signed bounded link \u2014 but the feasible region is the same." + "source": "All three give `fuel=25` at `power=15` (which is `f(15)` exactly) — the math is equivalent. The LP method is strictly cheaper: no auxiliary variables, just three chord constraints and two domain bounds.\n\nThe SOS2 and incremental methods create lambdas (or deltas + binaries) and split the link into a pinned-equality constraint plus a signed bounded link — but the feasible region is the same." }, { "cell_type": "markdown", "metadata": {}, - "source": "## Visualising the feasible region\n\nThe feasible region for `(power, fuel)` with `fuel` bounded `<=` is the **hypograph** of `f` restricted to the curve's x-domain:\n\n$$\\{ (x, y) : x_0 \\le x \\le x_n,\\ y \\le f(x) \\}$$\n\nWe colour green feasible points, red infeasible ones. Three test points:\n\n- `(15, 15)` \u2014 inside the curve, `15 \u2264 f(15)=25` \u2713\n- `(15, 25)` \u2014 on the curve \u2713\n- `(15, 29)` \u2014 above `f(15)`, should be infeasible \u2717\n- `(35, 20)` \u2014 power beyond domain, infeasible \u2717" + "source": "## Visualising the feasible region\n\nThe feasible region for `(power, fuel)` with `fuel` bounded `<=` is the **hypograph** of `f` restricted to the curve's x-domain:\n\n$$\\{ (x, y) : x_0 \\le x \\le x_n,\\ y \\le f(x) \\}$$\n\nWe colour green feasible points, red infeasible ones. Three test points:\n\n- `(15, 15)` — inside the curve, `15 ≤ f(15)=25` ✓\n- `(15, 25)` — on the curve ✓\n- `(15, 29)` — above `f(15)`, should be infeasible ✗\n- `(35, 20)` — power beyond domain, infeasible ✗" }, { "cell_type": "code", @@ -144,7 +144,7 @@ "ax.set(\n", " xlabel=\"power\",\n", " ylabel=\"fuel\",\n", - " title=\"sign='<=' feasible region \u2014 hypograph of f(x) on [x_0, x_n]\",\n", + " title=\"sign='<=' feasible region — hypograph of f(x) on [x_0, x_n]\",\n", ")\n", "ax.grid(alpha=0.3)\n", "ax.legend()\n", @@ -157,16 +157,16 @@ "source": [ "## When is LP the right choice?\n", "\n", - "`tangent_lines` imposes the **intersection** of chord inequalities. Whether that intersection matches the true hypograph/epigraph of `f` depends on the curvature \u00d7 sign combination:\n", + "`tangent_lines` imposes the **intersection** of chord inequalities. Whether that intersection matches the true hypograph/epigraph of `f` depends on the curvature × sign combination:\n", "\n", "| curvature | bounded `<=` | bounded `>=` |\n", "|-----------|--------------|--------------|\n", - "| **concave** | **hypograph (exact \u2713)** | **wrong region** \u2014 requires `y \u2265 max_k chord_k(x) > f(x)` |\n", - "| **convex** | **wrong region** \u2014 requires `y \u2264 min_k chord_k(x) < f(x)` | **epigraph (exact \u2713)** |\n", + "| **concave** | **hypograph (exact ✓)** | **wrong region** — requires `y ≥ max_k chord_k(x) > f(x)` |\n", + "| **convex** | **wrong region** — requires `y ≤ min_k chord_k(x) < f(x)` | **epigraph (exact ✓)** |\n", "| linear | exact | exact |\n", "| mixed (non-convex) | convex hull of `f` (wrong for exact hypograph) | concave hull of `f` (wrong for exact epigraph) |\n", "\n", - "In the \u2717 cases, tangent lines do **not** give a loose relaxation \u2014 they give a **strictly wrong feasible region** that rejects points satisfying the true constraint. Example: for a concave `f` with `y \u2265 f(x)`, the chord of any piece extrapolated over another piece's x-range lies *above* `f`, so `y \u2265 max_k chord_k(x)` forbids `y = f(x)` itself.\n", + "In the ✗ cases, tangent lines do **not** give a loose relaxation — they give a **strictly wrong feasible region** that rejects points satisfying the true constraint. Example: for a concave `f` with `y ≥ f(x)`, the chord of any piece extrapolated over another piece's x-range lies *above* `f`, so `y ≥ max_k chord_k(x)` forbids `y = f(x)` itself.\n", "\n", "`method=\"auto\"` dispatches to LP only in the two **exact** cases (concave + `<=` or convex + `>=`). For the other combinations it falls back to SOS2 or incremental, which encode the hypograph/epigraph exactly via discrete piece selection.\n", "\n", @@ -185,12 +185,12 @@ } }, "outputs": [], - "source": "# 1. Non-convex curve: auto falls back (LP relaxation would be loose)\nx_nc = [0, 10, 20, 30]\ny_nc = [0, 20, 10, 30] # slopes change sign \u2192 mixed convexity\n\nm1 = linopy.Model()\nx1 = m1.add_variables(lower=0, upper=30, name=\"x\")\ny1 = m1.add_variables(lower=0, upper=40, name=\"y\")\nf1 = m1.add_piecewise_formulation((y1, y_nc, \"<=\"), (x1, x_nc))\nprint(f\"non-convex + '<=' \u2192 {f1.method}\")\n\n# 2. Concave curve + sign='>=': LP would be loose \u2192 auto falls back to MIP\nx_cc = [0, 10, 20, 30]\ny_cc = [0, 20, 30, 35] # concave\n\nm2 = linopy.Model()\nx2 = m2.add_variables(lower=0, upper=30, name=\"x\")\ny2 = m2.add_variables(lower=0, upper=40, name=\"y\")\nf2 = m2.add_piecewise_formulation((y2, y_cc, \">=\"), (x2, x_cc))\nprint(f\"concave + '>=' \u2192 {f2.method}\")\n\n# 3. Explicit method=\"lp\" with mismatched curvature raises\ntry:\n m3 = linopy.Model()\n x3 = m3.add_variables(lower=0, upper=30, name=\"x\")\n y3 = m3.add_variables(lower=0, upper=40, name=\"y\")\n m3.add_piecewise_formulation((y3, y_cc, \">=\"), (x3, x_cc), method=\"lp\")\nexcept ValueError as e:\n print(f\"lp(concave, '>=') \u2192 raises: {e}\")" + "source": "# 1. Non-convex curve: auto falls back (LP relaxation would be loose)\nx_nc = [0, 10, 20, 30]\ny_nc = [0, 20, 10, 30] # slopes change sign → mixed convexity\n\nm1 = linopy.Model()\nx1 = m1.add_variables(lower=0, upper=30, name=\"x\")\ny1 = m1.add_variables(lower=0, upper=40, name=\"y\")\nf1 = m1.add_piecewise_formulation((y1, y_nc, \"<=\"), (x1, x_nc))\nprint(f\"non-convex + '<=' → {f1.method}\")\n\n# 2. Concave curve + sign='>=': LP would be loose → auto falls back to MIP\nx_cc = [0, 10, 20, 30]\ny_cc = [0, 20, 30, 35] # concave\n\nm2 = linopy.Model()\nx2 = m2.add_variables(lower=0, upper=30, name=\"x\")\ny2 = m2.add_variables(lower=0, upper=40, name=\"y\")\nf2 = m2.add_piecewise_formulation((y2, y_cc, \">=\"), (x2, x_cc))\nprint(f\"concave + '>=' → {f2.method}\")\n\n# 3. Explicit method=\"lp\" with mismatched curvature raises\ntry:\n m3 = linopy.Model()\n x3 = m3.add_variables(lower=0, upper=30, name=\"x\")\n y3 = m3.add_variables(lower=0, upper=40, name=\"y\")\n m3.add_piecewise_formulation((y3, y_cc, \">=\"), (x3, x_cc), method=\"lp\")\nexcept ValueError as e:\n print(f\"lp(concave, '>=') → raises: {e}\")" }, { "cell_type": "markdown", "metadata": {}, - "source": "## Summary\n\n- Default is all-equality: every tuple lies on the curve.\n- Append `\"<=\"` or `\">=\"` as a third tuple element to mark one expression as bounded by the curve.\n- `method=\"auto\"` picks the most efficient formulation: LP for matching-curvature 2-variable inequalities, otherwise SOS2 or incremental.\n- At most one tuple may be bounded; with 3+ tuples all must be equality. Multi-bounded and N\u22653 inequality use cases \u2014 please open an issue at https://github.com/PyPSA/linopy/issues so we can scope them." + "source": "## Summary\n\n- Default is all-equality: every tuple lies on the curve.\n- Append `\"<=\"` or `\">=\"` as a third tuple element to mark one expression as bounded by the curve.\n- `method=\"auto\"` picks the most efficient formulation: LP for matching-curvature 2-variable inequalities, otherwise SOS2 or incremental.\n- At most one tuple may be bounded; with 3+ tuples all must be equality. Multi-bounded and N≥3 inequality use cases — please open an issue at https://github.com/PyPSA/linopy/issues so we can scope them." } ], "metadata": { diff --git a/examples/piecewise-linear-constraints.ipynb b/examples/piecewise-linear-constraints.ipynb index 392ca8f1..fe1da9b8 100644 --- a/examples/piecewise-linear-constraints.ipynb +++ b/examples/piecewise-linear-constraints.ipynb @@ -81,7 +81,7 @@ "pwf = m.add_piecewise_formulation((power, x_pts), (fuel, y_pts))\n", "m.add_constraints(power == demand, name=\"demand\")\n", "m.add_objective(fuel.sum())\n", - "m.solve(reformulate_sos=\"auto\")\n", + "m.solve(reformulate_sos=\"auto\", output_flag=False)\n", "\n", "print(pwf) # inspect the auto-resolved method\n", "m.solution[[\"power\", \"fuel\"]].to_pandas()" @@ -136,7 +136,7 @@ " m.add_piecewise_formulation((power, x_pts), (fuel, y_pts), method=method)\n", " m.add_constraints(power == demand, name=\"demand\")\n", " m.add_objective(fuel.sum())\n", - " m.solve(reformulate_sos=\"auto\")\n", + " m.solve(reformulate_sos=\"auto\", output_flag=False)\n", " return m.solution[\"fuel\"].to_pandas()\n", "\n", "\n", @@ -175,7 +175,7 @@ ")\n", "m.add_constraints(power + backup == xr.DataArray([15, 60, 75], coords=[time]))\n", "m.add_objective(cost.sum() + 10 * backup.sum())\n", - "m.solve(reformulate_sos=\"auto\")\n", + "m.solve(reformulate_sos=\"auto\", output_flag=False)\n", "m.solution[[\"power\", \"cost\", \"backup\"]].to_pandas()" ] }, @@ -225,7 +225,7 @@ ")\n", "m.add_constraints(power == xr.DataArray([30, 80, 100], coords=[time]))\n", "m.add_objective(-fuel.sum()) # push fuel against the bound\n", - "m.solve(reformulate_sos=\"auto\")\n", + "m.solve(reformulate_sos=\"auto\", output_flag=False)\n", "\n", "print(f\"resolved method={pwf.method}, curvature={pwf.convexity}\")\n", "m.solution[[\"power\", \"fuel\"]].to_pandas()" @@ -282,7 +282,7 @@ "# demand below p_min at t=1 — commit must be 0 and backup covers it\n", "m.add_constraints(power + backup == xr.DataArray([15, 80, 40], coords=[time]))\n", "m.add_objective(fuel.sum() + 50 * commit.sum() + 200 * backup.sum())\n", - "m.solve(reformulate_sos=\"auto\")\n", + "m.solve(reformulate_sos=\"auto\", output_flag=False)\n", "m.solution[[\"commit\", \"power\", \"fuel\", \"backup\"]].to_pandas()" ] }, @@ -330,7 +330,7 @@ ")\n", "m.add_constraints(fuel == xr.DataArray([20, 100, 160], coords=[time]))\n", "m.add_objective(power.sum())\n", - "m.solve(reformulate_sos=\"auto\")\n", + "m.solve(reformulate_sos=\"auto\", output_flag=False)\n", "m.solution[[\"power\", \"fuel\", \"heat\"]].to_pandas().round(2)" ] }, @@ -388,7 +388,7 @@ "m.add_piecewise_formulation((power, x_gen), (fuel, y_gen))\n", "m.add_constraints(power.sum(\"gen\") == xr.DataArray([80, 120, 50], coords=[time]))\n", "m.add_objective(fuel.sum())\n", - "m.solve(reformulate_sos=\"auto\")\n", + "m.solve(reformulate_sos=\"auto\", output_flag=False)\n", "m.solution[[\"power\", \"fuel\"]].to_dataframe()" ] }, @@ -417,7 +417,7 @@ ")\n", "m.add_constraints(power == demand, name=\"demand\")\n", "m.add_objective(fuel.sum())\n", - "m.solve(reformulate_sos=\"auto\")\n", + "m.solve(reformulate_sos=\"auto\", output_flag=False)\n", "\n", "m.solution[[\"power\", \"fuel\"]].to_pandas()" ]