Skip to content
Open
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
1 change: 1 addition & 0 deletions doc/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Upcoming Version
* A frozen constraint caches the label-to-position mapping of its matrix columns by weak reference and only rebuilds it when the constraint or the set of variables changes. While a persistent snapshot holds the arrays, repeated matrix assembly on an unchanged model returns the same objects, so the snapshot diff can again skip the comparison of untouched frozen constraints by object identity; one-off exports such as ``to_file`` retain no extra memory. (`#933 <https://github.com/PyPSA/linopy/issues/933>`__)
* ``Model.copy`` (and the ``copy.copy``/``copy.deepcopy`` protocols) keeps frozen constraints as ``CSRConstraint`` instead of rebuilding them as dense ``Constraint``; ``deep=True`` copies their arrays, and duals are copied only with ``include_solution=True``. A CSR-backed objective is now deep-copied with ``deep=True`` as well. The auxiliary coordinates of a CSR grid are stored read-only, so a copy can share them safely. (`#981 <https://github.com/PyPSA/linopy/issues/981>`__)
* ``Solver.close()`` no longer leaves dangling native handles behind. The solver model is now dropped before the environment that owns it, instead of after. And the COPT and MindOpt file interfaces no longer hand back a model they already disposed: after a file-based COPT or MindOpt solve, ``model.solver_model`` is ``None`` rather than a handle into freed memory. (`#899 <https://github.com/PyPSA/linopy/pull/899>`__)
* The repr of an expression with more terms than ``linopy.options["display_max_terms"]`` now shows the last terms of a ``QuadraticExpression`` after the ``...`` instead of repeating the first ones, and prints the constant once at the end instead of also before the ``...``. (`#1023 <https://github.com/PyPSA/linopy/pull/1023>`__)

**Breaking Changes**

Expand Down
5 changes: 3 additions & 2 deletions linopy/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1158,12 +1158,13 @@ def format_line(
truncate = max_terms // 2
positions = model.variables.get_label_position(v[..., :truncate])
expr = list(zip(c[:truncate], positions))
res = format_line(expr, const)
# the constant is printed once, after the last terms
res = format_line(expr, np.nan)
res += " ... "
expr = list(
zip(
c[-truncate:],
model.variables.get_label_position(v[-truncate:]),
model.variables.get_label_position(v[..., -truncate:]),
)
)
residual = format_line(expr, const)
Expand Down
15 changes: 15 additions & 0 deletions test/test_repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,21 @@ def test_print_options(obj: Variable | LinearExpression | Constraint) -> None:
obj.print(display_max_rows=20)


def test_truncated_expression_repr_prints_constant_once() -> None:
expr = (np.arange(1, 11) * x).sum() + 5
assert repr(expr).splitlines()[-1] == (
"+1 x[0] + 2 x[1] + 3 x[2] ... +8 x[7] + 9 x[8] + 10 x[9] + 5"
)


def test_truncated_quadratic_expression_repr_shows_last_terms() -> None:
expr = (np.arange(1, 11) * x * a).sum()
assert repr(expr).splitlines()[-1] == (
"+1 x[0] a[0] + 2 x[1] a[1] + 3 x[2] a[2] ... "
"+8 x[7] a[7] + 9 x[8] a[8] + 10 x[9] a[9]"
)


def test_format_labels() -> None:
assert m.variables.format_labels([1, 2, 3])
assert m.constraints.format_labels([1, 2, 3])
Expand Down
Loading