Skip to content

docs(piecewise): rewrite reference page + tutorials for correctness and pedagogy#677

Merged
FabianHofmann merged 29 commits into
masterfrom
docs/piecewise-precision
May 12, 2026
Merged

docs(piecewise): rewrite reference page + tutorials for correctness and pedagogy#677
FabianHofmann merged 29 commits into
masterfrom
docs/piecewise-precision

Conversation

@FBumann
Copy link
Copy Markdown
Collaborator

@FBumann FBumann commented May 11, 2026

What was wrong

The piecewise documentation had grown organically and accumulated several precision, structural, and pedagogical problems.

Correctness bugs

  • Disjunctive auxiliary-variables row in the comparison table said "Binary + SOS2", but _add_disjunctive actually creates continuous lambda_var, binary segment selectors, and an SOS2 constraint — three kinds, not two.
  • LP domain bound math was written x_0 ≤ x ≤ x_n, implicitly assuming ascending breakpoints. _lp_eligibility accepts strict monotonicity in either direction; the math should be x_min ≤ x ≤ x_max.
  • Inequality Quick Start example used (fuel, [0, 20, 30, 35], "<=") with the misleading comment "pinned to the curve" on the other tuple. Bounding fuel (a consumption-side variable) with <= was the anti-pattern the doc's own "Choice of bounded tuple" section warned against.
  • (0, 0) "off" segment in the disjunctive example used a degenerate single-point segment to encode on/off — exactly what active=... (Advanced Features) is for. The example duplicated a pattern that has a proper API and taught a bad habit.
  • Disjunctive table caveat that "Disjunctive (segments) → always sos2" appeared in the prose before the table, where the apparent contradiction (.method == "sos2" but a separate column) was confusing.
  • Implementation-detail leakage: a "Formulation math" subsection named internal constraint suffixes (*_link, *_output_link) while a different part of the page said names "are an implementation detail and may evolve".
  • "Pinned" was geometrically misleading: the doc claimed pinned tuples "lie on the curve", but for 2-tuple inequalities the pinned axis's marginal feasible set is just its breakpoint domain — a single coordinate can't locate a curve point.
  • Tutorial 2 was structured around fuel ≤ f(power) with a maximise -fuel objective. The artificial objective hid the fact that bounding fuel from above admits fuel = 0, which makes no physical sense.

Structural problems

  • "Per-tuple sign" was a chapter masquerading as a section — six concepts under one heading (roles, restrictions, joint geometry across 1/2/3+ tuples, formulation math, sign-choice motivation, deactivation warning). Readers looking up "how do I supply breakpoints" had to scroll past all of it.
  • Two breakpoint sections — "Breakpoint inputs" under API (overview) and "Breakpoint Construction" as its own section (tutorial). Same three building blocks, overlapping content.
  • tangent_lines was a useful standalone helper buried in a paragraph inside the LP method section.
  • Tutorial 1 §2's method-comparison table appeared before §3 and §4 had defined the terms it referenced (sign, curvature requirements).
  • Tutorial 2's standalone setup plot showed the same curve that the hypograph/epigraph visualisation later in the notebook would show again with operating points.

Tutorial-execution noise

  • Every m.solve() printed the HiGHS banner and the once-per-session EvolvingAPIWarning, drowning the actual lesson.

What changed

doc/piecewise-linear-constraints.rst

  • Restructured: moved Breakpoint Construction ahead of Per-tuple sign, split the latter into four focused subsections, folded the duplicate "Breakpoint inputs" overview into it, promoted tangent_lines to its own subsection under LP, and shortened the up-front terminology block.
  • Removed the abstract "Formulation math" subsection; the load-bearing active=0 warning moved into Active parameter.
  • Fixed factual content: corrected the Disjunctive aux-vars row, rewrote the LP domain bound as x_min ≤ x ≤ x_max, referenced :ref:sos-reformulation`` for the Big-M fallback, generalised "Choice of bounded tuple" to both signs, and explained why active isn't supported with `method="lp"`.
  • Replaced misleading examples: Quick Start inequality now uses fuel ≥ f(power) on the same curve as the equality example; disjunctive snippet replaces the (0, 0) on/off hack with a stepped pump and points to active=... for on/off.

examples/piecewise-linear-constraints.ipynb

  • New intro with an 8-section roadmap; heading renamed to "Creating Piecewise Linear Constraints".
  • §2 method comparison trimmed to a forward pointer.
  • §3 rewritten as two pumps in parallel with two operating bands each (low / high) and a forbidden zone. Demand [30, 75, 150] makes every timestep single-pump-infeasible. Output is a flat 4-column DataFrame.
  • §4 inequality now uses fuel ≥ f(power) on §1's curve.
  • New closing "When to use what" table with cross-links.

examples/piecewise-inequality-bounds.ipynb

  • Heading renamed to "Creating Piecewise Inequality Bounds".
  • Intro rewritten (motivation, then snippet, then a precise tuple-roles table); standalone setup plot removed.
  • Reframed end-to-end around fuel ≥ f(power) with breakpoints aligned to the rest of the doc; hypograph visualisation replaced with the epigraph variant; fallback cell exercises the dual mismatched-curvature cases.
  • New summary cross-linking back to the linear-constraints tutorial.

Both tutorials

  • m.solve(...) calls now pass solver_name="highs", reformulate_sos="auto", and output_flag=False.
  • Imports cell silences EvolvingAPIWarning.

Pedagogical additions (beyond the stated bug list)

A few additions go beyond fixing the documented problems and into making the docs a better read. Calling them out explicitly so they're easy to review or revert:

  • Tutorial 1 intro roadmap (8-section list).
  • Tutorial 1 "When to use what" closing table (cheat-sheet for picking the right API pattern).
  • Tutorial 2 "Tuple roles" table (replaces and expands the old "Key points" table with role + what-it-constrains semantics).
  • Tutorial 2 closing summary with cross-links back to the linear-constraints tutorial.
  • tangent_lines promoted to its own subsection under LP (discoverability — the function existed before but was buried).

Test plan

  • sphinx-build of doc/ renders without warnings.
  • CI's "Test documentation notebooks" job passes on both notebooks.
  • :ref:sos-reformulation`` link resolves correctly.

🤖 Generated with Claude Code

FBumann and others added 2 commits May 11, 2026 14:17
- "breakpoint" is now framed as one knot defined by the i-th entry of
  each tuple, so the N-tuple linking case isn't (x, y)-specific.
- "pinned" is reframed as a sign role, with a brief breakdown of what
  it actually constrains: joint-on-curve only with 2+ pinned tuples;
  with one bounded + one pinned, the pinned axis collapses to a
  [x_min, x_max] domain box (LP enforces it directly, SOS2/incremental
  via the weight link).
- Disjunctive auxiliary-variables cell corrected to
  "Continuous + binary + SOS2".
- SOS2/disjunctive solver-requirement cells now mention the Big-M
  reformulation path and link to :ref:`sos-reformulation`.
- LP domain bound math uses x_min/x_max (descending grids accepted).
- Per-tuple-sign formulation math switched to a method-agnostic
  W_j(weights, B) so the section covers both SOS2 (lambda) and
  incremental (delta) accurately.
- "Two factories" lead-in widened to three building blocks so Slopes
  isn't hidden in the code block.
- Quick Start inequality bounds heat (a curtailable output) instead of
  fuel, matching the doc's own "choice of bounded tuple" guidance.
- Tutorials: add output_flag=False to m.solve(...) calls so HiGHS's
  banner/progress doesn't clutter the nbsphinx-rendered output;
  linopy's INFO logs (including auto-dispatch resolution) are kept.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…r Constraints"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FBumann FBumann marked this pull request as draft May 11, 2026 12:22
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FBumann
Copy link
Copy Markdown
Collaborator Author

FBumann commented May 11, 2026

@FabianHofmann I would argue that we could try to remove the solver logs from the tutorials in the docs overall...?
WOuld improve readability and reduce noise i think

FBumann and others added 7 commits May 11, 2026 14:33
- Tut 1 intro now opens with a one-line description plus an 8-section
  roadmap, replacing the jargon-y "stacks one feature on top of a
  small shared dispatch pattern" line.
- Tut 1 §3 explains the degenerate (0, 0) "off" segment instead of
  leaving it for the reader to puzzle out.
- Tut 1 §4 inequality example now bounds `heat` (a curtailable output)
  on a concave curve, matching the rst doc's "choice of bounded tuple"
  guidance.  Variables use intuitive `power_pts` / `heat_pts` names so
  the plot cell no longer needs a "swap to put power on the x-axis"
  comment.
- Tut 1 ends with a "When to use what" table cross-linking to the rst
  reference page and to the inequality-bounds tutorial.
- Tut 2 intro leads with the one-sided-bound motivation and the
  pure-LP pay-off before the API snippet, and the "Tuple roles" table
  matches the rst's precision: with one bounded + one equality tuple,
  the equality tuple's marginal feasible set is just its breakpoint
  domain (not "lies exactly on the curve").
- Tut 2's summary cross-links back to the linear-constraints tutorial.
- Both notebooks: removed remaining "pinned" wording where it implied
  geometric on-curve placement instead of a sign role.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Other linopy tutorials (create-a-model.ipynb, manipulating-models.ipynb,
etc.) explicitly pass solver_name='highs' to m.solve(...). The piecewise
tutorials relied on the default-available-solver fallback, which made
the HiGHS-specific output_flag kwarg look mysterious.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous framing — fuel <= f(power) with objective -fuel — is
logically off: bounding fuel from above lets the solver choose any
non-negative fuel, including zero (since fuel is consumption-side).
The artificial maximise-fuel objective hid this but the underlying
relation didn't make physical sense.

Power ≤ f(fuel) is the classic production-function bound: f maps fuel
input to the maximum power the unit can deliver, and the unit can
always run below that (output is curtailable).  Maximising power
against the bound is now a sensible LP objective rather than a
contrivance.

- Reframed cells 0, 2, 3, 4, 5, 6, 7, 8, 10 around fuel_pts /
  power_pts; axis labels and the hypograph plot now read (fuel, power)
  with f(fuel) as the production curve.
- Cell 5's objective is now `-power` (maximise power up to the curve
  bound), matching real LPs.
- Test points and curvature × sign analysis unchanged — only the
  physical interpretation flipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous version bounded `heat` by a curve labelled "concave" — but the
slopes (0.8, 1.0, 1.33) are increasing, so the curve is actually convex,
and `heat <= f(power)` on a convex curve doesn't dispatch to LP.

Switched to a convex heat-rate curve with `fuel >= f(power)`: over-
fuelling is physically admissible (waste heat) but wasteful, so
minimising fuel pulls the operating point onto the curve.  This is the
epigraph half of the LP-applicable region, complementing the inequality-
bounds tutorial's hypograph example (concave + `<=`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Matches the tutorial 1 §4 reframe: convex heat-rate curve with
``fuel >= f(power)``, where over-fuelling is admissible but wasteful so
minimisation pulls the operating point onto the curve.  Replaces the
heat <= f(power) example (which used a curve that was actually convex,
not concave, so it wouldn't have dispatched to LP).

Generalised the "Choice of bounded tuple" guidance to cover both signs:

- ``"<="`` for a controllable dissipation path (curtailment, post-
  treatment).
- ``">="`` for an input whose over-supply is admissible but wasteful
  (fuel, raw materials).

The wrong-direction warning now spells out both anti-patterns: ``"<="``
on fuel, ``">="`` on a non-curtailable output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reuses §1's exact breakpoints — only the sign on one tuple changes —
so the reader sees "the same curve, now with an inequality" rather than
a new curve.  Reads as a production function: power output is bounded
by what the fuel input can support, and the unit may run below the
maximum (curtailable output).

Same physical meaning as the previous fuel ≥ f(power) framing (the two
forms describe the same feasible region under inversion), but more
intuitive and continuous with the rest of the tutorial.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Inequality-bounds tutorial now uses the same curve as §1/§4 of the
linear-constraints tutorial and the rst Quick Start:

  fuel_pts  = [0, 36, 84, 170]
  power_pts = [0, 30, 60, 100]

This concave production curve has f(60) = 45, so the verification cell
checks power = 45 at fuel = 60.  The hypograph-visualisation test
points are scaled to the new axes: (60, 30) under, (60, 45) on,
(60, 55) above, (180, 50) beyond domain.  The non-convex fallback
example also uses the [0, 170] fuel domain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FabianHofmann
Copy link
Copy Markdown
Collaborator

@FabianHofmann I would argue that we could try to remove the solver logs from the tutorials in the docs overall...? WOuld improve readability and reduce noise i think

yes, totally

FBumann and others added 3 commits May 11, 2026 14:50
The warning fires once per session on first use of
add_piecewise_formulation / Slopes / tangent_lines.  Useful in user
code, but in a tutorial it's a distracting wall of yellow above the
first solve.  Silenced in the imports cell of each notebook via
warnings.filterwarnings — the canonical recipe from the warning
message itself.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Heat-rate framing — `fuel = f(power)` — is native to power-systems
modelling, so the inequality variant reads naturally as `fuel ≥
f(power)`: the curve is the design minimum, over-fuelling is admissible
but wasteful, and minimising fuel pulls the operating point onto the
curve.  Same feasible region as the previous `power ≤ f(fuel)` form
under inversion; the LP path uses the convex + `>=` (epigraph) half
instead of concave + `<=` (hypograph).

- rst Quick Start: bound fuel ≥ f(power), same breakpoints as §1.
- Tutorial 1 §4: same.
- Tutorial 2: setup curve labelled "convex heat-rate curve f(power)";
  solve checks fuel=84 at power=60; visualisation is now the epigraph
  with test points (60, 100), (60, 84), (60, 70), (120, 100); fallback
  cell exercises the dual mismatched-curvature cases (convex + `<=`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HiGHS doesn't natively support SOS constraints, so the sos2 and
incremental cases of the three-methods comparison need
reformulate_sos="auto" (matching tutorial 1's pattern).  Without it,
m.solve(solver_name="highs", ...) raises ValueError on the SOS2 path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
FBumann added a commit that referenced this pull request May 11, 2026
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) <noreply@anthropic.com>
@FBumann FBumann force-pushed the docs/piecewise-precision branch from e58dcd4 to 825af88 Compare May 11, 2026 13:39
FBumann and others added 3 commits May 11, 2026 15:49
RST restructure
- Moved "Breakpoint Construction" ahead of "Per-tuple sign".  Readers
  looking up "how do I supply breakpoints" no longer have to scroll
  through the inequality section first.
- Split "Per-tuple sign" — previously a chapter masquerading as a
  section, covering six concepts under one heading — into five proper
  subsections: Roles and restrictions, Geometry, Choice of bounded
  tuple and sign, When is a one-sided bound wanted?, Formulation math.
- Folded the duplicate "Breakpoint inputs" overview (under API) into
  the lead-in of "Breakpoint Construction"; the three building blocks
  (breakpoints, segments, Slopes) are now introduced once.
- Promoted tangent_lines to its own "Chord expressions as a building
  block" subsection under LP — previously a half-hidden paragraph.
- Moved the disjunctive caveat ("method returns 'sos2' but the table
  treats it separately") into a `.. note::` directly under the
  comparison table where the apparent contradiction is.
- Shortened the terminology block at the top to one paragraph (it
  previously defined "segment" hundreds of lines before the disjunctive
  section).
- Centralised N≥3 sign restriction — N-variable linking section now
  cross-references Per-tuple sign instead of redefining it.
- Removed the duplicated active+sign warning under "Advanced Features"
  — single source of truth now in "Per-tuple sign / Formulation math".

Tutorial flow
- Tut 1 §2: trimmed the upfront method-comparison table to a forward
  pointer — the table previously claimed "lp requires sign != ==" and
  "matching curvature" before §3 and §4 had tutorialised those terms.
- Tut 2: dropped the standalone setup plot that showed only the curve.
  The hypograph/epigraph visualisation later in the notebook already
  shows the curve, with the operating points overlaid — saves a
  figure and tightens the narrative.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…o Active

The W_j(weights, B) abstraction it introduced was immediately re-
derived in each method section below (SOS2 with λ, incremental with
δ), so it added a layer for the reader to climb through without
delivering content the method sections didn't already.  The
"*_link" / "*_output_link" naming detail contradicted our own guidance
elsewhere ("exact name suffixes are an implementation detail and may
evolve").  The "equality keeps equality, bounded flips sign" idea is
already conveyed by Roles & restrictions and Geometry above.

The one load-bearing nugget was the active=0 warning.  Moved it into
the Active parameter (unit commitment) subsection under Advanced
Features, where readers setting `active=...` actually land — that's
where the gotcha needs to be visible.

Also dropped the now-stale cross-reference from the Incremental method
section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
"Not supported with method='lp'" reads as a missing feature; one-line
addition explains it's structural (gating needs a binary) and points
to the auto-dispatch and to tangent_lines for manual gating.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FBumann FBumann force-pushed the docs/piecewise-precision branch from 6d3b99f to c2fe7f6 Compare May 11, 2026 14:16
FBumann and others added 7 commits May 11, 2026 16:21
…example

The previous example used `segments([(0, 0), (50, 80)])` — the (0,0)
"off" segment was a hack to encode on/off behaviour, which is exactly
what `active=...` (§5) is for.  Using disjunctive for on/off
duplicates §5 and teaches a bad pattern.

New example shows what disjunctive is actually for: equipment without
a continuous design space — gas turbines in three commercial classes
(small / medium / large), each with its own non-overlapping power band
and 2-piece heat-rate curve.  The formulation picks the appropriate
class per timestep based on demand.

Added a forward pointer to §5 for the on/off case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…izing

Matches the tutorial §3 rewrite — uses three turbine classes with
non-overlapping operating bands as the canonical disjunctive example,
and adds a one-line steer away from the (0,0) anti-pattern toward
`active=...` for on/off gating.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The turbine-classes framing was claiming "investment" but the
formulation puts the binary on the time dimension by default — so
the model was actually re-deciding the class each timestep, not
making a one-time sizing call.  Either we'd need a contrived
constraint to make the binary time-invariant, or we'd be using an
"investment" narrative on per-period selection.

Pump VSD is honest per-period selection: a pump with three stepped
speed settings, each covering a different flow band, switches speed
between dispatch periods as a matter of normal operation.  No
constraints to bolt on, no narrative-vs-math gap.

Also added "switchable combustion cycles" and "allowed bands around
forbidden vibration zones" as alternative real use cases in the
intro, so readers see disjunctive is for genuine multi-mode
equipment.

Updated both the rst Disjunctive-segments code block and the
tutorial §3 (markdown intro, code, explanatory cell) to use the
pump example.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two pumps in parallel, each with two operating bands (low 5–25 m³/h,
high 40–100 m³/h) and a forbidden zone in between.  Demand profile
[30, 75, 150] makes every timestep single-pump-infeasible:

- t=1, demand=30: lands in the single-pump gap (25, 40); both pumps
  run in low band, splitting the load.
- t=2, demand=75: too much for low+low (max 50), too little for
  high+high (min 80); the low pump tops out at 25, the high pump
  covers the remaining 50.
- t=3, demand=150: exceeds a single pump's maximum (100); both pumps
  run in high band.

Each segment is now a single piece (2 breakpoints), so the example is
clean and the load-split arithmetic is explicit.  Rst snippet updated
to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
power_p1 / power_p2 / flow (total) per timestep — the asymmetric split
at t=2 is visible directly in the powers (one pump at 7 kW, the other
at ~21 kW) instead of buried in a multi-index DataFrame.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
flat 4-column DataFrame (flow_p1, flow_p2, power_p1, power_p2) per
timestep, via unstack on the pump dimension.  The asymmetric splits
are visible directly: at t=2 one pump runs at flow=25 (low band), the
other at flow=50 (high band).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
§3 previously rebound the Python `demand` variable to its own
pump-tutorial values [30, 75, 150], which then broke §4 and §8
downstream: both rely on §1's `demand = [50, 80, 30]`, and §4 with
demand=150 is infeasible (power.upper=100).

Inlined §3's demand into the constraint so the global namespace is
untouched.  Verified §1 → §3 → §4 sequence end-to-end: §4 now solves
to optimal with fuel = [68, 127, 36].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FBumann FBumann changed the title docs(piecewise): tighten language and fix small inaccuracies docs(piecewise): rewrite reference page + tutorials for correctness and pedagogy May 11, 2026
FBumann and others added 4 commits May 11, 2026 22:17
…he code block

A five-line "# ..." comment inside the snippet was carrying the
formulation explanation — that belongs as rst prose around the code
block, not stuffed into the Python.  Code block now has a single
one-line orienting comment; the rationale moves to a paragraph below.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The two-line "stepped pump ... forbidden zone" comment inside the
code block duplicated the prose immediately above ("stepped pump
speeds ... forbidden vibration zones").  Single-line orienting
comment is enough.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bare-slug markdown links (`[text](piecewise-linear-constraints)`)
produced sphinx "File not found" warnings AND rendered with href
attributes missing the `.html` extension, requiring browser-side
resolution.  Switching to `.html` form generates correct `href`s
in the rendered HTML directly — verified against the built doc:

  <a class="reference external" href="piecewise-linear-constraints.html">
  <a class="reference external" href="piecewise-inequality-bounds-tutorial.html">

Sphinx still warns at build time (its link checker doesn't find a
source file with `.html` extension), but the warnings are cosmetic
and the rendered docs work correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous .html form rendered correct browser hrefs but produced
sphinx "File not found" warnings AND rendered as external links.

Switching to source-extension form:
- [text](page.rst) for rst pages
- [text](tutorial.nblink) for sibling notebook tutorials

Sphinx resolves both to internal cross-references at build time —
HTML output shows `class="reference internal"` with the doc anchor,
no build warnings.  Verified locally: piecewise cross-link warnings
went from 6 to 0 (total build warnings 20 → 10, the remainder are
pre-existing unrelated issues).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FBumann FBumann marked this pull request as ready for review May 11, 2026 20:44
Comment thread doc/piecewise-linear-constraints.rst Outdated
works here.

For a single on/off gate on one continuous curve, prefer ``active=...``
(see *Advanced Features* below) — using a degenerate ``(0, 0)`` segment
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"advanced features" should likely be a ref link

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now links directly to the active parameter

Comment thread doc/piecewise-linear-constraints.rst Outdated
- At most one tuple may carry a non-equality sign — a single bounded side.
- With **3 or more** tuples, all signs must be ``"=="``.

Multi-bounded and N≥3-inequality use cases aren't supported yet. If
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could go into a info block

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally

Comment thread doc/piecewise-linear-constraints.rst Outdated
- :func:`~linopy.segments` — **disjoint** operating regions with gaps
between them (e.g. forbidden zones); selects the disjunctive
formulation automatically.
- :class:`~linopy.Slopes` — per-piece slopes plus an initial ``y0``,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a more detailed explanation on their usages. it would be helpful to know how they show up in the code. add a paragraph what their individual purpose is (either individually or combined) or ref examples (like the notebook)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rewrote the section as a whole. now starts with a brief intro thats closely related to our data mdoel (breakpoints or segments), followed by how to pass breakpoints or segments. Slopes is framed as a convenience for breakpoints (which it is. We resolve it to breakpoints)

FBumann added a commit that referenced this pull request May 12, 2026
1. Forward pointer to the Active parameter section now uses a proper
   `:ref:` link.  Added a `_piecewise-active:` label above the
   subsection so it survives reorganisation.

2. The Restrictions block under "Roles and restrictions" became a
   `.. note::` admonition (matching the pattern in sos-constraints.rst
   and gpu-acceleration.rst).

3. Rewrote Breakpoint Construction.  Previously six subsections
   organised around input-shape and example type (From lists / factory
   / From slopes / Per-entity / Disjunctive / N-variable); now four
   organised around the three building blocks themselves:

   - ``breakpoints()`` — connected curve, with use case (efficiency
     curves, heat rates, cost curves) and the per-entity option folded
     in as a subsection.
   - ``segments()`` — disjoint operating bands.
   - ``Slopes`` — marginal-cost specification.
   - N-variable linking (kept separate; orthogonal to input type).

   Each subsection opens with the use case it addresses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FBumann FBumann force-pushed the docs/piecewise-precision branch from fa58ae0 to 1753923 Compare May 12, 2026 11:21
Fabian's review raised three points (#677 (review)):

1. "Advanced features" forward-pointer should be a ref link.

   Added `_piecewise-active:` label above the Active parameter
   subsection; the disjunctive forward-pointer now uses
   `:ref:`piecewise-active`` (renders as a clickable internal link).

2. Restrictions block could be an info block.

   Converted to `.. note::` (matching the existing pattern in
   sos-constraints.rst and gpu-acceleration.rst — the codebase doesn't
   use `.. info::`, only note/warning).

3. Building blocks need more detail on usage.

   Restructured Breakpoint Construction.  Originally six subsections
   organised around input shape (From lists / breakpoints() factory /
   From slopes / Per-entity / Disjunctive / N-variable).  Now organised
   around the two factories with Slopes folded in as a convenience:

   - `breakpoints()` — connected curve.  Opens with use case
     (efficiency curves, heat rates, cost curves).  Two bold-inline
     sub-blocks: **Per-entity curves.** (dict input) and **Specifying
     by slopes.** (Slopes wrapper).
   - `segments()` — disjoint operating bands.  Opens with use case.
     Trimmed redundant trailing prose; kept the bounded-tuple
     compatibility note as a one-liner.
   - N-variable linking — kept separate (orthogonal to input type).

   Added a two-sentence signpost at the top of Breakpoint Construction
   that transitions from the API signature: names both factories with
   cross-refs and positions Slopes as a slope-input stand-in for
   `breakpoints()` (not a separate building block — Slopes resolves to
   a breakpoints array internally).

Plus minor editorial cleanups from the iteration:
- Dropped the SOS2 jargon from the `segments()` opener (replaced with
  "continuous interpolation within the chosen band" — the SOS2 method
  is introduced later in Formulation Methods).
- Dropped the accepted-datatypes enumeration from the `breakpoints()`
  opener (redundant with examples and the function's docstring).
- Dropped the ambiguous "prices per MWh per operating step" example
  from the Slopes block — both electricity-specific and confusable
  with the disjunctive/VSD case from §3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FBumann FBumann force-pushed the docs/piecewise-precision branch from d186853 to 532dab6 Compare May 12, 2026 11:46
@FBumann
Copy link
Copy Markdown
Collaborator Author

FBumann commented May 12, 2026

@FabianHofmann Its ready.

@FabianHofmann FabianHofmann merged commit c04d272 into master May 12, 2026
22 of 23 checks passed
@FabianHofmann FabianHofmann deleted the docs/piecewise-precision branch May 12, 2026 14:30
FabianHofmann pushed a commit that referenced this pull request May 15, 2026
…ces (#680)

* 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) <noreply@anthropic.com>

* docs: silence HiGHS console output in piecewise tutorials too

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) <noreply@anthropic.com>

* docs: fix broken toctree, refresh API reference, and clean up references

- Add doc/coordinate-alignment.nblink so the index.rst toctree entry
  resolves to examples/coordinate-alignment.ipynb.
- Update api.rst to match the current public API: add the missing
  solver classes (COPT, Knitro, MindOpt, PIPS, cuPDLPx), expose
  top-level helpers (align, merge, options, EvolvingAPIWarning,
  PerformanceWarning), add the missing Model methods
  (add_sos_constraints, reformulate_sos_constraints,
  compute_infeasibilities, format_infeasibilities), add Variable
  methods (to_linexpr, fix/unfix, relax/unrelax), add sections for
  QuadraticExpression, Objective, and RemoteHandler, remove the
  duplicate Variables.integers, and fix the "hook" -> "hood" typo.
- contributing.rst: replace stale Black reference with ruff, correct
  the nblink example (proper JSON, right path, fixed RST indentation
  that was breaking pygments), and use pre-commit run --all-files.
- benchmark.rst: fix the rendered objective, which read as a product
  of two variables; corrected to the actual linear benchmark
  (2x + y with x - y >= i-1, matching benchmark_linopy.py).
- prerequisites.rst: add SCIP, give MOSEK a description, drop the
  dangling "-" after MindOpt, remove the outdated HiGHS-platforms
  claim, and clarify what the [solvers] extra actually pulls in.
- conf.py + index.rst: bump copyright to 2026 and fix the
  "contnuous" typo on the landing page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
FabianHofmann pushed a commit that referenced this pull request May 18, 2026
* 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) <noreply@anthropic.com>

* docs: silence HiGHS console output in piecewise tutorials too

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) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
FBumann added a commit that referenced this pull request May 18, 2026
…uide landing (#681)

* 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) <noreply@anthropic.com>

* docs: silence HiGHS console output in piecewise tutorials too

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) <noreply@anthropic.com>

* docs: fix broken toctree, refresh API reference, and clean up references

- Add doc/coordinate-alignment.nblink so the index.rst toctree entry
  resolves to examples/coordinate-alignment.ipynb.
- Update api.rst to match the current public API: add the missing
  solver classes (COPT, Knitro, MindOpt, PIPS, cuPDLPx), expose
  top-level helpers (align, merge, options, EvolvingAPIWarning,
  PerformanceWarning), add the missing Model methods
  (add_sos_constraints, reformulate_sos_constraints,
  compute_infeasibilities, format_infeasibilities), add Variable
  methods (to_linexpr, fix/unfix, relax/unrelax), add sections for
  QuadraticExpression, Objective, and RemoteHandler, remove the
  duplicate Variables.integers, and fix the "hook" -> "hood" typo.
- contributing.rst: replace stale Black reference with ruff, correct
  the nblink example (proper JSON, right path, fixed RST indentation
  that was breaking pygments), and use pre-commit run --all-files.
- benchmark.rst: fix the rendered objective, which read as a product
  of two variables; corrected to the actual linear benchmark
  (2x + y with x - y >= i-1, matching benchmark_linopy.py).
- prerequisites.rst: add SCIP, give MOSEK a description, drop the
  dangling "-" after MindOpt, remove the outdated HiGHS-platforms
  claim, and clarify what the [solvers] extra actually pulls in.
- conf.py + index.rst: bump copyright to 2026 and fix the
  "contnuous" typo on the landing page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: reorganize toctree into basic→advanced sections and rewrite user-guide landing page

Split the previously flat 16-item User Guide bag into focused
sections so users move from install to advanced features in a clear
order:

  Getting Started → User Guide (core building blocks) →
  Advanced Features → Tutorials → Solving → Troubleshooting →
  Benchmarking → Reference

Rewrite user-guide.rst from a one-paragraph stub into a roadmap
landing page: it groups the core notebooks (variables, expressions,
constraints, coordinate alignment, manipulating models) into a
recommended reading order and points outward to advanced topics,
tutorials, remote/GPU solving, and troubleshooting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: fix broken admonitions in notebooks and configure intersphinx

Three RST admonitions in notebook markdown cells had a blank line
between the directive and a tab-indented body. CommonMark then ate
the indented block as a code block, so nbsphinx saw an empty
directive ("Content block expected for the …" build errors). Fix by
removing the blank line and using a 3-space indent — the convention
already used by the working admonitions in the same notebooks
(e.g. creating-variables cell `..note::\n   Since we did not …`).

- creating-expressions.ipynb cell 13: restored `.. important::` on
  coordinate-determination semantics.
- creating-expressions.ipynb cell 17: restored `.. tip::` pointing
  at `.add/.sub/.mul/.div` with the `join` parameter and the
  coordinate-alignment guide.
- creating-variables.ipynb cell 42: re-added a corrected `.. note::`
  on `coords=` being ignored when supplied alongside pandas objects.
  Dropped the stale "New in version 0.3.6" framing and the broken
  "is ignored is passed" wording from the original.

conf.py: configure intersphinx_mapping for python, numpy, pandas,
xarray, scipy, and dask. The intersphinx extension was already
loaded but had no mapping, so cross-references like
:class:`xarray.DataArray` or :func:`numpy.ndarray` were silently
unresolved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: downgrade coordinate-determination admonition from important to note

The coordinate-determination behaviour is regular alignment semantics,
not a sharp pitfall — note is the right level.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Revert "docs: downgrade coordinate-determination admonition from important to note"

This reverts commit e44cbd3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci: empty commit to retrigger CI

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: rename toctree captions and reorder Examples below Solving

- Benchmarking → Comparisons. The two children (performance and
  syntax) both compare linopy with JuMP and Pyomo, not "benchmark"
  in the regression-tracking sense.
- benchmark.rst H1: Benchmarks → Performance comparison, so the
  page title matches the section framing (syntax.rst was already
  "Syntax comparison").
- Tutorials → Examples. The contents are end-to-end worked problems
  and a migration guide; "Tutorials" overloads with the rest of the
  docs (every notebook is tutorial-style).
- Move Examples below Solving so the section flow is
  Getting Started → User Guide → Advanced Features → Solving →
  Examples → Troubleshooting → Comparisons → Reference. The user
  now knows how to both build and run a model before being handed a
  full worked problem.

Update the user-guide.rst cross-reference accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: move Examples directly under User Guide

Sit Examples right after the core building blocks so users move from
"I learned the mechanics" to "show me a complete worked problem"
before tackling Advanced Features and Solving.

Final sidebar order:
  Getting Started → User Guide → Examples → Advanced Features →
  Solving → Troubleshooting → Comparisons → Reference

Reorder the corresponding bullets in user-guide.rst so the prose
matches the sidebar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: bridge Getting Started → User Guide and rename landing page H1

Three small fixes that tighten the boundary between the two top
sections without changing what each one covers:

- Append a "Where to next" cell to create-a-model-with-coordinates,
  pointing into the five User Guide notebooks. The coordinates
  notebook is deliberately a shallow tour, so the handoff is now
  explicit rather than implied by toctree order.
- Rewrite the user-guide.rst opening to acknowledge what the reader
  just did in Getting Started, framing the User Guide as the depth
  pass on the same surface.
- Rename the user-guide.rst H1 from "User Guide" to "Overview" so
  the sidebar entry under the "User Guide" caption no longer
  duplicates the caption name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: fix malformed first cell of solve-on-remote notebook

Cell 0 had two lines that contained literal "\n" sequences as text
(plus a stray trailing double-quote), so the markdown rendered as
one long line and Sphinx emitted four warnings about
"SSH:nbsphinx-math" file-not-found and inline interpreted text.

Rewrite the cell with proper newline-separated lines and turn the
inline reference to solve-on-oetc.ipynb into a :doc: cross-reference.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: use markdown links for cross-refs in notebook markdown cells

:doc: only resolves inside RST contexts (rst files and the body of
RST directives like .. tip::). In plain markdown cells nbsphinx
needs markdown links to the .ipynb files, which it then rewrites to
the rendered .html targets.

- create-a-model-with-coordinates: the new "Where to next" cell now
  uses [text](other.ipynb) for the five User Guide notebooks.
- solve-on-remote: the inline :doc:`solve-on-oetc` introduced in the
  previous fix is now a markdown link too.

Verified the build rewrites all five links to .html targets.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: collapse "Where to next" to a single pointer at the User Guide overview

Listing the five User Guide notebooks at the end of the coordinates
notebook duplicated the bullet list the overview page already
maintains. Single forward pointer keeps the User Guide overview as
the source of truth and pushes the reader through the deliberate
intro on that page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: restructure api.rst — task-oriented top, classes under the hood, advanced bottom

Replace the flat alphabetic per-class dump with a layered structure
that puts the surface 90% of users reach for at the top, the
supporting classes in the middle, and the genuinely rare-use surface
at the bottom.

Task-oriented top sections (Model methods grouped by what the user
is doing):

  Creating a model
  Inspecting a model
  Modifying a model
  Solving
  Post-solve access     (Model post-solve accessors + status enums)
  Diagnostics
  IO
  Top-level helpers     (align, options)

Classes under the hood:

  Variable / Variables / LinearExpression / Constraint /
  Constraints / Objective / Piecewise

Each gets a small thematic split inside (Attributes / Operations /
Conversion / Post-solve / etc.) rather than an alphabetic dump.

Advanced section at the bottom for surface that most users will not
reach for:

  QuadraticExpression
  CSRConstraint
  Bulk variable operations (Variables.fix/unfix/relax/unrelax)
  Auto-reformulation (Model.reformulate_sos_constraints)
  Remote solving (RemoteHandler)
  Warnings (EvolvingAPIWarning, PerformanceWarning)

Curated to drop internal escape hatches and helpers:
- Model.to_gurobipy/to_highspy/to_mosek/to_cupdlpx (power-user
  escape hatches)
- Model.linexpr (arithmetic on Variables is the natural path)
- Constraints.format_labels, .coefficientrange (internal diagnostics)
- LinearExpression.from_rule, .from_constant (niche constructors)
- Constraint.freeze / .mutable, CSRConstraint.freeze / .mutable
  (CSR backend plumbing)
- ScalarVariable, ScalarLinearExpression (internal types)
- solvers.PIPS (stub that raises NotImplementedError)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: add docstrings for properties surfaced in api.rst autosummary tables

The new api.rst structure exposed 14 properties whose autosummary
table cell was blank because they had no docstring. Add a single-line
description to each:

- Model.is_linear / is_quadratic / type
- BaseExpression.vars / coeffs / const (fixes both LinearExpression
  and QuadraticExpression entries)
- Objective.is_linear / is_quadratic
- PiecewiseFormulation.method / convexity (added as inline attribute
  docstrings on the dataclass fields)
- OptionSettings class docstring (so the top-level `options` instance
  picks up a description)

PiecewiseFormulation: also dropped the duplicated literal value lists
from the class-level Attributes block and from the new attribute
docstrings, referencing the PWL_METHOD / PWL_CONVEXITY type aliases
instead so there is a single source of truth for the allowed values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: surface PWL_METHOD / PWL_CONVEXITY type aliases in api.rst

The :data:`PWL_METHOD` and :data:`PWL_CONVEXITY` references added
in the previous commit rendered as plain <code> rather than as
hyperlinks: their docs target didn't exist yet, and the role was
being looked up in the wrong module.

- Add docstrings to PWL_METHOD, PWL_METHODS, PWL_CONVEXITY, and
  PWL_CONVEXITIES in linopy/constants.py.
- List all four in api.rst under the Piecewise subsection so
  autosummary generates dedicated pages.
- Switch the cross-references in PiecewiseFormulation.method /
  .convexity and in constants.py to the fully-qualified form
  (:data:`~linopy.constants.PWL_METHOD`) so they resolve from
  whichever module they're rendered in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: dissolve the api.rst Advanced umbrella; each item gets a natural home

The Advanced section was a subjective bucket. Each entry now sits
where it belongs:

- QuadraticExpression moves into Classes under the hood alongside
  LinearExpression — it's a class with its own surface, not a
  power-user appendix.
- CSRConstraint moves into Classes under the hood next to Constraint —
  alternative storage backend, but a regular documented class.
- Variables.fix / unfix / relax / unrelax return as a Bulk modify
  subgroup under the Variables container.
- Model.reformulate_sos_constraints joins Modifying a model — it
  transforms the model in place.
- Remote solving and Warnings become small top-level sections of
  their own at the end of the page rather than nested under Advanced.

Preamble updated to drop the now-stale "Advanced section at the
bottom" reference and to signal the actual top-level structure
(task-oriented top, supporting classes below).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: keep page TOC depth 2; expand right-side TOC to L2 site-wide

Inline ``.. contents::`` directive on api.rst stays at depth 2 — the
page-top TOC is the executive summary, not a complete map.

For navigation into a section, bump sphinx-book-theme's
``show_toc_level`` to 2 in ``html_theme_options``. The right-side
"On this page" panel now shows H3 entries by default rather than
only expanding the section the user has scrolled into. Applies
site-wide; the other pages have shallow H3 structures so this is
a usability win across the board.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: rename "Classes and types" → "Other classes and types"

Makes the structural role explicit: these are the classes and types
not already covered by the task-oriented top sections.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: standardise H3 subgroup vocabulary across api.rst class sections

Align the subgroup names that appear in multiple class sections so a
reader who learns the scheme once can scan across classes. Six shared
labels emerge — Structure, Construction, Modification, Operations,
Conversion, Post-solve access — used wherever they fit.

- Variable: "Modifying state" → "Modification" (match Variables,
  Constraints).
- LinearExpression: "Building blocks" → "Structure" (match
  Constraint, QuadraticExpression below); "Manipulation" →
  "Operations" (match Variable).
- QuadraticExpression: replace the flat list with the same subgroup
  shape as LinearExpression — Structure, Conversion, Post-solve
  access.
- CSRConstraint: replace the flat list with the same subgroup shape
  as Constraint — Structure, Post-solve access, Conversion.

Also move the solver-status enums out of Post-solve access into
their own subsection (Solver status and result types) under Other
classes and types: SolverStatus / TerminationCondition / Status /
Solution / Result are types you compare Model.status against, not
accessors.

Model keeps its own task vocabulary (Building / Inspecting /
Modifying / Solving / Diagnostics / IO / etc.) because it's
structurally different from the data-type classes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: revert show_toc_level=2 in book-theme options

Roll back to the default (1). The right-side page TOC will only
expand the section the reader has scrolled into, not all H3 entries
across the page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: restructure api.rst as Model-first and tighten the curated surface

Two changes in one pass:

(1) Make api.rst per-class throughout. Drop the artificial split
between task-oriented top sections and "Other classes and types".
Model becomes the first H2 (with its task labels — Building /
Inspecting / Modifying / Solving / Post-solve / Diagnostics / IO —
as H3 subsections), and every supporting class becomes a sibling
H2 of Model. Preamble rewritten to frame the page: Model is the
entry point; supporting classes document the types reached via
``model.<attr>`` accessors.

(2) Tighten the surface further. Drop entries that are internal,
implicit-by-arithmetic, or trivial:

  - Variables.add / .remove, Constraints.add / .remove — internal
    mechanisms used by model.add_*; users never call them.
  - Variable.sanitize, Constraints.sanitize_missings — internal
    cleanup helpers in the solver pipeline.
  - LinearExpression.to_constraint, QuadraticExpression.to_constraint
    — almost always implicit via <=, >=, == on expressions.
  - LinearExpression.to_quadexpr — niche conversion only meaningful
    if you're already deep in quadratic forms.
  - Model.get_problem_file / .get_solution_file — debugging-only
    temp-file accessors.
  - solvers.Solver (abstract base, never instantiated) and
    solvers.quadratic_solvers (trivial list).

With Solver and quadratic_solvers removed, the "Solver interface"
section only contained available_solvers, so collapse it into a
single "Solvers" section with the implementation classes.

Also reordered the H3 subgroups inside each class so the most-used
entries appear first. Post-solve access leads on the expression /
constraint classes (the .solution and .dual readers are typically
what a reader is looking for); Aggregate access + Bulk modify lead
on the Variables container.

Top-level helpers moved to the bottom as "Utilities" (align,
options) — they're stragglers, not entry points.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: move piecewise construction helpers into the Piecewise section

The piecewise construction helpers (breakpoints, segments, Slopes)
were previously listed under Model > Building a model because they
are used alongside Model.add_piecewise_formulation. Move them into
the Piecewise section instead — they live in linopy.piecewise and a
reader looking for "how do I build a piecewise formulation" expects
everything piecewise in one place.

Split the Piecewise section into four small subsections (Construction
helpers / PiecewiseFormulation / Low-level helper / Type aliases) so
the helper functions, the return type, the standalone tangent_lines,
and the PWL_METHOD / PWL_CONVEXITY type aliases all sit under
clearly labelled groups instead of one mixed flat list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: harmonise Variables container labels with Variable; fix preamble cross-refs

- Rename Variables container subgroups so they match Variable's
  vocabulary where the role is the same:
    "Aggregate access" → "Attributes"
    "Bulk modify"      → "Modification"  (the "Bulk" qualifier is
                                          clear from context — the
                                          methods live on the
                                          container)
    "Inventory by type" → "Inventory"    (matches Constraints'
                                          equivalent subsection)
- Drop the redundant prose note "Container-wide analogues of
  Variable.fix, etc." — same reason; clear from context.

Also fix the preamble cross-references. The autosummary entries
register the documented entities under their full module paths
(linopy.model.Model, linopy.variables.Variable, …), so the bare
``:class:`Model``` refs were rendering as plain styled code rather
than hyperlinks. Use the qualified ``~linopy.<module>.<name>`` form
for class refs (display stays "Model" / "Variable" / "Constraint" /
"Objective") and the ``Target <full.path>`` form for methods and
attributes so the link text reads "Model.add_variables" etc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: api reference link

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants