@@ -169,6 +169,11 @@ def rhs(self) -> DataArray:
169169 def dual (self ) -> DataArray :
170170 """Get the dual values DataArray."""
171171
172+ @dual .setter
173+ @abstractmethod
174+ def dual (self , value : DataArray ) -> None :
175+ """Set the dual values DataArray."""
176+
172177 @abstractmethod
173178 def has_variable (self , variable : variables .Variable ) -> bool :
174179 """Check if the constraint references any of the given variable labels."""
@@ -185,6 +190,18 @@ def sanitize_missings(self) -> ConstraintBase:
185190 def sanitize_infinities (self ) -> ConstraintBase :
186191 """Mask out rows with invalid infinite RHS values."""
187192
193+ @abstractmethod
194+ def to_polars (self ) -> pl .DataFrame :
195+ """Convert constraint to a polars DataFrame."""
196+
197+ @abstractmethod
198+ def freeze (self ) -> Constraint :
199+ """Return an immutable Constraint (CSR-backed)."""
200+
201+ @abstractmethod
202+ def mutable (self ) -> MutableConstraint :
203+ """Return a mutable MutableConstraint."""
204+
188205 @abstractmethod
189206 def to_matrix_with_rhs (
190207 self , label_index : VariableLabelIndex
@@ -298,7 +315,8 @@ def mask(self) -> DataArray | None:
298315 (True) and disabled (False).
299316 """
300317 if self .is_assigned :
301- return (self .labels != FILL_VALUE ["labels" ]).astype (bool )
318+ result : DataArray = self .labels != FILL_VALUE ["labels" ] # type: ignore[assignment]
319+ return result .astype (bool )
302320 return None
303321
304322 @property
@@ -391,7 +409,7 @@ def flat(self) -> pd.DataFrame:
391409 """
392410 ds = self .data
393411
394- def mask_func (data : pd . DataFrame ) -> pd .Series :
412+ def mask_func (data : dict ) -> pd .Series :
395413 mask = (data ["vars" ] != - 1 ) & (data ["coeffs" ] != 0 )
396414 if "labels" in data :
397415 mask &= data ["labels" ] != - 1
@@ -593,7 +611,7 @@ def nterm(self) -> int:
593611
594612 @property
595613 def coord_names (self ) -> list [str ]:
596- return [c .name for c in self ._coords ]
614+ return [str ( c .name ) for c in self ._coords ]
597615
598616 @property
599617 def labels (self ) -> DataArray :
@@ -828,8 +846,8 @@ def from_netcdf_ds(cls, ds: Dataset, model: Model, name: str) -> Constraint:
828846 )
829847 rhs = ds ["rhs" ].values
830848 sign = attrs ["sign" ]
831- cindex = int (attrs ["cindex" ])
832- cindex = cindex if cindex >= 0 else None
849+ _cindex_raw = int (attrs ["cindex" ])
850+ cindex : int | None = _cindex_raw if _cindex_raw >= 0 else None
833851 coord_dims = attrs ["coord_dims" ]
834852 if isinstance (coord_dims , str ):
835853 coord_dims = [coord_dims ]
@@ -892,7 +910,7 @@ def mutable(self) -> MutableConstraint:
892910 """Convert to a MutableConstraint."""
893911 return MutableConstraint (self .data , self ._model , self ._name )
894912
895- def to_polars (self ) -> Any :
913+ def to_polars (self ) -> pl . DataFrame :
896914 """Convert to polars DataFrame — delegates to mutable()."""
897915 return self .mutable ().to_polars ()
898916
@@ -1598,6 +1616,8 @@ def set_blocks(self, block_map: np.ndarray) -> None:
15981616 N = block_map .max ()
15991617
16001618 for name , constraint in self .items ():
1619+ if not isinstance (constraint , MutableConstraint ):
1620+ self .data [name ] = constraint = constraint .mutable ()
16011621 res = xr .full_like (constraint .labels , N + 1 , dtype = block_map .dtype )
16021622 entries = replace_by_map (constraint .vars , block_map )
16031623
@@ -1679,9 +1699,12 @@ def reset_dual(self) -> None:
16791699 cindex = c ._cindex ,
16801700 dual = None ,
16811701 )
1682- else :
1702+ elif isinstance ( c , MutableConstraint ) :
16831703 if "dual" in c .data :
16841704 c ._data = c .data .drop_vars ("dual" )
1705+ else :
1706+ msg = f"reset_dual encountered an unknown constraint type: { type (c )} "
1707+ raise NotImplementedError (msg )
16851708
16861709
16871710class AnonymousScalarConstraint :
0 commit comments