Skip to content

Commit c05e428

Browse files
committed
Improve performance
1 parent 75ef055 commit c05e428

File tree

5 files changed

+37
-17
lines changed

5 files changed

+37
-17
lines changed

benchmarks/src/facility_location/bm_pyoframe.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,4 @@ def build(self):
5959

6060

6161
if __name__ == "__main__":
62-
Bench("gurobi", 5).run()
62+
Bench("gurobi", 100).run()

benchmarks/src/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ def __init__(self, *args, use_var_names=False, **kwargs):
4242
import pyoframe as pf
4343

4444
pf.Config.print_uses_variable_names = False
45+
pf.Config.maintain_order = False
46+
pf.Config.disable_unmatched_checks = True
4547

4648
def solve(self, model):
4749
if self.block_solver:

src/pyoframe/_arithmetic.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ def _add_expressions_core(*expressions: "Expression") -> "Expression":
235235
left, right = right, left
236236

237237
def get_indices(expr):
238-
return expr.data.select(dims).unique(maintain_order=True)
238+
return expr.data.select(dims).unique(maintain_order=Config.maintain_order)
239239

240240
left_data, right_data = left.data, right.data
241241

@@ -343,7 +343,9 @@ def _add_dimension(self: "Expression", target: "Expression") -> "Expression":
343343
f"Dataframe has missing dimensions {missing_dims}. If this is intentional, use .add_dim()\n{self.data}"
344344
)
345345

346-
target_data = target.data.select(target_dims).unique(maintain_order=True)
346+
target_data = target.data.select(target_dims).unique(
347+
maintain_order=Config.maintain_order
348+
)
347349

348350
if not dims_in_common:
349351
return self._new(self.data.join(target_data, how="cross"))
@@ -365,7 +367,7 @@ def _sum_like_terms(df: pl.DataFrame) -> pl.DataFrame:
365367
"""Combines terms with the same variables."""
366368
dims = [c for c in df.columns if c not in RESERVED_COL_KEYS]
367369
var_cols = [VAR_KEY] + ([QUAD_VAR_KEY] if QUAD_VAR_KEY in df.columns else [])
368-
df = df.group_by(dims + var_cols, maintain_order=True).sum()
370+
df = df.group_by(dims + var_cols, maintain_order=Config.maintain_order).sum()
369371
return df
370372

371373

@@ -426,7 +428,7 @@ def _simplify_expr_df(df: pl.DataFrame) -> pl.DataFrame:
426428
if len(df_filtered) < len(df):
427429
dims = [c for c in df.columns if c not in RESERVED_COL_KEYS]
428430
if dims:
429-
dim_values = df.select(dims).unique(maintain_order=True)
431+
dim_values = df.select(dims).unique(maintain_order=Config.maintain_order)
430432
df = (
431433
dim_values.join(df_filtered, on=dims, how="left")
432434
.with_columns(pl.col(COEF_KEY).fill_null(0))

src/pyoframe/constants.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ class Config(metaclass=_ConfigMeta):
115115
unexpected errors. Setting the tolerance to zero disables the check.
116116
"""
117117

118+
maintain_order: bool = True
119+
"""
120+
If True, performance and memory usage may worsen, but the order of terms within expressions will not change across runs.
121+
"""
122+
118123
@classmethod
119124
def reset_defaults(cls):
120125
"""

src/pyoframe/core.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,9 @@ def __add__(self, other):
317317
if isinstance(other, Set):
318318
try:
319319
return self._new(
320-
pl.concat([self.data, other.data]).unique(maintain_order=True)
320+
pl.concat([self.data, other.data]).unique(
321+
maintain_order=Config.maintain_order
322+
)
321323
)
322324
except pl.exceptions.ShapeError as e:
323325
if "unable to vstack, column names don't match" in str(e):
@@ -347,7 +349,7 @@ def _set_to_polars(set: "SetTypes") -> pl.DataFrame:
347349
df = (
348350
set.to_expr()
349351
.data.drop(RESERVED_COL_KEYS, strict=False)
350-
.unique(maintain_order=True)
352+
.unique(maintain_order=Config.maintain_order)
351353
)
352354
elif isinstance(set, pd.Index):
353355
df = pl.from_pandas(pd.DataFrame(index=set).reset_index())
@@ -481,7 +483,10 @@ def sum(self, over: Union[str, Iterable[str]]):
481483

482484
return self._new(
483485
self.data.drop(over)
484-
.group_by(remaining_dims + self._variable_columns, maintain_order=True)
486+
.group_by(
487+
remaining_dims + self._variable_columns,
488+
maintain_order=Config.maintain_order,
489+
)
485490
.sum()
486491
)
487492

@@ -650,7 +655,7 @@ def within(self, set: "SetTypes") -> Expression:
650655
"Cannot use .within() with an expression with no dimensions."
651656
)
652657
dims_in_common = [dim for dim in dims if dim in set_dims]
653-
by_dims = df.select(dims_in_common).unique(maintain_order=True)
658+
by_dims = df.select(dims_in_common).unique(maintain_order=Config.maintain_order)
654659
return self._new(self.data.join(by_dims, on=dims_in_common))
655660

656661
@property
@@ -815,7 +820,7 @@ def _add_const(self, const: int | float) -> Expression:
815820
else:
816821
keys = (
817822
data.select(dim)
818-
.unique(maintain_order=True)
823+
.unique(maintain_order=Config.maintain_order)
819824
.with_columns(pl.lit(CONST_TERM).alias(VAR_KEY).cast(KEY_TYPE))
820825
)
821826
if self.is_quadratic:
@@ -841,7 +846,9 @@ def constant_terms(self):
841846
if self.is_quadratic:
842847
constant_terms = constant_terms.drop(QUAD_VAR_KEY)
843848
if dims is not None:
844-
dims_df = self.data.select(dims).unique(maintain_order=True)
849+
dims_df = self.data.select(dims).unique(
850+
maintain_order=Config.maintain_order
851+
)
845852
df = constant_terms.join(dims_df, on=dims, how="full", coalesce=True)
846853
return df.with_columns(pl.col(COEF_KEY).fill_null(0.0))
847854
else:
@@ -909,7 +916,7 @@ def evaluate(self) -> pl.DataFrame:
909916

910917
dims = self.dimensions
911918
if dims is not None:
912-
df = df.group_by(dims, maintain_order=True)
919+
df = df.group_by(dims, maintain_order=Config.maintain_order)
913920
return df.sum()
914921

915922
def to_poi(self) -> poi.ScalarAffineFunction | poi.ScalarQuadraticFunction:
@@ -970,7 +977,7 @@ def to_str_table(self, include_const_term=True):
970977
).drop(COEF_KEY, VAR_KEY)
971978

972979
if dimensions is not None:
973-
data = data.group_by(dimensions, maintain_order=True).agg(
980+
data = data.group_by(dimensions, maintain_order=Config.maintain_order).agg(
974981
pl.col("expr").str.join(delimiter=" ")
975982
)
976983
else:
@@ -1311,9 +1318,9 @@ def _assign_ids(self):
13111318
.cast(KEY_TYPE)
13121319
)
13131320
else:
1314-
df = self.lhs.data.group_by(self.dimensions, maintain_order=True).agg(
1315-
*key_cols_polars
1316-
)
1321+
df = self.lhs.data.group_by(
1322+
self.dimensions, maintain_order=Config.maintain_order
1323+
).agg(*key_cols_polars)
13171324
if use_var_names:
13181325
df = (
13191326
concat_dimensions(df, prefix=self.name)
@@ -1896,7 +1903,11 @@ def next(self, dim: str, wrap_around: bool = False) -> Expression:
18961903
[18:00,Toronto]: bat_charge[18:00,Toronto] + bat_flow[18:00,Toronto] - bat_charge[00:00,Toronto] = 0
18971904
"""
18981905

1899-
wrapped = self.data.select(dim).unique(maintain_order=True).sort(by=dim)
1906+
wrapped = (
1907+
self.data.select(dim)
1908+
.unique(maintain_order=Config.maintain_order)
1909+
.sort(by=dim)
1910+
)
19001911
wrapped = wrapped.with_columns(pl.col(dim).shift(-1).alias("__next"))
19011912
if wrap_around:
19021913
wrapped = wrapped.with_columns(pl.col("__next").fill_null(pl.first(dim)))

0 commit comments

Comments
 (0)