Skip to content

Commit 3870e50

Browse files
fix: use multiindex safe assignment (#456)
1 parent 4ccd002 commit 3870e50

File tree

6 files changed

+28
-20
lines changed

6 files changed

+28
-20
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

doc/release_notes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ Upcoming Version
1212
gap tolerance.
1313
* Improve the mapping of termination conditions for the SCIP solver
1414
* Treat GLPK's `integer undefined` status as not-OK
15+
* Internally assign new data fields to `Variable` and `Constraint` with a multiindexed-safe routine. Before the
16+
assignment when using multi-indexed coordinates, an deprecation warning was raised. This is fixed now.
17+
1518

1619
Version 0.5.3
1720
--------------

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
@@ -313,7 +313,7 @@ def sum(self, **kwargs: Any) -> LinearExpression:
313313
.rename({TERM_DIM: STACKED_TERM_DIM})
314314
.stack({TERM_DIM: [STACKED_TERM_DIM, "_rolling_term"]}, create_index=False)
315315
)
316-
ds["const"] = data.const.sum("_rolling_term")
316+
ds = assign_multiindex_safe(ds, const=data.const.sum("_rolling_term"))
317317
return LinearExpression(ds, self.model)
318318

319319

@@ -783,23 +783,23 @@ def vars(self) -> DataArray:
783783

784784
@vars.setter
785785
def vars(self, value: DataArray) -> None:
786-
self.data["vars"] = value
786+
self._data = assign_multiindex_safe(self.data, vars=value)
787787

788788
@property
789789
def coeffs(self) -> DataArray:
790790
return self.data.coeffs
791791

792792
@coeffs.setter
793793
def coeffs(self, value: DataArray) -> None:
794-
self.data["coeffs"] = value
794+
self._data = assign_multiindex_safe(self.data, coeffs=value)
795795

796796
@property
797797
def const(self) -> DataArray:
798798
return self.data.const
799799

800800
@const.setter
801801
def const(self, value: DataArray) -> None:
802-
self.data["const"] = value
802+
self._data = assign_multiindex_safe(self.data, const=value)
803803

804804
@property
805805
def has_constant(self) -> DataArray:
@@ -1458,7 +1458,7 @@ def to_polars(self) -> pl.DataFrame:
14581458
return df
14591459

14601460
# Wrapped function which would convert variable to dataarray
1461-
assign = exprwrap(Dataset.assign)
1461+
assign = exprwrap(assign_multiindex_safe)
14621462

14631463
assign_multiindex_safe = exprwrap(assign_multiindex_safe)
14641464

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
@@ -755,7 +754,7 @@ def upper(self, value: ConstantLike) -> None:
755754
value = DataArray(value).broadcast_like(self.upper)
756755
if not set(value.dims).issubset(self.model.variables[self.name].dims):
757756
raise ValueError("Cannot assign new dimensions to existing variable.")
758-
self.data["upper"] = value
757+
self._data = assign_multiindex_safe(self.data, upper=value)
759758

760759
@property
761760
def lower(self) -> DataArray:
@@ -779,7 +778,7 @@ def lower(self, value: ConstantLike) -> None:
779778
value = DataArray(value).broadcast_like(self.lower)
780779
if not set(value.dims).issubset(self.model.variables[self.name].dims):
781780
raise ValueError("Cannot assign new dimensions to existing variable.")
782-
self.data["lower"] = value
781+
self._data = assign_multiindex_safe(self.data, lower=value)
783782

784783
@property
785784
@has_optimized_model
@@ -1059,8 +1058,7 @@ def bfill(self, dim: str, limit: None = None) -> Variable:
10591058
.map(DataArray.bfill, dim=dim, limit=limit)
10601059
.fillna(self._fill_value)
10611060
)
1062-
data = data.assign(labels=data.labels.astype(int))
1063-
return self.__class__(data, self.model, self.name)
1061+
return self.assign(labels=data.labels.astype(int))
10641062

10651063
def sanitize(self) -> Variable:
10661064
"""
@@ -1071,8 +1069,7 @@ def sanitize(self) -> Variable:
10711069
linopy.Variable
10721070
"""
10731071
if issubdtype(self.labels.dtype, floating):
1074-
data = self.data.assign(labels=self.labels.fillna(-1).astype(int))
1075-
return self.__class__(data, self.model, self.name)
1072+
return self.assign(labels=self.labels.fillna(-1).astype(int))
10761073
return self
10771074

10781075
def equals(self, other: Variable) -> bool:
@@ -1083,6 +1080,8 @@ def equals(self, other: Variable) -> bool:
10831080

10841081
assign_coords = varwrap(Dataset.assign_coords)
10851082

1083+
assign = varwrap(assign_multiindex_safe)
1084+
10861085
assign_multiindex_safe = varwrap(assign_multiindex_safe)
10871086

10881087
broadcast_like = varwrap(Dataset.broadcast_like)
@@ -1450,7 +1449,9 @@ def set_blocks(self, blocks: DataArray) -> None:
14501449

14511450
for name, variable in self.items():
14521451
if dim in variable.dims:
1453-
variable.data["blocks"] = blocks.broadcast_like(variable.labels)
1452+
variable._data = assign_multiindex_safe(
1453+
variable.data, blocks=blocks.broadcast_like(variable.labels)
1454+
)
14541455

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

0 commit comments

Comments
 (0)