pyoptima 0.0.1__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.
- pyoptima-0.0.1/LICENSE +22 -0
- pyoptima-0.0.1/MANIFEST.in +6 -0
- pyoptima-0.0.1/PKG-INFO +404 -0
- pyoptima-0.0.1/README.md +364 -0
- pyoptima-0.0.1/examples/README.md +34 -0
- pyoptima-0.0.1/examples/example_usage.py +51 -0
- pyoptima-0.0.1/examples/nurse_scheduling.json +43 -0
- pyoptima-0.0.1/examples/portfolio_optimization.json +32 -0
- pyoptima-0.0.1/pyoptima/__init__.py +34 -0
- pyoptima-0.0.1/pyoptima/cli.py +124 -0
- pyoptima-0.0.1/pyoptima/config_parser/__init__.py +8 -0
- pyoptima-0.0.1/pyoptima/config_parser/parser.py +67 -0
- pyoptima-0.0.1/pyoptima/models/__init__.py +22 -0
- pyoptima-0.0.1/pyoptima/models/config.py +108 -0
- pyoptima-0.0.1/pyoptima/optimization_engine.py +111 -0
- pyoptima-0.0.1/pyoptima/py.typed +0 -0
- pyoptima-0.0.1/pyoptima/solvers/__init__.py +9 -0
- pyoptima-0.0.1/pyoptima/solvers/base.py +60 -0
- pyoptima-0.0.1/pyoptima/solvers/cbc_solver.py +117 -0
- pyoptima-0.0.1/pyoptima/solvers/factory.py +50 -0
- pyoptima-0.0.1/pyoptima/solvers/glpk_solver.py +111 -0
- pyoptima-0.0.1/pyoptima/solvers/gurobi_solver.py +119 -0
- pyoptima-0.0.1/pyoptima.egg-info/PKG-INFO +404 -0
- pyoptima-0.0.1/pyoptima.egg-info/SOURCES.txt +29 -0
- pyoptima-0.0.1/pyoptima.egg-info/dependency_links.txt +1 -0
- pyoptima-0.0.1/pyoptima.egg-info/entry_points.txt +2 -0
- pyoptima-0.0.1/pyoptima.egg-info/requires.txt +23 -0
- pyoptima-0.0.1/pyoptima.egg-info/top_level.txt +1 -0
- pyoptima-0.0.1/pyproject.toml +91 -0
- pyoptima-0.0.1/setup.cfg +4 -0
- pyoptima-0.0.1/setup.py +14 -0
pyoptima-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 PyOptima Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
pyoptima-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyoptima
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A Python package for declarative optimization that accepts configuration files and performs optimizations using various solvers (CBC, GUROBI, GLPK)
|
|
5
|
+
Author-email: semantic developers <na@example.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/auscheng/pyoptima
|
|
8
|
+
Project-URL: Documentation, https://github.com/auscheng/pyoptima#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/auscheng/pyoptima
|
|
10
|
+
Project-URL: Issues, https://github.com/auscheng/pyoptima/issues
|
|
11
|
+
Keywords: optimization,python,linear-programming,solver,declarative
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: pydantic>=2.0.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
27
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: build>=0.10.0; extra == "dev"
|
|
29
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
30
|
+
Provides-Extra: cbc
|
|
31
|
+
Requires-Dist: pulp>=2.7.0; extra == "cbc"
|
|
32
|
+
Provides-Extra: gurobi
|
|
33
|
+
Requires-Dist: gurobipy>=11.0.0; extra == "gurobi"
|
|
34
|
+
Provides-Extra: glpk
|
|
35
|
+
Requires-Dist: pulp>=2.7.0; extra == "glpk"
|
|
36
|
+
Provides-Extra: all
|
|
37
|
+
Requires-Dist: pulp>=2.7.0; extra == "all"
|
|
38
|
+
Requires-Dist: gurobipy>=11.0.0; extra == "all"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# PyOptima
|
|
42
|
+
|
|
43
|
+
> **Declarative Optimization Service - Accept configuration files and perform optimizations**
|
|
44
|
+
|
|
45
|
+
[](https://www.python.org/downloads/)
|
|
46
|
+
[](https://opensource.org/licenses/MIT)
|
|
47
|
+
[](https://github.com/psf/black)
|
|
48
|
+
|
|
49
|
+
**PyOptima** is a Python package for declarative optimization that accepts configuration files and performs optimizations using various solvers (CBC, GUROBI, GLPK). It provides a simple, declarative interface for defining optimization problems without writing solver-specific code.
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- 🚀 **Declarative Configuration** - Define optimization problems using JSON configuration files
|
|
54
|
+
- 🔧 **Multiple Solvers** - Support for CBC, GUROBI, and GLPK solvers
|
|
55
|
+
- 📋 **Type Safety** - Full type hints and Pydantic v2 compatibility
|
|
56
|
+
- 🎯 **Easy to Use** - Simple API for running optimizations
|
|
57
|
+
- 🔄 **Swappable Solvers** - Easily switch between different solvers via configuration
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
### Core Library
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install pyoptima
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### With Solver Support
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# For CBC and GLPK (using PuLP)
|
|
71
|
+
pip install pyoptima[cbc]
|
|
72
|
+
pip install pyoptima[glpk]
|
|
73
|
+
|
|
74
|
+
# For Gurobi (requires Gurobi license)
|
|
75
|
+
pip install pyoptima[gurobi]
|
|
76
|
+
|
|
77
|
+
# Install all solvers
|
|
78
|
+
pip install pyoptima[all]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Quick Start
|
|
82
|
+
|
|
83
|
+
### 1. Create a Configuration File
|
|
84
|
+
|
|
85
|
+
Create a JSON file (e.g., `portfolio.json`) with your optimization problem:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"meta": {
|
|
90
|
+
"job_id": "portfolio-rebalance-001",
|
|
91
|
+
"solver": "CBC",
|
|
92
|
+
"time_limit_seconds": 30
|
|
93
|
+
},
|
|
94
|
+
"variables": [
|
|
95
|
+
{ "id": "w_aapl", "type": "Continuous", "lb": 0, "ub": 0.5 },
|
|
96
|
+
{ "id": "w_msft", "type": "Continuous", "lb": 0, "ub": 0.5 }
|
|
97
|
+
],
|
|
98
|
+
"objective": {
|
|
99
|
+
"direction": "Maximize",
|
|
100
|
+
"terms": [
|
|
101
|
+
{ "var": "w_aapl", "coef": 0.12 },
|
|
102
|
+
{ "var": "w_msft", "coef": 0.15 }
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
"constraints": [
|
|
106
|
+
{
|
|
107
|
+
"id": "budget_limit",
|
|
108
|
+
"upper_bound": 1.0,
|
|
109
|
+
"terms": [
|
|
110
|
+
{ "var": "w_aapl", "coef": 1 },
|
|
111
|
+
{ "var": "w_msft", "coef": 1 }
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 2. Run Optimization
|
|
119
|
+
|
|
120
|
+
#### Using CLI
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pyoptima optimize portfolio.json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
With output file:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pyoptima optimize portfolio.json --output results.json --pretty
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### Using Python API
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from pyoptima import OptimizationEngine
|
|
136
|
+
|
|
137
|
+
# Create engine
|
|
138
|
+
engine = OptimizationEngine()
|
|
139
|
+
|
|
140
|
+
# Run optimization
|
|
141
|
+
result = engine.optimize_from_file("portfolio.json")
|
|
142
|
+
|
|
143
|
+
# Check results
|
|
144
|
+
if result.is_optimal():
|
|
145
|
+
print(f"Optimal objective value: {result.objective_value}")
|
|
146
|
+
print(f"Variable values: {result.variables}")
|
|
147
|
+
else:
|
|
148
|
+
print(f"Optimization status: {result.status}")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Configuration Format
|
|
152
|
+
|
|
153
|
+
### Meta
|
|
154
|
+
|
|
155
|
+
Metadata for the optimization job:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"meta": {
|
|
160
|
+
"job_id": "unique-job-id",
|
|
161
|
+
"solver": "CBC", // "CBC", "GUROBI", or "GLPK"
|
|
162
|
+
"time_limit_seconds": 30 // Optional
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Variables
|
|
168
|
+
|
|
169
|
+
Define optimization variables:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"variables": [
|
|
174
|
+
{
|
|
175
|
+
"id": "w_aapl",
|
|
176
|
+
"type": "Continuous", // "Continuous", "Binary", or "Integer"
|
|
177
|
+
"lb": 0, // Optional lower bound
|
|
178
|
+
"ub": 0.5 // Optional upper bound
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"id": "shift_john_1",
|
|
182
|
+
"type": "Binary" // Binary variables don't need bounds
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Objective
|
|
189
|
+
|
|
190
|
+
Define the objective function:
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"objective": {
|
|
195
|
+
"direction": "Maximize", // "Maximize" or "Minimize"
|
|
196
|
+
"terms": [
|
|
197
|
+
{ "var": "w_aapl", "coef": 0.12 },
|
|
198
|
+
{ "var": "shift_john_1", "coef": -10 }
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Constraints
|
|
205
|
+
|
|
206
|
+
Define constraints:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"constraints": [
|
|
211
|
+
{
|
|
212
|
+
"id": "budget_limit",
|
|
213
|
+
"lower_bound": null, // Optional
|
|
214
|
+
"upper_bound": 1.0, // Optional
|
|
215
|
+
"terms": [
|
|
216
|
+
{ "var": "w_aapl", "coef": 1 },
|
|
217
|
+
{ "var": "w_msft", "coef": 1 }
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"id": "min_nurses",
|
|
222
|
+
"lower_bound": 2.0,
|
|
223
|
+
"upper_bound": null,
|
|
224
|
+
"terms": [
|
|
225
|
+
{ "var": "shift_john_1", "coef": 1 },
|
|
226
|
+
{ "var": "shift_jane_1", "coef": 1 }
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Examples
|
|
234
|
+
|
|
235
|
+
### Portfolio Optimization
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"meta": {
|
|
240
|
+
"job_id": "portfolio-001",
|
|
241
|
+
"solver": "CBC"
|
|
242
|
+
},
|
|
243
|
+
"variables": [
|
|
244
|
+
{ "id": "w_aapl", "type": "Continuous", "lb": 0, "ub": 0.4 },
|
|
245
|
+
{ "id": "w_msft", "type": "Continuous", "lb": 0, "ub": 0.4 },
|
|
246
|
+
{ "id": "w_goog", "type": "Continuous", "lb": 0, "ub": 0.4 }
|
|
247
|
+
],
|
|
248
|
+
"objective": {
|
|
249
|
+
"direction": "Maximize",
|
|
250
|
+
"terms": [
|
|
251
|
+
{ "var": "w_aapl", "coef": 0.12 },
|
|
252
|
+
{ "var": "w_msft", "coef": 0.15 },
|
|
253
|
+
{ "var": "w_goog", "coef": 0.18 }
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
"constraints": [
|
|
257
|
+
{
|
|
258
|
+
"id": "budget",
|
|
259
|
+
"upper_bound": 1.0,
|
|
260
|
+
"terms": [
|
|
261
|
+
{ "var": "w_aapl", "coef": 1 },
|
|
262
|
+
{ "var": "w_msft", "coef": 1 },
|
|
263
|
+
{ "var": "w_goog", "coef": 1 }
|
|
264
|
+
]
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Nurse Scheduling
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"meta": {
|
|
275
|
+
"job_id": "nurse-scheduling-001",
|
|
276
|
+
"solver": "CBC"
|
|
277
|
+
},
|
|
278
|
+
"variables": [
|
|
279
|
+
{ "id": "shift_john_1", "type": "Binary" },
|
|
280
|
+
{ "id": "shift_john_2", "type": "Binary" },
|
|
281
|
+
{ "id": "shift_jane_1", "type": "Binary" },
|
|
282
|
+
{ "id": "shift_jane_2", "type": "Binary" }
|
|
283
|
+
],
|
|
284
|
+
"objective": {
|
|
285
|
+
"direction": "Minimize",
|
|
286
|
+
"terms": [
|
|
287
|
+
{ "var": "shift_john_1", "coef": 1 },
|
|
288
|
+
{ "var": "shift_john_2", "coef": 1 },
|
|
289
|
+
{ "var": "shift_jane_1", "coef": 1 },
|
|
290
|
+
{ "var": "shift_jane_2", "coef": 1 }
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
"constraints": [
|
|
294
|
+
{
|
|
295
|
+
"id": "min_nurses_shift1",
|
|
296
|
+
"lower_bound": 2.0,
|
|
297
|
+
"terms": [
|
|
298
|
+
{ "var": "shift_john_1", "coef": 1 },
|
|
299
|
+
{ "var": "shift_jane_1", "coef": 1 }
|
|
300
|
+
]
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"id": "min_nurses_shift2",
|
|
304
|
+
"lower_bound": 2.0,
|
|
305
|
+
"terms": [
|
|
306
|
+
{ "var": "shift_john_2", "coef": 1 },
|
|
307
|
+
{ "var": "shift_jane_2", "coef": 1 }
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
]
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## API Reference
|
|
315
|
+
|
|
316
|
+
### OptimizationEngine
|
|
317
|
+
|
|
318
|
+
Main engine for running optimizations.
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
from pyoptima import OptimizationEngine
|
|
322
|
+
|
|
323
|
+
engine = OptimizationEngine()
|
|
324
|
+
|
|
325
|
+
# From file
|
|
326
|
+
result = engine.optimize_from_file("config.json")
|
|
327
|
+
|
|
328
|
+
# From config object
|
|
329
|
+
from pyoptima import parse_config_file
|
|
330
|
+
config = parse_config_file("config.json")
|
|
331
|
+
result = engine.optimize(config)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### OptimizationResult
|
|
335
|
+
|
|
336
|
+
Result object containing optimization results.
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
result.is_optimal() # Check if solution is optimal
|
|
340
|
+
result.objective_value # Objective function value
|
|
341
|
+
result.variables # Dictionary of variable values
|
|
342
|
+
result.status # Status string
|
|
343
|
+
result.to_dict() # Convert to dictionary
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Supported Solvers
|
|
347
|
+
|
|
348
|
+
### CBC (COIN-OR Branch and Cut)
|
|
349
|
+
|
|
350
|
+
- **Installation**: `pip install pyoptima[cbc]`
|
|
351
|
+
- **Requirements**: PuLP library
|
|
352
|
+
- **Best for**: General-purpose linear and integer programming
|
|
353
|
+
|
|
354
|
+
### Gurobi
|
|
355
|
+
|
|
356
|
+
- **Installation**: `pip install pyoptima[gurobi]`
|
|
357
|
+
- **Requirements**: Gurobi license (academic or commercial)
|
|
358
|
+
- **Best for**: Large-scale optimization problems
|
|
359
|
+
|
|
360
|
+
### GLPK (GNU Linear Programming Kit)
|
|
361
|
+
|
|
362
|
+
- **Installation**: `pip install pyoptima[glpk]`
|
|
363
|
+
- **Requirements**: PuLP library
|
|
364
|
+
- **Best for**: Open-source alternative to commercial solvers
|
|
365
|
+
|
|
366
|
+
## Development Setup
|
|
367
|
+
|
|
368
|
+
### Quick Setup
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# Clone repository
|
|
372
|
+
cd pyoptima
|
|
373
|
+
|
|
374
|
+
# Install in development mode
|
|
375
|
+
pip install -e ".[dev,all]"
|
|
376
|
+
|
|
377
|
+
# Run tests
|
|
378
|
+
pytest
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Requirements
|
|
382
|
+
|
|
383
|
+
- Python 3.10+
|
|
384
|
+
- Pydantic >= 2.0.0
|
|
385
|
+
- Solver-specific dependencies (see installation section)
|
|
386
|
+
|
|
387
|
+
## License
|
|
388
|
+
|
|
389
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
390
|
+
|
|
391
|
+
## Contributing
|
|
392
|
+
|
|
393
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
394
|
+
|
|
395
|
+
1. Fork the repository
|
|
396
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
397
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
398
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
399
|
+
5. Open a Pull Request
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
**Made with ❤️ for the Python optimization community**
|
|
404
|
+
|