oatdb 0.4.0__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.
@@ -0,0 +1,364 @@
1
+ Metadata-Version: 2.1
2
+ Name: oatdb
3
+ Version: 0.4.0
4
+ Summary: Python client for OAT (Optimization and Analysis Tooling) database
5
+ License: MIT
6
+ Keywords: optimization,constraint-solving,database
7
+ Author: Rikard Olsson
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Dist: more-itertools (>=10.8.0,<11.0.0)
18
+ Requires-Dist: pldag (>=0.10.17,<0.11.0)
19
+ Requires-Dist: requests (>=2.31.0,<3.0.0)
20
+ Description-Content-Type: text/markdown
21
+
22
+ # OatDB Python SDK
23
+
24
+ A Python client library for interacting with the OatDB (Optimization and Analysis Tooling) database backend.
25
+
26
+ ## Features
27
+
28
+ - ✅ Full support for all 30 OatDB API functions
29
+ - ✅ Logical operations (AND, OR, XOR, NOT, IMPLY, EQUIV)
30
+ - ✅ Cardinality constraints (AtLeast, AtMost, Equal)
31
+ - ✅ Linear inequality constraints (GeLineq)
32
+ - ✅ Property management
33
+ - ✅ DAG operations (sub, sub_many, validate, ranks)
34
+ - ✅ Constraint propagation
35
+ - ✅ Optimization solver (solve, solve_many)
36
+ - ✅ Node deletion and management
37
+ - ✅ Alias support for named constraints
38
+ - ✅ Type hints for better IDE support
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install oat-python-sdk
44
+ ```
45
+
46
+ Or with Poetry:
47
+
48
+ ```bash
49
+ poetry add oat-python-sdk
50
+ ```
51
+
52
+ ## Quick Start
53
+
54
+ ```python
55
+ from oatdb import OatClient, set_primitive, set_property, set_and, sub, solve
56
+
57
+ # Initialize client
58
+ client = OatClient("http://localhost:7061")
59
+
60
+ # Create primitives with bounds [min, max]
61
+ x = set_primitive("x", bound=1j) # [0, 1]
62
+ y = set_primitive("y", bound=10j) # [0, 10]
63
+
64
+ # Add properties
65
+ x_name = set_property(x, "name", "Variable X")
66
+
67
+ # Create constraints
68
+ constraint = set_and([x, y], alias="my_constraint")
69
+
70
+ # Extract DAG and solve
71
+ dag = sub(constraint)
72
+ solution = solve(
73
+ dag=dag,
74
+ objective={
75
+ x: 1,
76
+ y: 2
77
+ },
78
+ assume={
79
+ # Force constraint to be true
80
+ constraint: 1+1j
81
+ },
82
+ maximize=True
83
+ )
84
+
85
+ # Execute and get results
86
+ result = client.execute(solution)
87
+ print(result)
88
+ ```
89
+
90
+ ## Core Concepts
91
+
92
+ ### Bounds
93
+
94
+ Bounds are represented as complex numbers where:
95
+ - Real part = lower bound
96
+ - Imaginary part = upper bound
97
+
98
+ ```python
99
+ # Bound [0, 1]
100
+ bound = 1j
101
+
102
+ # Bound [5, 10]
103
+ bound = 5 + 10j
104
+
105
+ # Access bounds from solution
106
+ solution_data = result[solution.out]
107
+ x_bounds = solution_data["x"] # [lower, upper] as list
108
+ ```
109
+
110
+ ### Function Calls and Execution
111
+
112
+ All operations return `FunctionCall` objects that you execute using the client:
113
+
114
+ ```python
115
+ from oatdb import OatClient, set_primitive, set_and, sub
116
+
117
+ client = OatClient("http://localhost:7061")
118
+
119
+ # Create function calls
120
+ x = set_primitive("x", bound=1j)
121
+ y = set_primitive("y", bound=1j)
122
+ constraint = set_and([x, y])
123
+
124
+ # Execute a single operation
125
+ result = client.execute(constraint)
126
+
127
+ # Execute multiple operations
128
+ dag = sub(constraint)
129
+ result = client.execute_many([x, y, constraint, dag])
130
+
131
+ # Access results by the function call's output key
132
+ dag_data = result[dag.out]
133
+ ```
134
+
135
+ ## Available Functions
136
+
137
+ All functions return `FunctionCall` objects that are executed using `client.execute()` or `client.execute_many()`.
138
+
139
+ ### Primitive Operations
140
+ - `set_primitive(id: str, bound: complex = 1j, alias: Optional[str] = None)` - Create a single primitive
141
+ - `set_primitives(ids: List[str], bound: complex = 1j)` - Create multiple primitives
142
+ - `set_property(id: Union[str, FunctionCall], property: str, value: Any)` - Set node property
143
+
144
+ ### Logical Operations
145
+ - `set_and(references: List, alias: Optional[str] = None)` - AND operation
146
+ - `set_or(references: List, alias: Optional[str] = None)` - OR operation
147
+ - `set_xor(references: List, alias: Optional[str] = None)` - XOR operation
148
+ - `set_not(references: List, alias: Optional[str] = None)` - NOT operation
149
+ - `set_imply(lhs, rhs, alias: Optional[str] = None)` - Implication (lhs → rhs)
150
+ - `set_equiv(lhs, rhs, alias: Optional[str] = None)` - Equivalence (lhs ↔ rhs)
151
+
152
+ ### Cardinality Constraints
153
+ - `set_atleast(references: List, value: int, alias: Optional[str] = None)` - At least N must be true
154
+ - `set_atmost(references: List, value: int, alias: Optional[str] = None)` - At most N must be true
155
+ - `set_equal(references: List, value: Union[int, str], alias: Optional[str] = None)` - Exactly N must be true
156
+
157
+ ### Linear Constraints
158
+ - `set_gelineq(coefficients: Dict, bias: int, alias: Optional[str] = None)` - Greater-or-equal linear inequality (ax + b >= 0)
159
+
160
+ ### DAG Operations
161
+ - `sub(root)` - Extract sub-DAG from a root node
162
+ - `sub_many(roots: List)` - Extract multiple sub-DAGs
163
+ - `get_node_ids(dag)` - Get all node IDs in a DAG
164
+ - `get_ids_from_dag(dag)` - Get all node IDs from a DAG (alternative)
165
+ - `validate(dag)` - Validate DAG structure
166
+ - `ranks(dag)` - Compute topological ranks
167
+
168
+ ### Alias Operations
169
+ - `get_id_from_alias(alias: str)` - Get node ID from alias
170
+ - `get_alias(id)` - Get alias for a node ID
171
+ - `get_aliases_from_id(id)` - Get all aliases for a node ID
172
+ - `get_ids_from_aliases(aliases: List[str])` - Get IDs for multiple aliases
173
+
174
+ ### Node Operations
175
+ - `get_node(id)` - Get a single node
176
+ - `get_nodes(ids: List)` - Get multiple nodes
177
+ - `get_property_values(property: str)` - Get all nodes with a specific property
178
+
179
+ ### Propagation
180
+ - `propagate(assignments: Dict)` - Propagate constraints with assignments
181
+ - `propagate_many(many_assignments: List[Dict])` - Propagate multiple assignment sets
182
+
183
+ ### Solver
184
+ - `solve(dag, objective: Dict, assume: Optional[Dict] = None, maximize: bool = True)` - Solve single optimization
185
+ - `solve_many(dag, objectives: List[Dict], assume: Optional[Dict] = None, maximize: bool = True)` - Solve multiple optimizations
186
+
187
+ ### Deletion
188
+ - `delete_node(id)` - Delete a single node
189
+ - `delete_sub(roots: List)` - Delete sub-DAGs from roots
190
+
191
+ ### Client Methods
192
+ - `OatClient(url: str)` - Initialize client with server URL
193
+ - `client.execute(call: FunctionCall)` - Execute a single function call
194
+ - `client.execute_many(calls: List[FunctionCall])` - Execute multiple function calls
195
+
196
+ ## Complete Example
197
+
198
+ ```python
199
+ from oatdb import (
200
+ OatClient, set_primitive, set_property, set_and, set_or,
201
+ set_imply, set_atleast, set_gelineq, sub, solve
202
+ )
203
+
204
+ # Initialize
205
+ client = OatClient("http://localhost:7061")
206
+
207
+ # Create primitives
208
+ x = set_primitive("x", bound=10j)
209
+ y = set_primitive("y", bound=10j)
210
+ z = set_primitive("z", bound=10j)
211
+
212
+ # Add metadata
213
+ x_type = set_property(x, "type", "variable")
214
+ x_priority = set_property(x, "priority", 10)
215
+
216
+ # Create constraints
217
+ and_constraint = set_and([x, y], alias="both_xy")
218
+ or_constraint = set_or([y, z])
219
+ imply_constraint = set_imply(x, y) # x → y
220
+
221
+ # Cardinality: at least 2 must be true
222
+ atleast_2 = set_atleast([x, y, z], 2)
223
+
224
+ # Linear constraint: 2x + 3y - z + 5 >= 0
225
+ linear = set_gelineq(
226
+ coefficients={x: 2, y: 3, z: -1},
227
+ bias=5
228
+ )
229
+
230
+ # Combine all constraints
231
+ root = set_and([atleast_2, linear], alias="root")
232
+
233
+ # Extract DAG
234
+ dag = sub(root)
235
+
236
+ # Solve optimization: maximize 3x + 2y + z
237
+ solution = solve(
238
+ dag=dag,
239
+ objective={
240
+ x: 3,
241
+ y: 2,
242
+ z: 1
243
+ },
244
+ assume={
245
+ root: 1+1j
246
+ },
247
+ maximize=True
248
+ )
249
+
250
+ # Execute and get results
251
+ result = client.execute(solution)
252
+
253
+ print("Solution:")
254
+ for var, bounds in result.items():
255
+ if isinstance(bounds, complex):
256
+ print(f" {var}: [{bounds.real}, {bounds.imag}]")
257
+ ```
258
+
259
+ ## Working with Aliases
260
+
261
+ ```python
262
+ from oatdb import OatClient, set_primitive, set_and, get_id_from_alias, get_alias
263
+
264
+ client = OatClient("http://localhost:7061")
265
+
266
+ # Create constraint with alias
267
+ x = set_primitive("x", bound=1j)
268
+ y = set_primitive("y", bound=1j)
269
+ constraint = set_and([x, y], alias="my_constraint")
270
+
271
+ # Execute creation
272
+ client.execute_many([x, y, constraint])
273
+
274
+ # Query by alias
275
+ id_from_alias = get_id_from_alias("my_constraint")
276
+ alias_from_id = get_alias(id_from_alias)
277
+
278
+ result = client.execute_many([id_from_alias, alias_from_id])
279
+ print(f"ID: {result[id_from_alias.out]}")
280
+ print(f"Alias: {result[alias_from_id.out]}")
281
+ ```
282
+
283
+ ## Propagation Example
284
+
285
+ ```python
286
+ from oatdb import OatClient, set_primitive, set_and, propagate
287
+
288
+ client = OatClient("http://localhost:7061")
289
+
290
+ # Create AND constraint
291
+ a = set_primitive("a", bound=1j)
292
+ b = set_primitive("b", bound=1j)
293
+ c = set_primitive("c", bound=1j)
294
+ and_gate = set_and([a, b, c], alias="and_gate")
295
+
296
+ # Propagate: if AND is true, what can we infer?
297
+ prop_result = propagate(
298
+ assignments={
299
+ a: 1+1j,
300
+ b: 1+1j,
301
+ c: 1+1j,
302
+ and_gate: 1j # Upper bound only
303
+ }
304
+ )
305
+
306
+ result = client.execute(prop_result)
307
+ # Result will show that a, b, and c must all be [1, 1]
308
+ print(f"Inferred bounds: {result}")
309
+ ```
310
+
311
+ ## Testing
312
+
313
+ ### Run the comprehensive test suite:
314
+
315
+ ```bash
316
+ cd clients/Python
317
+ python tests/test_client.py
318
+ ```
319
+
320
+ Or with Poetry:
321
+
322
+ ```bash
323
+ poetry run python tests/test_client.py
324
+ ```
325
+
326
+ **Note**: Make sure the OatDB server is running on `http://localhost:7061` before running tests.
327
+
328
+ ### Run examples:
329
+
330
+ ```bash
331
+ python examples.py
332
+ ```
333
+
334
+ ## Requirements
335
+
336
+ - Python >= 3.10
337
+ - requests >= 2.31.0
338
+
339
+ ## Development
340
+
341
+ ```bash
342
+ # Install with Poetry
343
+ poetry install
344
+
345
+ # Run tests
346
+ poetry run pytest
347
+
348
+ # Format code
349
+ poetry run black .
350
+
351
+ # Type checking
352
+ poetry run mypy oatdb
353
+ ```
354
+
355
+ ## License
356
+
357
+ MIT
358
+
359
+ ## Links
360
+
361
+ - [GitHub Repository](https://github.com/yourusername/oat-db-rust-v2)
362
+ - [OatDB Documentation](https://github.com/yourusername/oat-db-rust-v2)
363
+ - [Rust Client](https://github.com/yourusername/oat-db-rust-v2/tree/main/clients/Rust)
364
+
@@ -0,0 +1,4 @@
1
+ oatdb/__init__.py,sha256=0w4BWeg7zzMgKjEA8gBTa4BesnxJGlOOSbeci9aQPM8,36408
2
+ oatdb-0.4.0.dist-info/METADATA,sha256=w1EeFQ9DqxjS6DiqDvoP4TLXAjdKt8tpi1HKhVdZV5c,9618
3
+ oatdb-0.4.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
4
+ oatdb-0.4.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.9.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any