fomtools 0.0.1__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.
- fomtools/__init__.py +14 -0
- fomtools/canonicalizers/__init__.py +5 -0
- fomtools/canonicalizers/canonicalizer.py +293 -0
- fomtools/canonicalizers/mip.py +1265 -0
- fomtools/canonicalizers/obbt_handler.py +339 -0
- fomtools/canonicalizers/sdp.py +2223 -0
- fomtools/canonicalizers/simulator.py +1403 -0
- fomtools/codegen/__init__.py +103 -0
- fomtools/codegen/agent/__init__.py +110 -0
- fomtools/codegen/agent/agents.yaml +33 -0
- fomtools/codegen/agent/budget.py +132 -0
- fomtools/codegen/agent/claude_sdk.py +221 -0
- fomtools/codegen/agent/cli_driver.py +328 -0
- fomtools/codegen/agent/cli_specs.py +265 -0
- fomtools/codegen/agent/codex_sdk.py +151 -0
- fomtools/codegen/agent/driver.py +313 -0
- fomtools/codegen/agent/pidev_sdk.py +131 -0
- fomtools/codegen/agent/prompts.py +246 -0
- fomtools/codegen/agent/sdk_base.py +384 -0
- fomtools/codegen/agent/stub.py +104 -0
- fomtools/codegen/cli.py +263 -0
- fomtools/codegen/config.py +336 -0
- fomtools/codegen/dedup.py +132 -0
- fomtools/codegen/emit.py +37 -0
- fomtools/codegen/examples.py +483 -0
- fomtools/codegen/extract.py +655 -0
- fomtools/codegen/extract_scheduled.py +415 -0
- fomtools/codegen/extract_unrolled.py +321 -0
- fomtools/codegen/factorize.py +457 -0
- fomtools/codegen/generate.py +625 -0
- fomtools/codegen/harness.py +226 -0
- fomtools/codegen/ir.py +456 -0
- fomtools/codegen/kernel_rules.py +347 -0
- fomtools/codegen/objective.py +463 -0
- fomtools/codegen/oracle.py +470 -0
- fomtools/codegen/postprocess.py +298 -0
- fomtools/codegen/schedule.py +123 -0
- fomtools/codegen/spec.py +584 -0
- fomtools/codegen/targets/__init__.py +26 -0
- fomtools/codegen/targets/base.py +151 -0
- fomtools/codegen/targets/embedded_c.py +1751 -0
- fomtools/codegen/targets/large_scale_cuda.py +1028 -0
- fomtools/codegen/targets/large_scale_openmp.py +119 -0
- fomtools/codegen/wrapper.py +167 -0
- fomtools/constraint.py +425 -0
- fomtools/cvxpygen/__init__.py +62 -0
- fomtools/cvxpygen/api.py +200 -0
- fomtools/cvxpygen/builders.py +600 -0
- fomtools/cvxpygen/glue.py +397 -0
- fomtools/cvxpygen/interface.py +470 -0
- fomtools/cvxpygen/qpdata.py +240 -0
- fomtools/cvxpygen/scaling.py +136 -0
- fomtools/iteratetrajectory.py +212 -0
- fomtools/linearexpression.py +837 -0
- fomtools/nn/__init__.py +3 -0
- fomtools/nn/layers.py +256 -0
- fomtools/proxable_functions/__init__.py +25 -0
- fomtools/proxable_functions/elastic_net.py +108 -0
- fomtools/proxable_functions/hinge_loss.py +72 -0
- fomtools/proxable_functions/huber_loss.py +137 -0
- fomtools/proxable_functions/ind_affine.py +144 -0
- fomtools/proxable_functions/ind_ball_l1.py +67 -0
- fomtools/proxable_functions/ind_ball_linf.py +69 -0
- fomtools/proxable_functions/ind_box.py +108 -0
- fomtools/proxable_functions/ind_half_space.py +86 -0
- fomtools/proxable_functions/ind_nonnegative.py +65 -0
- fomtools/proxable_functions/ind_nonpositive.py +65 -0
- fomtools/proxable_functions/ind_point.py +71 -0
- fomtools/proxable_functions/ind_polyhedral.py +86 -0
- fomtools/proxable_functions/ind_simplex.py +56 -0
- fomtools/proxable_functions/labeled_hinge_loss.py +74 -0
- fomtools/proxable_functions/least_squares.py +91 -0
- fomtools/proxable_functions/linear.py +90 -0
- fomtools/proxable_functions/norm_inf.py +80 -0
- fomtools/proxable_functions/norm_l1.py +109 -0
- fomtools/proxable_functions/proximal_operator.py +97 -0
- fomtools/proxable_functions/quadratic.py +152 -0
- fomtools/proxable_functions/soft_nonnegative.py +85 -0
- fomtools/proxable_functions/sq_l2_norm.py +84 -0
- fomtools/proxable_functions/sum_negative.py +101 -0
- fomtools/proxable_functions/sum_positive.py +97 -0
- fomtools/proxable_functions/total_variation_1d.py +93 -0
- fomtools/sets/__init__.py +21 -0
- fomtools/sets/affine_subspace.py +31 -0
- fomtools/sets/ball.py +58 -0
- fomtools/sets/box.py +98 -0
- fomtools/sets/polyhedron.py +91 -0
- fomtools/sets/set.py +112 -0
- fomtools/solvers/__init__.py +20 -0
- fomtools/solvers/clarabel.py +269 -0
- fomtools/solvers/cuclarabel.py +159 -0
- fomtools/solvers/factory.py +75 -0
- fomtools/solvers/gurobi.py +567 -0
- fomtools/solvers/highs.py +430 -0
- fomtools/solvers/mip_solver.py +293 -0
- fomtools/solvers/sdp_solver.py +48 -0
- fomtools/solvers/solver.py +179 -0
- fomtools/stepdecomposers/__init__.py +3 -0
- fomtools/stepdecomposers/mip_step_decomposer.py +52 -0
- fomtools/stepdecomposers/sdp_step_decomposer.py +201 -0
- fomtools/stepdecomposers/simulator_step_decomposer.py +326 -0
- fomtools/stepdecomposers/step_decomposer.py +1303 -0
- fomtools/steps/__init__.py +7 -0
- fomtools/steps/affine.py +133 -0
- fomtools/steps/lin_prog.py +128 -0
- fomtools/steps/quad_prog.py +224 -0
- fomtools/steps/relu.py +223 -0
- fomtools/steps/saturated_linear.py +113 -0
- fomtools/steps/soft_threshold.py +89 -0
- fomtools/steps/step.py +79 -0
- fomtools/utils/__init__.py +2 -0
- fomtools/utils/convex_hull_cuts.py +206 -0
- fomtools/utils/dict_utils.py +69 -0
- fomtools/utils/envelopes.py +66 -0
- fomtools/utils/math_utils.py +86 -0
- fomtools/utils/matrix_utils.py +60 -0
- fomtools/utils/range_utils.py +65 -0
- fomtools/utils/sparse_utils.py +81 -0
- fomtools/verifier.py +1602 -0
- fomtools-0.0.1.dist-info/METADATA +212 -0
- fomtools-0.0.1.dist-info/RECORD +125 -0
- fomtools-0.0.1.dist-info/WHEEL +5 -0
- fomtools-0.0.1.dist-info/entry_points.txt +2 -0
- fomtools-0.0.1.dist-info/licenses/LICENSE +201 -0
- fomtools-0.0.1.dist-info/top_level.txt +1 -0
fomtools/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
__version__ = version("fomtools")
|
|
5
|
+
except PackageNotFoundError:
|
|
6
|
+
__version__ = "unknown"
|
|
7
|
+
|
|
8
|
+
from fomtools.utils.dict_utils import merge_dict, prune_dict
|
|
9
|
+
from fomtools.linearexpression import LinearExpression, solve_linexpr, stack
|
|
10
|
+
from fomtools.constraint import sum_squares
|
|
11
|
+
from fomtools.verifier import Verifier
|
|
12
|
+
from fomtools.iteratetrajectory import IterateTrajectory
|
|
13
|
+
from fomtools.steps.step import Step
|
|
14
|
+
from fomtools.sets.set import Set
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
from fomtools.canonicalizers.canonicalizer import Canonicalizer
|
|
2
|
+
from fomtools.canonicalizers.mip import MIP
|
|
3
|
+
from fomtools.canonicalizers.obbt_handler import OBBTHandler
|
|
4
|
+
from fomtools.canonicalizers.sdp import SDP
|
|
5
|
+
from fomtools.canonicalizers.simulator import Simulator
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import ClassVar
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from fomtools.constraint import Constraint
|
|
7
|
+
from fomtools.linearexpression import LinearExpression
|
|
8
|
+
from fomtools.solvers.factory import make_solver
|
|
9
|
+
from fomtools.solvers.solver import Solver
|
|
10
|
+
from fomtools.steps.step import Step
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Canonicalizer:
|
|
14
|
+
"""
|
|
15
|
+
A base class for mathematical-optimization methods. This class
|
|
16
|
+
defines a common interface for mixed-integer programming (MIP),
|
|
17
|
+
and semidefinite programming (SDP).
|
|
18
|
+
|
|
19
|
+
Subclasses declare a class-level ``_CANONICALIZERS`` dict mapping the
|
|
20
|
+
lowercase step class name (e.g. ``"relu"``) to the function that
|
|
21
|
+
encodes it. ``canonicalize`` looks up the function in this dict and
|
|
22
|
+
raises ``NotImplementedError`` if absent.
|
|
23
|
+
|
|
24
|
+
Attributes
|
|
25
|
+
----------
|
|
26
|
+
solver: Solver
|
|
27
|
+
A ready-to-use instance of a subclass of :class:`Solver`
|
|
28
|
+
(e.g., ``gurobi.Gurobi()``).
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
_CANONICALIZERS: ClassVar[dict] = {}
|
|
33
|
+
|
|
34
|
+
def __init__(self, solver_params: dict = None, solver: str = "highs"):
|
|
35
|
+
"""
|
|
36
|
+
Initialize an instance of :class:`Method`.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
solver_params: dict or None, optional
|
|
41
|
+
Key-value pairs with solver parameters and their corresponding
|
|
42
|
+
configuration values.
|
|
43
|
+
|
|
44
|
+
solver: str, default "gurobi"
|
|
45
|
+
Case-insensitive identifier for the solver to use. Supported
|
|
46
|
+
values (and common aliases) include:
|
|
47
|
+
- ``"gurobi"``, ``"grb"``
|
|
48
|
+
"""
|
|
49
|
+
self.solver_params = solver_params
|
|
50
|
+
self.obbt_handler = None
|
|
51
|
+
if solver is not None:
|
|
52
|
+
self.solver_name = solver.lower()
|
|
53
|
+
self.solver = self._get_solver(solver, solver_params)
|
|
54
|
+
else:
|
|
55
|
+
self.solver_name = None
|
|
56
|
+
self.solver = None
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def _get_solver(solver: str, solver_params: dict) -> Solver:
|
|
60
|
+
"""
|
|
61
|
+
Return an initialized solver instance for the requested backend.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
solver: str
|
|
66
|
+
Case-insensitive identifier for the solver to use. Supported values
|
|
67
|
+
(and common aliases) include:
|
|
68
|
+
- ``"gurobi"``, ``"grb"``
|
|
69
|
+
- ``"highs"``
|
|
70
|
+
|
|
71
|
+
solver_params: dict or None, optional
|
|
72
|
+
Key-value pairs with solver parameters and their corresponding
|
|
73
|
+
configuration values.
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
Solver
|
|
78
|
+
A ready-to-use instance of a subclass of :class:`Solver`
|
|
79
|
+
(e.g., ``gurobi.Gurobi()``).
|
|
80
|
+
|
|
81
|
+
Raises
|
|
82
|
+
------
|
|
83
|
+
ValueError
|
|
84
|
+
If `solver` is not one of the supported options.
|
|
85
|
+
"""
|
|
86
|
+
return make_solver(solver, solver_params)
|
|
87
|
+
|
|
88
|
+
def canonicalize(self, step: Step):
|
|
89
|
+
"""
|
|
90
|
+
Dispatch the provided step into a backend-specific encoding.
|
|
91
|
+
|
|
92
|
+
Looks up the lowercase step class name (e.g. ``"relu"``) in this
|
|
93
|
+
canonicalizer's ``_CANONICALIZERS`` registry and invokes the
|
|
94
|
+
corresponding encoder. Raises ``NotImplementedError`` if the step
|
|
95
|
+
type is not registered.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
step: Step
|
|
100
|
+
The concrete step class to canonicalize. This class encapsulates
|
|
101
|
+
the thresholding or activation operator.
|
|
102
|
+
|
|
103
|
+
Returns
|
|
104
|
+
-------
|
|
105
|
+
None
|
|
106
|
+
|
|
107
|
+
Raises
|
|
108
|
+
------
|
|
109
|
+
NotImplementedError
|
|
110
|
+
If this canonicalizer's ``_CANONICALIZERS`` registry has no
|
|
111
|
+
entry for the concrete type of ``step``.
|
|
112
|
+
|
|
113
|
+
"""
|
|
114
|
+
canonicalizer = self._CANONICALIZERS.get(type(step).__name__.lower())
|
|
115
|
+
if canonicalizer is None:
|
|
116
|
+
raise NotImplementedError(
|
|
117
|
+
f"{self.__class__.__name__} does not support {type(step).__name__}"
|
|
118
|
+
)
|
|
119
|
+
canonicalizer(self, step)
|
|
120
|
+
|
|
121
|
+
def add_var(self, iterate, **kwargs) -> None:
|
|
122
|
+
"""
|
|
123
|
+
Add a variable to the canonicalizer instance.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
var : LinearExpression
|
|
128
|
+
Linear expression object to add to the canonicalizer.
|
|
129
|
+
|
|
130
|
+
Raises
|
|
131
|
+
------
|
|
132
|
+
NotImplementedError
|
|
133
|
+
Must be implemented by subclasses.
|
|
134
|
+
"""
|
|
135
|
+
raise NotImplementedError
|
|
136
|
+
|
|
137
|
+
def add_constraint(self, constraint: Constraint) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Add a constraint to the canonicalizer instance.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
constraint : Constraint
|
|
144
|
+
Constraint object to add to the canonicalizer.
|
|
145
|
+
|
|
146
|
+
Raises
|
|
147
|
+
------
|
|
148
|
+
NotImplementedError
|
|
149
|
+
Must be implemented by subclasses.
|
|
150
|
+
"""
|
|
151
|
+
raise NotImplementedError
|
|
152
|
+
|
|
153
|
+
def update_bounds(
|
|
154
|
+
self, expression: LinearExpression, lb: float | np.ndarray, ub: float | np.ndarray
|
|
155
|
+
) -> None:
|
|
156
|
+
"""
|
|
157
|
+
Update the lower and upper bounds of the solver variables corresponding
|
|
158
|
+
to the given ``LinearExpression``.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
expression : LinearExpression
|
|
163
|
+
A ``LinearExpression`` object whose underlying variable
|
|
164
|
+
bounds are to be updated.
|
|
165
|
+
|
|
166
|
+
lb : float or np.ndarray
|
|
167
|
+
New lower bound(s).
|
|
168
|
+
|
|
169
|
+
ub : float or np.ndarray
|
|
170
|
+
New upper bound(s).
|
|
171
|
+
|
|
172
|
+
Raises
|
|
173
|
+
------
|
|
174
|
+
NotImplementedError
|
|
175
|
+
Must be implemented by subclasses.
|
|
176
|
+
"""
|
|
177
|
+
raise NotImplementedError
|
|
178
|
+
|
|
179
|
+
def set_two_norm_objective(
|
|
180
|
+
self, expr_list: list[LinearExpression], lb_list=None, ub_list=None
|
|
181
|
+
) -> None:
|
|
182
|
+
"""
|
|
183
|
+
Set the objective to maximize the sum of squared two-norms.
|
|
184
|
+
|
|
185
|
+
Configures the optimization objective to compute
|
|
186
|
+
sum_i ||expr_i||_2^2 over the given list of expressions.
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
expr_list : list[LinearExpression]
|
|
191
|
+
List of expressions whose squared norms are summed in the
|
|
192
|
+
objective.
|
|
193
|
+
lb_list : list[np.ndarray], optional
|
|
194
|
+
Lower bounds for each expression (may be used by some backends).
|
|
195
|
+
ub_list : list[np.ndarray], optional
|
|
196
|
+
Upper bounds for each expression (may be used by some backends).
|
|
197
|
+
|
|
198
|
+
Raises
|
|
199
|
+
------
|
|
200
|
+
NotImplementedError
|
|
201
|
+
Must be implemented by subclasses that support this objective type.
|
|
202
|
+
"""
|
|
203
|
+
raise NotImplementedError(
|
|
204
|
+
f"{self.__class__.__name__} does not support set_two_norm_objective"
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def set_one_norm_objective(self, expr_list: list[LinearExpression]) -> None:
|
|
208
|
+
"""
|
|
209
|
+
Set the objective to maximize the one-norm (sum of absolute values).
|
|
210
|
+
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
expr_list : list[LinearExpression]
|
|
214
|
+
List of expressions whose one-norms are summed in the objective.
|
|
215
|
+
|
|
216
|
+
Raises
|
|
217
|
+
------
|
|
218
|
+
NotImplementedError
|
|
219
|
+
Must be implemented by subclasses that support this objective type.
|
|
220
|
+
"""
|
|
221
|
+
raise NotImplementedError(
|
|
222
|
+
f"{self.__class__.__name__} does not support set_one_norm_objective"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
def set_infinity_norm_objective(
|
|
226
|
+
self, expr_list: list[LinearExpression], lb=None, ub=None
|
|
227
|
+
) -> None:
|
|
228
|
+
"""
|
|
229
|
+
Set the objective to maximize the infinity-norm (maximum absolute value).
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
expr_list : list[LinearExpression]
|
|
234
|
+
List of expressions whose infinity-norm maximum is the objective.
|
|
235
|
+
lb : np.ndarray, optional
|
|
236
|
+
Lower bounds for the expressions (may be used by some backends).
|
|
237
|
+
ub : np.ndarray, optional
|
|
238
|
+
Upper bounds for the expressions (may be used by some backends).
|
|
239
|
+
|
|
240
|
+
Raises
|
|
241
|
+
------
|
|
242
|
+
NotImplementedError
|
|
243
|
+
Must be implemented by subclasses that support this objective type.
|
|
244
|
+
"""
|
|
245
|
+
raise NotImplementedError(
|
|
246
|
+
f"{self.__class__.__name__} does not support set_infinity_norm_objective"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def get_expression_bounds(self, expr: LinearExpression) -> tuple[np.ndarray, np.ndarray]:
|
|
250
|
+
"""
|
|
251
|
+
Compute bounds for a linear expression.
|
|
252
|
+
|
|
253
|
+
Uses OBBT if available for tighter bounds, otherwise falls back
|
|
254
|
+
to interval bound propagation.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
expr : LinearExpression
|
|
259
|
+
The expression whose bounds are to be computed.
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
tuple[np.ndarray, np.ndarray]
|
|
264
|
+
A tuple (lb, ub) of lower and upper bounds.
|
|
265
|
+
"""
|
|
266
|
+
lb, ub = expr.bound_propagation()
|
|
267
|
+
|
|
268
|
+
if self.obbt_handler is not None:
|
|
269
|
+
result = self.obbt_handler.obbt(expr, lb, ub)
|
|
270
|
+
if result is not None:
|
|
271
|
+
lb, ub = result
|
|
272
|
+
|
|
273
|
+
return lb, ub
|
|
274
|
+
|
|
275
|
+
@abstractmethod
|
|
276
|
+
def copy(self) -> "Canonicalizer":
|
|
277
|
+
"""
|
|
278
|
+
Create an independent copy of this canonicalizer.
|
|
279
|
+
|
|
280
|
+
The copy shares no mutable state with the original and can be
|
|
281
|
+
modified (e.g., adding objectives) without affecting the original.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
Canonicalizer
|
|
286
|
+
A new canonicalizer instance with copied state.
|
|
287
|
+
|
|
288
|
+
Raises
|
|
289
|
+
------
|
|
290
|
+
NotImplementedError
|
|
291
|
+
Must be implemented by subclasses.
|
|
292
|
+
"""
|
|
293
|
+
raise NotImplementedError
|