Skip to content

Commit ce39e45

Browse files
authored
Merge branch 'master' into feature/variable_and_data_array_operators
2 parents 4db1afe + 3870e50 commit ce39e45

File tree

7 files changed

+34
-23
lines changed

7 files changed

+34
-23
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ doc/api
1616
Highs.log
1717
paper/
1818
monkeytype.sqlite3
19+
.github/copilot-instructions.md
20+
uv.lock
1921

2022
# Environments
2123
.env

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
ci:
2-
autoupdate_schedule: monthly
2+
autoupdate_schedule: quarterly
33

44
repos:
55
- repo: https://github.com/pre-commit/pre-commit-hooks
@@ -9,7 +9,7 @@ repos:
99
- id: trailing-whitespace
1010
- id: check-merge-conflict
1111
- repo: https://github.com/astral-sh/ruff-pre-commit
12-
rev: v0.11.4
12+
rev: v0.11.8
1313
hooks:
1414
- id: ruff
1515
args: [--fix]

doc/release_notes.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Release Notes
22
=============
33

4+
Future Version
5+
---------------
6+
**Minor Improvements**
7+
* Improved variable/expression arithmetic methods so that they correctly handle types
8+
49
Upcoming Version
510
----------------
611

@@ -12,7 +17,8 @@ Upcoming Version
1217
gap tolerance.
1318
* Improve the mapping of termination conditions for the SCIP solver
1419
* Treat GLPK's `integer undefined` status as not-OK
15-
* Fixed variable/expression arithmetic methods so that they correctly handle types
20+
* Internally assign new data fields to `Variable` and `Constraint` with a multiindexed-safe routine. Before the
21+
assignment when using multi-indexed coordinates, an deprecation warning was raised. This is fixed now.
1622

1723
Version 0.5.3
1824
--------------

linopy/constraints.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
from __future__ import annotations
88

99
import functools
10-
from collections.abc import Hashable, ItemsView, Iterator, Sequence
10+
from collections.abc import Callable, Hashable, ItemsView, Iterator, Sequence
1111
from dataclasses import dataclass
1212
from itertools import product
1313
from typing import (
1414
TYPE_CHECKING,
1515
Any,
16-
Callable,
1716
overload,
1817
)
1918

@@ -460,7 +459,7 @@ def sign(self) -> DataArray:
460459
@is_constant
461460
def sign(self, value: SignLike) -> None:
462461
value = maybe_replace_signs(DataArray(value)).broadcast_like(self.sign)
463-
self.data["sign"] = value
462+
self._data = assign_multiindex_safe(self.data, sign=value)
464463

465464
@property
466465
def rhs(self) -> DataArray:
@@ -478,7 +477,7 @@ def rhs(self, value: ExpressionLike) -> None:
478477
value, self.model, coords=self.coords, dims=self.coord_dims
479478
)
480479
self.lhs = self.lhs - value.reset_const()
481-
self.data["rhs"] = value.const
480+
self._data = assign_multiindex_safe(self.data, rhs=value.const)
482481

483482
@property
484483
@has_optimized_model
@@ -1006,7 +1005,7 @@ def set_blocks(self, block_map: np.ndarray) -> None:
10061005

10071006
res = res.where(not_missing.any(constraint.term_dim), -1)
10081007
res = res.where(not_zero.any(constraint.term_dim), 0)
1009-
constraint.data["blocks"] = res
1008+
constraint._data = assign_multiindex_safe(constraint.data, blocks=res)
10101009

10111010
@property
10121011
def flat(self) -> pd.DataFrame:

linopy/expressions.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def sum(self, **kwargs: Any) -> LinearExpression:
311311
.rename({TERM_DIM: STACKED_TERM_DIM})
312312
.stack({TERM_DIM: [STACKED_TERM_DIM, "_rolling_term"]}, create_index=False)
313313
)
314-
ds["const"] = data.const.sum("_rolling_term")
314+
ds = assign_multiindex_safe(ds, const=data.const.sum("_rolling_term"))
315315
return LinearExpression(ds, self.model)
316316

317317

@@ -712,23 +712,23 @@ def vars(self) -> DataArray:
712712

713713
@vars.setter
714714
def vars(self, value: DataArray) -> None:
715-
self.data["vars"] = value
715+
self._data = assign_multiindex_safe(self.data, vars=value)
716716

717717
@property
718718
def coeffs(self) -> DataArray:
719719
return self.data.coeffs
720720

721721
@coeffs.setter
722722
def coeffs(self, value: DataArray) -> None:
723-
self.data["coeffs"] = value
723+
self._data = assign_multiindex_safe(self.data, coeffs=value)
724724

725725
@property
726726
def const(self) -> DataArray:
727727
return self.data.const
728728

729729
@const.setter
730730
def const(self, value: DataArray) -> None:
731-
self.data["const"] = value
731+
self._data = assign_multiindex_safe(self.data, const=value)
732732

733733
@property
734734
def has_constant(self) -> DataArray:
@@ -1182,7 +1182,7 @@ def _sum(
11821182
return ds
11831183

11841184
# Wrapped function which would convert variable to dataarray
1185-
assign = exprwrap(Dataset.assign)
1185+
assign = exprwrap(assign_multiindex_safe)
11861186

11871187
assign_multiindex_safe = exprwrap(assign_multiindex_safe)
11881188

linopy/model.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from linopy import solvers
2828
from linopy.common import (
2929
as_dataarray,
30+
assign_multiindex_safe,
3031
best_int,
3132
maybe_replace_signs,
3233
replace_by_map,
@@ -734,7 +735,9 @@ def remove_variables(self, name: str) -> None:
734735
for k in list(self.constraints):
735736
vars = self.constraints[k].data["vars"]
736737
vars = vars.where(~vars.isin(labels), -1)
737-
self.constraints[k].data["vars"] = vars
738+
self.constraints[k]._data = assign_multiindex_safe(
739+
self.constraints[k].data, vars=vars
740+
)
738741

739742
self.objective = self.objective.sel(
740743
{TERM_DIM: ~self.objective.vars.isin(labels)}

linopy/variables.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88

99
import functools
1010
import logging
11-
from collections.abc import Hashable, ItemsView, Iterator, Mapping
11+
from collections.abc import Callable, Hashable, ItemsView, Iterator, Mapping
1212
from dataclasses import dataclass
1313
from typing import (
1414
TYPE_CHECKING,
1515
Any,
16-
Callable,
1716
overload,
1817
)
1918
from warnings import warn
@@ -804,7 +803,7 @@ def upper(self, value: ConstantLike) -> None:
804803
value = DataArray(value).broadcast_like(self.upper)
805804
if not set(value.dims).issubset(self.model.variables[self.name].dims):
806805
raise ValueError("Cannot assign new dimensions to existing variable.")
807-
self.data["upper"] = value
806+
self._data = assign_multiindex_safe(self.data, upper=value)
808807

809808
@property
810809
def lower(self) -> DataArray:
@@ -828,7 +827,7 @@ def lower(self, value: ConstantLike) -> None:
828827
value = DataArray(value).broadcast_like(self.lower)
829828
if not set(value.dims).issubset(self.model.variables[self.name].dims):
830829
raise ValueError("Cannot assign new dimensions to existing variable.")
831-
self.data["lower"] = value
830+
self._data = assign_multiindex_safe(self.data, lower=value)
832831

833832
@property
834833
@has_optimized_model
@@ -1108,8 +1107,7 @@ def bfill(self, dim: str, limit: None = None) -> Variable:
11081107
.map(DataArray.bfill, dim=dim, limit=limit)
11091108
.fillna(self._fill_value)
11101109
)
1111-
data = data.assign(labels=data.labels.astype(int))
1112-
return self.__class__(data, self.model, self.name)
1110+
return self.assign(labels=data.labels.astype(int))
11131111

11141112
def sanitize(self) -> Variable:
11151113
"""
@@ -1120,8 +1118,7 @@ def sanitize(self) -> Variable:
11201118
linopy.Variable
11211119
"""
11221120
if issubdtype(self.labels.dtype, floating):
1123-
data = self.data.assign(labels=self.labels.fillna(-1).astype(int))
1124-
return self.__class__(data, self.model, self.name)
1121+
return self.assign(labels=self.labels.fillna(-1).astype(int))
11251122
return self
11261123

11271124
def equals(self, other: Variable) -> bool:
@@ -1132,6 +1129,8 @@ def equals(self, other: Variable) -> bool:
11321129

11331130
assign_coords = varwrap(Dataset.assign_coords)
11341131

1132+
assign = varwrap(assign_multiindex_safe)
1133+
11351134
assign_multiindex_safe = varwrap(assign_multiindex_safe)
11361135

11371136
broadcast_like = varwrap(Dataset.broadcast_like)
@@ -1499,7 +1498,9 @@ def set_blocks(self, blocks: DataArray) -> None:
14991498

15001499
for name, variable in self.items():
15011500
if dim in variable.dims:
1502-
variable.data["blocks"] = blocks.broadcast_like(variable.labels)
1501+
variable._data = assign_multiindex_safe(
1502+
variable.data, blocks=blocks.broadcast_like(variable.labels)
1503+
)
15031504

15041505
def get_blockmap(self, dtype: type = np.int8) -> ndarray:
15051506
"""

0 commit comments

Comments
 (0)