stitchlab-optimization 0.0.2__tar.gz → 0.0.4__tar.gz
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.
- stitchlab_optimization-0.0.4/PKG-INFO +176 -0
- stitchlab_optimization-0.0.4/README.md +142 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/pyproject.toml +1 -1
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/__init__.py +1 -1
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/builder/model.py +6 -3
- stitchlab_optimization-0.0.4/src/stitchlab_optimization.egg-info/PKG-INFO +176 -0
- stitchlab_optimization-0.0.2/PKG-INFO +0 -33
- stitchlab_optimization-0.0.2/README.md +0 -0
- stitchlab_optimization-0.0.2/src/stitchlab_optimization.egg-info/PKG-INFO +0 -33
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/LICENSE +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/setup.cfg +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/builder/__init__.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/builder/workflow.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/logger/__init__.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/logger/file_logger.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/logger/manager.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/logger/sqlite_logger.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/solver/__init__.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/solver/config.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/solver/engine.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/solver/status.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/tools/query/snowflake.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/tools/query/sqlite.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization/tools/utils.py +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization.egg-info/SOURCES.txt +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization.egg-info/dependency_links.txt +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization.egg-info/requires.txt +0 -0
- {stitchlab_optimization-0.0.2 → stitchlab_optimization-0.0.4}/src/stitchlab_optimization.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stitchlab-optimization
|
|
3
|
+
Version: 0.0.4
|
|
4
|
+
Summary: StitchLab Optimization application
|
|
5
|
+
Author-email: StitchLab Team <evazuliya97@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/eva-zuliya/stitchlab-optimization
|
|
8
|
+
Project-URL: Repository, https://github.com/eva-zuliya/stitchlab-optimization
|
|
9
|
+
Project-URL: Issues, https://github.com/eva-zuliya/stitchlab-optimization/issues
|
|
10
|
+
Keywords: optimization,ai
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: <3.14,>=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: pydantic<3.0,>=2.0
|
|
22
|
+
Requires-Dist: python-dotenv<2.0,>=1.0
|
|
23
|
+
Requires-Dist: pyscipopt<7.0,>=6.0
|
|
24
|
+
Requires-Dist: ortools<10.0,>=9.15
|
|
25
|
+
Requires-Dist: gurobipy<14.0,>=13.0
|
|
26
|
+
Requires-Dist: pandas<4.0,>=2.0
|
|
27
|
+
Requires-Dist: psutil<8.0,>=5.9
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
31
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# Stitchlab Optimization Framework
|
|
36
|
+
|
|
37
|
+
A standardized framework for building optimization models with multi-solver support. This framework allows you to define optimization models once and easily switch between different solvers without rewriting your model logic.
|
|
38
|
+
|
|
39
|
+
## Overview
|
|
40
|
+
|
|
41
|
+
The framework is built around two core concepts:
|
|
42
|
+
|
|
43
|
+
- **Workflow**: Orchestrates one or more optimization models to solve complex problems
|
|
44
|
+
- **Model**: Defines the optimization problem with multiple solver implementations (builders)
|
|
45
|
+
|
|
46
|
+
## Key Features
|
|
47
|
+
|
|
48
|
+
- **Solver Agnostic**: Write your model once, run it with different solvers (OR-Tools CP-SAT, OR-Tools SCIP, PySCIPOpt, etc.)
|
|
49
|
+
- **Type Safety**: Built with Pydantic for robust data validation
|
|
50
|
+
- **Logging**: SQLite-based logging for tracking optimization runs
|
|
51
|
+
- **Modular Design**: Separate concerns between model definition, solving, and workflow orchestration
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### 1. Define Your Model Parameters and Solution
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from pydantic import BaseModel
|
|
59
|
+
from stitchlab_optimization.builder.model import ModelParams
|
|
60
|
+
|
|
61
|
+
class SimpleParams(ModelParams):
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
class SimpleSolution(BaseModel):
|
|
65
|
+
x: int
|
|
66
|
+
y: int
|
|
67
|
+
objective: float
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Create Builders for Different Solvers
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from stitchlab_optimization.builder.model import ModelBuilder
|
|
74
|
+
|
|
75
|
+
class SimpleCPSATBuilder(ModelBuilder[SimpleParams, SimpleSolution]):
|
|
76
|
+
def build(self):
|
|
77
|
+
from ortools.sat.python import cp_model
|
|
78
|
+
model = cp_model.CpModel()
|
|
79
|
+
|
|
80
|
+
self.model_vars = {}
|
|
81
|
+
self.model_vars['x'] = model.NewIntVar(0, 5, 'x')
|
|
82
|
+
self.model_vars['y'] = model.NewIntVar(0, 7, 'y')
|
|
83
|
+
|
|
84
|
+
model.Add(self.model_vars['x'] + self.model_vars['y'] <= 10)
|
|
85
|
+
model.Maximize(self.model_vars['x'] + self.model_vars['y'])
|
|
86
|
+
|
|
87
|
+
self._set_model(model)
|
|
88
|
+
|
|
89
|
+
def construct_solution(self):
|
|
90
|
+
if self.model_output:
|
|
91
|
+
return SimpleSolution(
|
|
92
|
+
x=self.model_output.Value(self.model_vars['x']),
|
|
93
|
+
y=self.model_output.Value(self.model_vars['y']),
|
|
94
|
+
objective=self.model_output.ObjectiveValue()
|
|
95
|
+
)
|
|
96
|
+
return None
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Register Builders in Your Model
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from stitchlab_optimization.builder.model import OptimizationModel
|
|
103
|
+
from stitchlab_optimization.solver.engine import SolverEngine
|
|
104
|
+
|
|
105
|
+
class SimpleModel(OptimizationModel[SimpleParams, SimpleSolution]):
|
|
106
|
+
builders_registry = {
|
|
107
|
+
SolverEngine.ORTOOLS_CPSAT: SimpleCPSATBuilder,
|
|
108
|
+
SolverEngine.ORTOOLS_SCIP: SimpleSCIPBuilder,
|
|
109
|
+
SolverEngine.PYSCIPOPT: SimplePySCIPOPTBuilder
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 4. Create a Workflow
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from stitchlab_optimization.builder.workflow import OptimizationWorkflow
|
|
117
|
+
|
|
118
|
+
class InputData(BaseModel):
|
|
119
|
+
id: str
|
|
120
|
+
|
|
121
|
+
class OutputData(SimpleSolution):
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
class SimpleWorkflow(OptimizationWorkflow[InputData, OutputData]):
|
|
125
|
+
models_registry = {
|
|
126
|
+
"simple_model": SimpleModel
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
def execute(self):
|
|
130
|
+
return self.execute_model(
|
|
131
|
+
"simple_model",
|
|
132
|
+
SimpleParams(),
|
|
133
|
+
SolverEngine.ORTOOLS_CPSAT
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 5. Run Your Workflow
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from stitchlab_optimization.logger.sqlite_logger import SQLiteLogManager
|
|
141
|
+
|
|
142
|
+
logger = SQLiteLogManager(db_path="test.db")
|
|
143
|
+
|
|
144
|
+
payload = InputData(id="1")
|
|
145
|
+
workflow = SimpleWorkflow(payload=payload, logger=logger)
|
|
146
|
+
output = workflow.invoke()
|
|
147
|
+
print(output)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Architecture
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
Workflow
|
|
154
|
+
├── Model 1
|
|
155
|
+
│ ├── Builder (Solver A)
|
|
156
|
+
│ ├── Builder (Solver B)
|
|
157
|
+
│ └── Builder (Solver C)
|
|
158
|
+
└── Model 2
|
|
159
|
+
├── Builder (Solver A)
|
|
160
|
+
└── Builder (Solver B)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Benefits
|
|
164
|
+
|
|
165
|
+
1. **Easy Solver Switching**: Change solvers by modifying a single parameter
|
|
166
|
+
2. **Reusability**: Define model logic once, use with multiple solvers
|
|
167
|
+
3. **Maintainability**: Clear separation between model definition and solver implementation
|
|
168
|
+
4. **Extensibility**: Add new solvers by implementing new builders
|
|
169
|
+
5. **Testability**: Test different solvers against the same model to compare performance
|
|
170
|
+
|
|
171
|
+
## Supported Solvers
|
|
172
|
+
|
|
173
|
+
- OR-Tools CP-SAT
|
|
174
|
+
- OR-Tools SCIP
|
|
175
|
+
- PySCIPOpt
|
|
176
|
+
- GUROBI
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Stitchlab Optimization Framework
|
|
2
|
+
|
|
3
|
+
A standardized framework for building optimization models with multi-solver support. This framework allows you to define optimization models once and easily switch between different solvers without rewriting your model logic.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The framework is built around two core concepts:
|
|
8
|
+
|
|
9
|
+
- **Workflow**: Orchestrates one or more optimization models to solve complex problems
|
|
10
|
+
- **Model**: Defines the optimization problem with multiple solver implementations (builders)
|
|
11
|
+
|
|
12
|
+
## Key Features
|
|
13
|
+
|
|
14
|
+
- **Solver Agnostic**: Write your model once, run it with different solvers (OR-Tools CP-SAT, OR-Tools SCIP, PySCIPOpt, etc.)
|
|
15
|
+
- **Type Safety**: Built with Pydantic for robust data validation
|
|
16
|
+
- **Logging**: SQLite-based logging for tracking optimization runs
|
|
17
|
+
- **Modular Design**: Separate concerns between model definition, solving, and workflow orchestration
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### 1. Define Your Model Parameters and Solution
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from pydantic import BaseModel
|
|
25
|
+
from stitchlab_optimization.builder.model import ModelParams
|
|
26
|
+
|
|
27
|
+
class SimpleParams(ModelParams):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
class SimpleSolution(BaseModel):
|
|
31
|
+
x: int
|
|
32
|
+
y: int
|
|
33
|
+
objective: float
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Create Builders for Different Solvers
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from stitchlab_optimization.builder.model import ModelBuilder
|
|
40
|
+
|
|
41
|
+
class SimpleCPSATBuilder(ModelBuilder[SimpleParams, SimpleSolution]):
|
|
42
|
+
def build(self):
|
|
43
|
+
from ortools.sat.python import cp_model
|
|
44
|
+
model = cp_model.CpModel()
|
|
45
|
+
|
|
46
|
+
self.model_vars = {}
|
|
47
|
+
self.model_vars['x'] = model.NewIntVar(0, 5, 'x')
|
|
48
|
+
self.model_vars['y'] = model.NewIntVar(0, 7, 'y')
|
|
49
|
+
|
|
50
|
+
model.Add(self.model_vars['x'] + self.model_vars['y'] <= 10)
|
|
51
|
+
model.Maximize(self.model_vars['x'] + self.model_vars['y'])
|
|
52
|
+
|
|
53
|
+
self._set_model(model)
|
|
54
|
+
|
|
55
|
+
def construct_solution(self):
|
|
56
|
+
if self.model_output:
|
|
57
|
+
return SimpleSolution(
|
|
58
|
+
x=self.model_output.Value(self.model_vars['x']),
|
|
59
|
+
y=self.model_output.Value(self.model_vars['y']),
|
|
60
|
+
objective=self.model_output.ObjectiveValue()
|
|
61
|
+
)
|
|
62
|
+
return None
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. Register Builders in Your Model
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from stitchlab_optimization.builder.model import OptimizationModel
|
|
69
|
+
from stitchlab_optimization.solver.engine import SolverEngine
|
|
70
|
+
|
|
71
|
+
class SimpleModel(OptimizationModel[SimpleParams, SimpleSolution]):
|
|
72
|
+
builders_registry = {
|
|
73
|
+
SolverEngine.ORTOOLS_CPSAT: SimpleCPSATBuilder,
|
|
74
|
+
SolverEngine.ORTOOLS_SCIP: SimpleSCIPBuilder,
|
|
75
|
+
SolverEngine.PYSCIPOPT: SimplePySCIPOPTBuilder
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 4. Create a Workflow
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from stitchlab_optimization.builder.workflow import OptimizationWorkflow
|
|
83
|
+
|
|
84
|
+
class InputData(BaseModel):
|
|
85
|
+
id: str
|
|
86
|
+
|
|
87
|
+
class OutputData(SimpleSolution):
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
class SimpleWorkflow(OptimizationWorkflow[InputData, OutputData]):
|
|
91
|
+
models_registry = {
|
|
92
|
+
"simple_model": SimpleModel
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
def execute(self):
|
|
96
|
+
return self.execute_model(
|
|
97
|
+
"simple_model",
|
|
98
|
+
SimpleParams(),
|
|
99
|
+
SolverEngine.ORTOOLS_CPSAT
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 5. Run Your Workflow
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from stitchlab_optimization.logger.sqlite_logger import SQLiteLogManager
|
|
107
|
+
|
|
108
|
+
logger = SQLiteLogManager(db_path="test.db")
|
|
109
|
+
|
|
110
|
+
payload = InputData(id="1")
|
|
111
|
+
workflow = SimpleWorkflow(payload=payload, logger=logger)
|
|
112
|
+
output = workflow.invoke()
|
|
113
|
+
print(output)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Architecture
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Workflow
|
|
120
|
+
├── Model 1
|
|
121
|
+
│ ├── Builder (Solver A)
|
|
122
|
+
│ ├── Builder (Solver B)
|
|
123
|
+
│ └── Builder (Solver C)
|
|
124
|
+
└── Model 2
|
|
125
|
+
├── Builder (Solver A)
|
|
126
|
+
└── Builder (Solver B)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Benefits
|
|
130
|
+
|
|
131
|
+
1. **Easy Solver Switching**: Change solvers by modifying a single parameter
|
|
132
|
+
2. **Reusability**: Define model logic once, use with multiple solvers
|
|
133
|
+
3. **Maintainability**: Clear separation between model definition and solver implementation
|
|
134
|
+
4. **Extensibility**: Add new solvers by implementing new builders
|
|
135
|
+
5. **Testability**: Test different solvers against the same model to compare performance
|
|
136
|
+
|
|
137
|
+
## Supported Solvers
|
|
138
|
+
|
|
139
|
+
- OR-Tools CP-SAT
|
|
140
|
+
- OR-Tools SCIP
|
|
141
|
+
- PySCIPOpt
|
|
142
|
+
- GUROBI
|
|
@@ -126,6 +126,7 @@ class ModelBuilder(Generic[ParamsBaseModel, SolutionBaseModel], ABC):
|
|
|
126
126
|
|
|
127
127
|
elif self.solver_engine == SolverEngine.ORTOOLS_CPSAT:
|
|
128
128
|
self.solve_ortools_cpsat()
|
|
129
|
+
|
|
129
130
|
else:
|
|
130
131
|
raise ValueError(f"Solver engine {self.solver_engine} not supported")
|
|
131
132
|
|
|
@@ -396,11 +397,13 @@ class OptimizationModel(Generic[ParamsBaseModel, SolutionBaseModel], ABC, metacl
|
|
|
396
397
|
|
|
397
398
|
# Objective value (only available if model solved)
|
|
398
399
|
try:
|
|
399
|
-
objective_value = builder.
|
|
400
|
+
objective_value = builder.model_output.ObjectiveValue()
|
|
401
|
+
best_bound = builder.model_output.BestObjectiveBound()
|
|
402
|
+
optimality_gap = abs(objective_value - best_bound) / max(1.0, abs(objective_value))
|
|
403
|
+
|
|
400
404
|
except Exception:
|
|
401
405
|
objective_value = None
|
|
402
|
-
|
|
403
|
-
optimality_gap = None
|
|
406
|
+
optimality_gap = None
|
|
404
407
|
|
|
405
408
|
elif solver_engine == SolverEngine.PYSCIPOPT:
|
|
406
409
|
problem_size_vars = builder.model.getNVars()
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stitchlab-optimization
|
|
3
|
+
Version: 0.0.4
|
|
4
|
+
Summary: StitchLab Optimization application
|
|
5
|
+
Author-email: StitchLab Team <evazuliya97@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/eva-zuliya/stitchlab-optimization
|
|
8
|
+
Project-URL: Repository, https://github.com/eva-zuliya/stitchlab-optimization
|
|
9
|
+
Project-URL: Issues, https://github.com/eva-zuliya/stitchlab-optimization/issues
|
|
10
|
+
Keywords: optimization,ai
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: <3.14,>=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: pydantic<3.0,>=2.0
|
|
22
|
+
Requires-Dist: python-dotenv<2.0,>=1.0
|
|
23
|
+
Requires-Dist: pyscipopt<7.0,>=6.0
|
|
24
|
+
Requires-Dist: ortools<10.0,>=9.15
|
|
25
|
+
Requires-Dist: gurobipy<14.0,>=13.0
|
|
26
|
+
Requires-Dist: pandas<4.0,>=2.0
|
|
27
|
+
Requires-Dist: psutil<8.0,>=5.9
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
31
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# Stitchlab Optimization Framework
|
|
36
|
+
|
|
37
|
+
A standardized framework for building optimization models with multi-solver support. This framework allows you to define optimization models once and easily switch between different solvers without rewriting your model logic.
|
|
38
|
+
|
|
39
|
+
## Overview
|
|
40
|
+
|
|
41
|
+
The framework is built around two core concepts:
|
|
42
|
+
|
|
43
|
+
- **Workflow**: Orchestrates one or more optimization models to solve complex problems
|
|
44
|
+
- **Model**: Defines the optimization problem with multiple solver implementations (builders)
|
|
45
|
+
|
|
46
|
+
## Key Features
|
|
47
|
+
|
|
48
|
+
- **Solver Agnostic**: Write your model once, run it with different solvers (OR-Tools CP-SAT, OR-Tools SCIP, PySCIPOpt, etc.)
|
|
49
|
+
- **Type Safety**: Built with Pydantic for robust data validation
|
|
50
|
+
- **Logging**: SQLite-based logging for tracking optimization runs
|
|
51
|
+
- **Modular Design**: Separate concerns between model definition, solving, and workflow orchestration
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### 1. Define Your Model Parameters and Solution
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from pydantic import BaseModel
|
|
59
|
+
from stitchlab_optimization.builder.model import ModelParams
|
|
60
|
+
|
|
61
|
+
class SimpleParams(ModelParams):
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
class SimpleSolution(BaseModel):
|
|
65
|
+
x: int
|
|
66
|
+
y: int
|
|
67
|
+
objective: float
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Create Builders for Different Solvers
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from stitchlab_optimization.builder.model import ModelBuilder
|
|
74
|
+
|
|
75
|
+
class SimpleCPSATBuilder(ModelBuilder[SimpleParams, SimpleSolution]):
|
|
76
|
+
def build(self):
|
|
77
|
+
from ortools.sat.python import cp_model
|
|
78
|
+
model = cp_model.CpModel()
|
|
79
|
+
|
|
80
|
+
self.model_vars = {}
|
|
81
|
+
self.model_vars['x'] = model.NewIntVar(0, 5, 'x')
|
|
82
|
+
self.model_vars['y'] = model.NewIntVar(0, 7, 'y')
|
|
83
|
+
|
|
84
|
+
model.Add(self.model_vars['x'] + self.model_vars['y'] <= 10)
|
|
85
|
+
model.Maximize(self.model_vars['x'] + self.model_vars['y'])
|
|
86
|
+
|
|
87
|
+
self._set_model(model)
|
|
88
|
+
|
|
89
|
+
def construct_solution(self):
|
|
90
|
+
if self.model_output:
|
|
91
|
+
return SimpleSolution(
|
|
92
|
+
x=self.model_output.Value(self.model_vars['x']),
|
|
93
|
+
y=self.model_output.Value(self.model_vars['y']),
|
|
94
|
+
objective=self.model_output.ObjectiveValue()
|
|
95
|
+
)
|
|
96
|
+
return None
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Register Builders in Your Model
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from stitchlab_optimization.builder.model import OptimizationModel
|
|
103
|
+
from stitchlab_optimization.solver.engine import SolverEngine
|
|
104
|
+
|
|
105
|
+
class SimpleModel(OptimizationModel[SimpleParams, SimpleSolution]):
|
|
106
|
+
builders_registry = {
|
|
107
|
+
SolverEngine.ORTOOLS_CPSAT: SimpleCPSATBuilder,
|
|
108
|
+
SolverEngine.ORTOOLS_SCIP: SimpleSCIPBuilder,
|
|
109
|
+
SolverEngine.PYSCIPOPT: SimplePySCIPOPTBuilder
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 4. Create a Workflow
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from stitchlab_optimization.builder.workflow import OptimizationWorkflow
|
|
117
|
+
|
|
118
|
+
class InputData(BaseModel):
|
|
119
|
+
id: str
|
|
120
|
+
|
|
121
|
+
class OutputData(SimpleSolution):
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
class SimpleWorkflow(OptimizationWorkflow[InputData, OutputData]):
|
|
125
|
+
models_registry = {
|
|
126
|
+
"simple_model": SimpleModel
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
def execute(self):
|
|
130
|
+
return self.execute_model(
|
|
131
|
+
"simple_model",
|
|
132
|
+
SimpleParams(),
|
|
133
|
+
SolverEngine.ORTOOLS_CPSAT
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 5. Run Your Workflow
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from stitchlab_optimization.logger.sqlite_logger import SQLiteLogManager
|
|
141
|
+
|
|
142
|
+
logger = SQLiteLogManager(db_path="test.db")
|
|
143
|
+
|
|
144
|
+
payload = InputData(id="1")
|
|
145
|
+
workflow = SimpleWorkflow(payload=payload, logger=logger)
|
|
146
|
+
output = workflow.invoke()
|
|
147
|
+
print(output)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Architecture
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
Workflow
|
|
154
|
+
├── Model 1
|
|
155
|
+
│ ├── Builder (Solver A)
|
|
156
|
+
│ ├── Builder (Solver B)
|
|
157
|
+
│ └── Builder (Solver C)
|
|
158
|
+
└── Model 2
|
|
159
|
+
├── Builder (Solver A)
|
|
160
|
+
└── Builder (Solver B)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Benefits
|
|
164
|
+
|
|
165
|
+
1. **Easy Solver Switching**: Change solvers by modifying a single parameter
|
|
166
|
+
2. **Reusability**: Define model logic once, use with multiple solvers
|
|
167
|
+
3. **Maintainability**: Clear separation between model definition and solver implementation
|
|
168
|
+
4. **Extensibility**: Add new solvers by implementing new builders
|
|
169
|
+
5. **Testability**: Test different solvers against the same model to compare performance
|
|
170
|
+
|
|
171
|
+
## Supported Solvers
|
|
172
|
+
|
|
173
|
+
- OR-Tools CP-SAT
|
|
174
|
+
- OR-Tools SCIP
|
|
175
|
+
- PySCIPOpt
|
|
176
|
+
- GUROBI
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: stitchlab-optimization
|
|
3
|
-
Version: 0.0.2
|
|
4
|
-
Summary: StitchLab Optimization application
|
|
5
|
-
Author-email: StitchLab Team <evazuliya97@gmail.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/eva-zuliya/stitchlab-optimization
|
|
8
|
-
Project-URL: Repository, https://github.com/eva-zuliya/stitchlab-optimization
|
|
9
|
-
Project-URL: Issues, https://github.com/eva-zuliya/stitchlab-optimization/issues
|
|
10
|
-
Keywords: optimization,ai
|
|
11
|
-
Classifier: Development Status :: 3 - Alpha
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
-
Requires-Python: <3.14,>=3.11
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
20
|
-
License-File: LICENSE
|
|
21
|
-
Requires-Dist: pydantic<3.0,>=2.0
|
|
22
|
-
Requires-Dist: python-dotenv<2.0,>=1.0
|
|
23
|
-
Requires-Dist: pyscipopt<7.0,>=6.0
|
|
24
|
-
Requires-Dist: ortools<10.0,>=9.15
|
|
25
|
-
Requires-Dist: gurobipy<14.0,>=13.0
|
|
26
|
-
Requires-Dist: pandas<4.0,>=2.0
|
|
27
|
-
Requires-Dist: psutil<8.0,>=5.9
|
|
28
|
-
Provides-Extra: dev
|
|
29
|
-
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
30
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
31
|
-
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
32
|
-
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
|
-
Dynamic: license-file
|
|
File without changes
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: stitchlab-optimization
|
|
3
|
-
Version: 0.0.2
|
|
4
|
-
Summary: StitchLab Optimization application
|
|
5
|
-
Author-email: StitchLab Team <evazuliya97@gmail.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/eva-zuliya/stitchlab-optimization
|
|
8
|
-
Project-URL: Repository, https://github.com/eva-zuliya/stitchlab-optimization
|
|
9
|
-
Project-URL: Issues, https://github.com/eva-zuliya/stitchlab-optimization/issues
|
|
10
|
-
Keywords: optimization,ai
|
|
11
|
-
Classifier: Development Status :: 3 - Alpha
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
-
Requires-Python: <3.14,>=3.11
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
20
|
-
License-File: LICENSE
|
|
21
|
-
Requires-Dist: pydantic<3.0,>=2.0
|
|
22
|
-
Requires-Dist: python-dotenv<2.0,>=1.0
|
|
23
|
-
Requires-Dist: pyscipopt<7.0,>=6.0
|
|
24
|
-
Requires-Dist: ortools<10.0,>=9.15
|
|
25
|
-
Requires-Dist: gurobipy<14.0,>=13.0
|
|
26
|
-
Requires-Dist: pandas<4.0,>=2.0
|
|
27
|
-
Requires-Dist: psutil<8.0,>=5.9
|
|
28
|
-
Provides-Extra: dev
|
|
29
|
-
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
30
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
31
|
-
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
32
|
-
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
|
-
Dynamic: license-file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|