Skip to content

Commit df750a4

Browse files
committed
feat: allow multiplication by constant to introduce new dimensions
Fixes #411
1 parent 9b80b32 commit df750a4

File tree

2 files changed

+11
-10
lines changed

2 files changed

+11
-10
lines changed

doc/release_notes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Upcoming Version
55
----------------
66

77
* The internal handling of `Solution` objects was improved for more consistency. Solution objects created from solver calls now preserve the exact index names from the input file.
8+
* Multiplication of a linear expression by a constant value may now introduce new dimensions.
89

910
Version 0.4.4
1011
--------------

linopy/expressions.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -448,9 +448,9 @@ def __repr__(self) -> str:
448448
expr = print_single_expression(
449449
self.coeffs, self.vars, self.const, self.model
450450
)
451-
lines.append(f"{header_string}\n{'-'*len(header_string)}\n{expr}")
451+
lines.append(f"{header_string}\n{'-' * len(header_string)}\n{expr}")
452452
else:
453-
lines.append(f"{header_string}\n{'-'*len(header_string)}\n<empty>")
453+
lines.append(f"{header_string}\n{'-' * len(header_string)}\n<empty>")
454454

455455
return "\n".join(lines)
456456

@@ -555,7 +555,7 @@ def _multiply_by_linear_expression(
555555
def _multiply_by_constant(self, other: int | float | DataArray) -> LinearExpression:
556556
multiplier = as_dataarray(other, coords=self.coords, dims=self.coord_dims)
557557
coeffs = self.coeffs * multiplier
558-
assert set(coeffs.shape) == set(self.coeffs.shape)
558+
assert all(coeffs.sizes[d] == s for d, s in self.coeffs.sizes.items())
559559
const = self.const * multiplier
560560
return self.assign(coeffs=coeffs, const=const)
561561

@@ -1875,7 +1875,7 @@ def __add__(
18751875
return ScalarLinearExpression(coeffs, vars, self.model)
18761876
elif not isinstance(other, ScalarLinearExpression):
18771877
raise TypeError(
1878-
"unsupported operand type(s) for +: " f"{type(self)} and {type(other)}"
1878+
f"unsupported operand type(s) for +: {type(self)} and {type(other)}"
18791879
)
18801880

18811881
coeffs = self.coeffs + other.coeffs
@@ -1901,7 +1901,7 @@ def __sub__(
19011901
other = other.to_scalar_linexpr(1)
19021902
elif not isinstance(other, ScalarLinearExpression):
19031903
raise TypeError(
1904-
"unsupported operand type(s) for -: " f"{type(self)} and {type(other)}"
1904+
f"unsupported operand type(s) for -: {type(self)} and {type(other)}"
19051905
)
19061906

19071907
return ScalarLinearExpression(
@@ -1918,7 +1918,7 @@ def __neg__(self) -> ScalarLinearExpression:
19181918
def __mul__(self, other: float | int) -> ScalarLinearExpression:
19191919
if not isinstance(other, (int, float, np.number)):
19201920
raise TypeError(
1921-
"unsupported operand type(s) for *: " f"{type(self)} and {type(other)}"
1921+
f"unsupported operand type(s) for *: {type(self)} and {type(other)}"
19221922
)
19231923

19241924
return ScalarLinearExpression(
@@ -1931,7 +1931,7 @@ def __rmul__(self, other: int) -> ScalarLinearExpression:
19311931
def __div__(self, other: float | int) -> ScalarLinearExpression:
19321932
if not isinstance(other, (int, float, np.number)):
19331933
raise TypeError(
1934-
"unsupported operand type(s) for /: " f"{type(self)} and {type(other)}"
1934+
f"unsupported operand type(s) for /: {type(self)} and {type(other)}"
19351935
)
19361936
return self.__mul__(1 / other)
19371937

@@ -1941,23 +1941,23 @@ def __truediv__(self, other: float | int) -> ScalarLinearExpression:
19411941
def __le__(self, other: int | float) -> AnonymousScalarConstraint:
19421942
if not isinstance(other, (int, float, np.number)):
19431943
raise TypeError(
1944-
"unsupported operand type(s) for <=: " f"{type(self)} and {type(other)}"
1944+
f"unsupported operand type(s) for <=: {type(self)} and {type(other)}"
19451945
)
19461946

19471947
return constraints.AnonymousScalarConstraint(self, LESS_EQUAL, other)
19481948

19491949
def __ge__(self, other: int | float) -> AnonymousScalarConstraint:
19501950
if not isinstance(other, (int, float, np.number)):
19511951
raise TypeError(
1952-
"unsupported operand type(s) for >=: " f"{type(self)} and {type(other)}"
1952+
f"unsupported operand type(s) for >=: {type(self)} and {type(other)}"
19531953
)
19541954

19551955
return constraints.AnonymousScalarConstraint(self, GREATER_EQUAL, other)
19561956

19571957
def __eq__(self, other: int | float) -> AnonymousScalarConstraint: # type: ignore
19581958
if not isinstance(other, (int, float, np.number)):
19591959
raise TypeError(
1960-
"unsupported operand type(s) for ==: " f"{type(self)} and {type(other)}"
1960+
f"unsupported operand type(s) for ==: {type(self)} and {type(other)}"
19611961
)
19621962

19631963
return constraints.AnonymousScalarConstraint(self, EQUAL, other)

0 commit comments

Comments
 (0)