Skip to content

model_element

ModelElement(data, **kwargs)

Bases: ABC

Source code in pyoframe/model_element.py
def __init__(self, data: pl.DataFrame, **kwargs) -> None:
    # Sanity checks, no duplicate column names
    assert len(data.columns) == len(
        set(data.columns)
    ), "Duplicate column names found."

    cols = _get_dimensions(data)
    if cols is None:
        cols = []
    cols += [col for col in RESERVED_COL_KEYS if col in data.columns]

    # Reorder columns to keep things consistent
    data = data.select(cols)

    # Cast to proper dtype
    if COEF_KEY in data.columns:
        data = data.cast({COEF_KEY: pl.Float64})
    if VAR_KEY in data.columns:
        data = data.cast({VAR_KEY: KEY_TYPE})
    if QUAD_VAR_KEY in data.columns:
        data = data.cast({QUAD_VAR_KEY: KEY_TYPE})

    self._data = data
    self._model: Optional[Model] = None
    self.name = None
    super().__init__(**kwargs)

dimensions property

The names of the data's dimensions.

Examples:

>>> # A variable with no dimensions
>>> pf.Variable().dimensions
>>> # A variable with dimensions of "hour" and "city"
>>> pf.Variable([{"hour": ["00:00", "06:00", "12:00", "18:00"]}, {"city": ["Toronto", "Berlin", "Paris"]}]).dimensions
['hour', 'city']

dimensions_unsafe property

Same as dimensions but returns an empty list if there are no dimensions instead of None. When unsure, use dimensions instead since the type checker forces users to handle the None case (no dimensions).

shape property

The number of indices in each dimension.

Examples:

>>> # A variable with no dimensions
>>> pf.Variable().shape
{}
>>> # A variable with dimensions of "hour" and "city"
>>> pf.Variable([{"hour": ["00:00", "06:00", "12:00", "18:00"]}, {"city": ["Toronto", "Berlin", "Paris"]}]).shape
{'hour': 4, 'city': 3}

ModelElementWithId(data, **kwargs)

Bases: ModelElement

Provides a method that assigns a unique ID to each row in a DataFrame. IDs start at 1 and go up consecutively. No zero ID is assigned since it is reserved for the constant variable term. IDs are only unique for the subclass since different subclasses have different counters.

Source code in pyoframe/model_element.py
def __init__(self, data: pl.DataFrame, **kwargs) -> None:
    # Sanity checks, no duplicate column names
    assert len(data.columns) == len(
        set(data.columns)
    ), "Duplicate column names found."

    cols = _get_dimensions(data)
    if cols is None:
        cols = []
    cols += [col for col in RESERVED_COL_KEYS if col in data.columns]

    # Reorder columns to keep things consistent
    data = data.select(cols)

    # Cast to proper dtype
    if COEF_KEY in data.columns:
        data = data.cast({COEF_KEY: pl.Float64})
    if VAR_KEY in data.columns:
        data = data.cast({VAR_KEY: KEY_TYPE})
    if QUAD_VAR_KEY in data.columns:
        data = data.cast({QUAD_VAR_KEY: KEY_TYPE})

    self._data = data
    self._model: Optional[Model] = None
    self.name = None
    super().__init__(**kwargs)

get_id_column_name() abstractmethod classmethod

Returns the name of the column containing the IDs.

Source code in pyoframe/model_element.py
@classmethod
@abstractmethod
def get_id_column_name(cls) -> str:
    """
    Returns the name of the column containing the IDs.
    """

SupportPolarsMethodMixin

Bases: ABC

_new(data) abstractmethod

Used to create a new instance of the same class with the given data (for e.g. on .rename(), .with_columns(), etc.).

Source code in pyoframe/model_element.py
@abstractmethod
def _new(self, data: pl.DataFrame):
    """
    Used to create a new instance of the same class with the given data (for e.g. on .rename(), .with_columns(), etc.).
    """

pick(**kwargs)

Filters elements by the given criteria and then drops the filtered dimensions.

Examples:

>>> m = pf.Model()
>>> m.v = pf.Variable([{"hour": ["00:00", "06:00", "12:00", "18:00"]}, {"city": ["Toronto", "Berlin", "Paris"]}])
>>> m.v.pick(hour="06:00")
<Expression size=3 dimensions={'city': 3} terms=3>
[Toronto]: v[06:00,Toronto]
[Berlin]: v[06:00,Berlin]
[Paris]: v[06:00,Paris]
>>> m.v.pick(hour="06:00", city="Toronto")
<Expression size=1 dimensions={} terms=1>
v[06:00,Toronto]
Source code in pyoframe/model_element.py
def pick(self, **kwargs):
    """
    Filters elements by the given criteria and then drops the filtered dimensions.

    Examples:
        >>> m = pf.Model()
        >>> m.v = pf.Variable([{"hour": ["00:00", "06:00", "12:00", "18:00"]}, {"city": ["Toronto", "Berlin", "Paris"]}])
        >>> m.v.pick(hour="06:00")
        <Expression size=3 dimensions={'city': 3} terms=3>
        [Toronto]: v[06:00,Toronto]
        [Berlin]: v[06:00,Berlin]
        [Paris]: v[06:00,Paris]
        >>> m.v.pick(hour="06:00", city="Toronto")
        <Expression size=1 dimensions={} terms=1>
        v[06:00,Toronto]
    """
    return self._new(self.data.filter(**kwargs).drop(kwargs.keys()))

_support_polars_method(method_name)

Wrapper to add a method to ModelElement that simply calls the underlying Polars method on the data attribute.

Source code in pyoframe/model_element.py
def _support_polars_method(method_name: str):
    """
    Wrapper to add a method to ModelElement that simply calls the underlying Polars method on the data attribute.
    """

    def method(self: "SupportPolarsMethodMixin", *args, **kwargs) -> Any:
        result_from_polars = getattr(self.data, method_name)(*args, **kwargs)
        if isinstance(result_from_polars, pl.DataFrame):
            return self._new(result_from_polars)
        else:
            return result_from_polars

    return method