Issue Description
Structural operations — .shift(), .where(), mask= — leave absent slots: coordinates where the variable does not exist. linopy does not mark these as absent once the variable enters an expression, so after multiplication an absent slot is indistinguishable from a genuine zero-valued term, and fillna() cannot reach it.
Reproducible Example
import pandas as pd
import linopy
m = linopy.Model()
x = m.add_variables(coords=[pd.RangeIndex(5, name="time")])
xs = x.shift(time=1) # time=0 is now absent
print((xs * 3).isnull().values[0]) # False — the absent slot looks present
After xs * 3 the slot at time=0 reports isnull() == False — a present, 0-valued term — so it cannot be told apart from a real zero term.
Expected Behavior
An absent slot should stay absent through multiplication (isnull() == True), so absent and zero remain distinguishable.
Confirmed on linopy 0.7.0. Part of the arithmetic-convention work (#591).
Issue Description
Structural operations —
.shift(),.where(),mask=— leave absent slots: coordinates where the variable does not exist. linopy does not mark these as absent once the variable enters an expression, so after multiplication an absent slot is indistinguishable from a genuine zero-valued term, andfillna()cannot reach it.Reproducible Example
After
xs * 3the slot attime=0reportsisnull() == False— a present, 0-valued term — so it cannot be told apart from a real zero term.Expected Behavior
An absent slot should stay absent through multiplication (
isnull() == True), so absent and zero remain distinguishable.Confirmed on linopy 0.7.0. Part of the arithmetic-convention work (#591).