pyoframe 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyoframe/constants.py +3 -3
- pyoframe/model.py +66 -1
- pyoframe/util.py +19 -0
- {pyoframe-0.1.0.dist-info → pyoframe-0.1.2.dist-info}/METADATA +3 -3
- pyoframe-0.1.2.dist-info/RECORD +14 -0
- {pyoframe-0.1.0.dist-info → pyoframe-0.1.2.dist-info}/WHEEL +1 -1
- pyoframe-0.1.0.dist-info/RECORD +0 -14
- {pyoframe-0.1.0.dist-info → pyoframe-0.1.2.dist-info}/LICENSE +0 -0
- {pyoframe-0.1.0.dist-info → pyoframe-0.1.2.dist-info}/top_level.txt +0 -0
pyoframe/constants.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
File containing shared constants used across the package.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import importlib.metadata
|
|
6
5
|
import typing
|
|
7
6
|
from enum import Enum
|
|
8
7
|
from typing import Literal, Optional
|
|
@@ -11,8 +10,9 @@ import polars as pl
|
|
|
11
10
|
import pyoptinterface as poi
|
|
12
11
|
from packaging import version
|
|
13
12
|
|
|
14
|
-
#
|
|
15
|
-
|
|
13
|
+
# Constant to help split our logic depending on the polars version in use.
|
|
14
|
+
# This approach is compatible with polars-lts-cpu.
|
|
15
|
+
POLARS_VERSION = version.parse(pl.__version__)
|
|
16
16
|
|
|
17
17
|
COEF_KEY = "__coeff"
|
|
18
18
|
VAR_KEY = "__variable_id"
|
pyoframe/model.py
CHANGED
|
@@ -17,7 +17,7 @@ from pyoframe.constants import (
|
|
|
17
17
|
from pyoframe.core import Constraint, Variable
|
|
18
18
|
from pyoframe.model_element import ModelElement, ModelElementWithId
|
|
19
19
|
from pyoframe.objective import Objective
|
|
20
|
-
from pyoframe.util import Container, NamedVariableMapper, get_obj_repr
|
|
20
|
+
from pyoframe.util import Container, NamedVariableMapper, for_solvers, get_obj_repr
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class Model:
|
|
@@ -264,6 +264,71 @@ class Model:
|
|
|
264
264
|
def optimize(self):
|
|
265
265
|
self.poi.optimize()
|
|
266
266
|
|
|
267
|
+
@for_solvers("gurobi")
|
|
268
|
+
def convert_to_fixed(self) -> None:
|
|
269
|
+
"""
|
|
270
|
+
Turns a mixed integer program into a continuous one by fixing
|
|
271
|
+
all the integer and binary variables to their solution values.
|
|
272
|
+
|
|
273
|
+
!!! warning "Gurobi only"
|
|
274
|
+
This method only works with the Gurobi solver. Open an issue if you'd like to see support for other solvers.
|
|
275
|
+
|
|
276
|
+
Example:
|
|
277
|
+
>>> m = pf.Model(solver="gurobi")
|
|
278
|
+
>>> m.X = pf.Variable(vtype=pf.VType.BINARY, lb=0)
|
|
279
|
+
>>> m.Y = pf.Variable(vtype=pf.VType.INTEGER, lb=0)
|
|
280
|
+
>>> m.Z = pf.Variable(lb=0)
|
|
281
|
+
>>> m.my_constraint = m.X + m.Y + m.Z <= 10
|
|
282
|
+
>>> m.maximize = 3 * m.X + 2 * m.Y + m.Z
|
|
283
|
+
>>> m.optimize()
|
|
284
|
+
>>> m.X.solution, m.Y.solution, m.Z.solution
|
|
285
|
+
(1.0, 9.0, 0.0)
|
|
286
|
+
>>> m.my_constraint.dual
|
|
287
|
+
Traceback (most recent call last):
|
|
288
|
+
...
|
|
289
|
+
polars.exceptions.ComputeError: RuntimeError: Unable to retrieve attribute 'Pi'
|
|
290
|
+
>>> m.convert_to_fixed()
|
|
291
|
+
>>> m.optimize()
|
|
292
|
+
>>> m.my_constraint.dual
|
|
293
|
+
1.0
|
|
294
|
+
|
|
295
|
+
Only works for Gurobi:
|
|
296
|
+
|
|
297
|
+
>>> m = pf.Model("max", solver="highs")
|
|
298
|
+
>>> m.convert_to_fixed()
|
|
299
|
+
Traceback (most recent call last):
|
|
300
|
+
...
|
|
301
|
+
NotImplementedError: Method 'convert_to_fixed' is not implemented for solver 'highs'.
|
|
302
|
+
"""
|
|
303
|
+
self.poi._converttofixed()
|
|
304
|
+
|
|
305
|
+
@for_solvers("gurobi", "copt")
|
|
306
|
+
def compute_IIS(self):
|
|
307
|
+
"""
|
|
308
|
+
Computes the Irreducible Infeasible Set (IIS) of the model.
|
|
309
|
+
|
|
310
|
+
!!! warning "Gurobi only"
|
|
311
|
+
This method only works with the Gurobi solver. Open an issue if you'd like to see support for other solvers.
|
|
312
|
+
|
|
313
|
+
Example:
|
|
314
|
+
>>> m = pf.Model(solver="gurobi")
|
|
315
|
+
>>> m.X = pf.Variable(lb=0, ub=2)
|
|
316
|
+
>>> m.Y = pf.Variable(lb=0, ub=2)
|
|
317
|
+
>>> m.bad_constraint = m.X >= 3
|
|
318
|
+
>>> m.minimize = m.X + m.Y
|
|
319
|
+
>>> m.optimize()
|
|
320
|
+
>>> m.attr.TerminationStatus
|
|
321
|
+
<TerminationStatusCode.INFEASIBLE: 3>
|
|
322
|
+
>>> m.bad_constraint.attr.IIS
|
|
323
|
+
Traceback (most recent call last):
|
|
324
|
+
...
|
|
325
|
+
polars.exceptions.ComputeError: RuntimeError: Unable to retrieve attribute 'IISConstr'
|
|
326
|
+
>>> m.compute_IIS()
|
|
327
|
+
>>> m.bad_constraint.attr.IIS
|
|
328
|
+
True
|
|
329
|
+
"""
|
|
330
|
+
self.poi.computeIIS()
|
|
331
|
+
|
|
267
332
|
def _set_param(self, name, value):
|
|
268
333
|
self.poi.set_raw_parameter(name, value)
|
|
269
334
|
|
pyoframe/util.py
CHANGED
|
@@ -389,3 +389,22 @@ class NamedVariableMapper:
|
|
|
389
389
|
prefix=element_name,
|
|
390
390
|
to_col=self.NAME_COL,
|
|
391
391
|
)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def for_solvers(*solvers: str):
|
|
395
|
+
"""
|
|
396
|
+
Decorator that limits the function to only be called when the solver is in the `only` list.
|
|
397
|
+
"""
|
|
398
|
+
|
|
399
|
+
def decorator(func):
|
|
400
|
+
@wraps(func)
|
|
401
|
+
def wrapper(self, *args, **kwargs):
|
|
402
|
+
if self.solver_name not in solvers:
|
|
403
|
+
raise NotImplementedError(
|
|
404
|
+
f"Method '{func.__name__}' is not implemented for solver '{self.solver_name}'."
|
|
405
|
+
)
|
|
406
|
+
return func(self, *args, **kwargs)
|
|
407
|
+
|
|
408
|
+
return wrapper
|
|
409
|
+
|
|
410
|
+
return decorator
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: pyoframe
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Blazing fast linear program interface
|
|
5
5
|
Author-email: Bravos Power <dev@bravospower.com>
|
|
6
6
|
Project-URL: Homepage, https://bravos-power.github.io/pyoframe/
|
|
@@ -20,7 +20,7 @@ Requires-Dist: numpy
|
|
|
20
20
|
Requires-Dist: pyarrow
|
|
21
21
|
Requires-Dist: pandas
|
|
22
22
|
Requires-Dist: packaging
|
|
23
|
-
Requires-Dist: pyoptinterface~=0.
|
|
23
|
+
Requires-Dist: pyoptinterface~=0.4
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: black[jupyter]; extra == "dev"
|
|
26
26
|
Requires-Dist: bumpver; extra == "dev"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
pyoframe/__init__.py,sha256=nEN0OgqhevtsvxEiPbJLzwPojf3ngYAoT90M_1mc4kM,477
|
|
2
|
+
pyoframe/_arithmetic.py,sha256=LvuxI4pFYuqrqus4FxcIekUwXfdEMEVWBR-1h5hF7Ac,14764
|
|
3
|
+
pyoframe/constants.py,sha256=Dy1sCzykZlmkbvgsc5ckujqXPuYmsKkD3stANU0qr5Y,3784
|
|
4
|
+
pyoframe/core.py,sha256=C9T0wFDAgcsFVxwnLOYqQ2j9fwnCCS_usjlGSME_qmo,62743
|
|
5
|
+
pyoframe/model.py,sha256=d_WyLzdfroDYAtyXs3Ie_jo5c_CGxTX5qPT4vCVaiB8,11967
|
|
6
|
+
pyoframe/model_element.py,sha256=nCfe56CRWr6bwP8irUd2bmLAEGQ-7GwOQtWeqz2WxtU,5944
|
|
7
|
+
pyoframe/monkey_patch.py,sha256=9IfS14G6IPabmM9z80jzi_D4Rq0Mdx5aUCA39Yi2tgE,2044
|
|
8
|
+
pyoframe/objective.py,sha256=PBWxj30QkFlsvY6ijZ6KjyKdrJARD4to0ieF6GUqaQU,3238
|
|
9
|
+
pyoframe/util.py,sha256=Oyk8xh6FJHlb04X_cM4lN0UzdnKLXAMrKfyOf7IexiA,13480
|
|
10
|
+
pyoframe-0.1.2.dist-info/LICENSE,sha256=dkwA40ZzT-3x6eu2a6mf_o7PNSqHbdsyaFNhLxGHNQs,1065
|
|
11
|
+
pyoframe-0.1.2.dist-info/METADATA,sha256=VEtEP6xMwf3R2cbBXXPgfGRnn13qv-QjYwMY6FGR24I,3518
|
|
12
|
+
pyoframe-0.1.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
13
|
+
pyoframe-0.1.2.dist-info/top_level.txt,sha256=10z3OOJSVLriQ0IrFLMH8CH9zByugPWolqhlHlkNjV4,9
|
|
14
|
+
pyoframe-0.1.2.dist-info/RECORD,,
|
pyoframe-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
pyoframe/__init__.py,sha256=nEN0OgqhevtsvxEiPbJLzwPojf3ngYAoT90M_1mc4kM,477
|
|
2
|
-
pyoframe/_arithmetic.py,sha256=LvuxI4pFYuqrqus4FxcIekUwXfdEMEVWBR-1h5hF7Ac,14764
|
|
3
|
-
pyoframe/constants.py,sha256=STQZufgBCS7QTmyQTK_8lINYNSDjXCxVFgF1mXoXen4,3769
|
|
4
|
-
pyoframe/core.py,sha256=C9T0wFDAgcsFVxwnLOYqQ2j9fwnCCS_usjlGSME_qmo,62743
|
|
5
|
-
pyoframe/model.py,sha256=_anptjuAUK2JrHhC2Hy2ouyTT9arEiQAsLO1t5SwsAs,9483
|
|
6
|
-
pyoframe/model_element.py,sha256=nCfe56CRWr6bwP8irUd2bmLAEGQ-7GwOQtWeqz2WxtU,5944
|
|
7
|
-
pyoframe/monkey_patch.py,sha256=9IfS14G6IPabmM9z80jzi_D4Rq0Mdx5aUCA39Yi2tgE,2044
|
|
8
|
-
pyoframe/objective.py,sha256=PBWxj30QkFlsvY6ijZ6KjyKdrJARD4to0ieF6GUqaQU,3238
|
|
9
|
-
pyoframe/util.py,sha256=6Z-hccQ9RT208jJ4hA8pyjSoLvym5Et7M4zcJurIkkY,12941
|
|
10
|
-
pyoframe-0.1.0.dist-info/LICENSE,sha256=dkwA40ZzT-3x6eu2a6mf_o7PNSqHbdsyaFNhLxGHNQs,1065
|
|
11
|
-
pyoframe-0.1.0.dist-info/METADATA,sha256=PuYGrFWwrUL9sxQrremTxbUumg9KOtKVgPds14KCyjs,3518
|
|
12
|
-
pyoframe-0.1.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
13
|
-
pyoframe-0.1.0.dist-info/top_level.txt,sha256=10z3OOJSVLriQ0IrFLMH8CH9zByugPWolqhlHlkNjV4,9
|
|
14
|
-
pyoframe-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|