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.
Files changed (125) hide show
  1. fomtools/__init__.py +14 -0
  2. fomtools/canonicalizers/__init__.py +5 -0
  3. fomtools/canonicalizers/canonicalizer.py +293 -0
  4. fomtools/canonicalizers/mip.py +1265 -0
  5. fomtools/canonicalizers/obbt_handler.py +339 -0
  6. fomtools/canonicalizers/sdp.py +2223 -0
  7. fomtools/canonicalizers/simulator.py +1403 -0
  8. fomtools/codegen/__init__.py +103 -0
  9. fomtools/codegen/agent/__init__.py +110 -0
  10. fomtools/codegen/agent/agents.yaml +33 -0
  11. fomtools/codegen/agent/budget.py +132 -0
  12. fomtools/codegen/agent/claude_sdk.py +221 -0
  13. fomtools/codegen/agent/cli_driver.py +328 -0
  14. fomtools/codegen/agent/cli_specs.py +265 -0
  15. fomtools/codegen/agent/codex_sdk.py +151 -0
  16. fomtools/codegen/agent/driver.py +313 -0
  17. fomtools/codegen/agent/pidev_sdk.py +131 -0
  18. fomtools/codegen/agent/prompts.py +246 -0
  19. fomtools/codegen/agent/sdk_base.py +384 -0
  20. fomtools/codegen/agent/stub.py +104 -0
  21. fomtools/codegen/cli.py +263 -0
  22. fomtools/codegen/config.py +336 -0
  23. fomtools/codegen/dedup.py +132 -0
  24. fomtools/codegen/emit.py +37 -0
  25. fomtools/codegen/examples.py +483 -0
  26. fomtools/codegen/extract.py +655 -0
  27. fomtools/codegen/extract_scheduled.py +415 -0
  28. fomtools/codegen/extract_unrolled.py +321 -0
  29. fomtools/codegen/factorize.py +457 -0
  30. fomtools/codegen/generate.py +625 -0
  31. fomtools/codegen/harness.py +226 -0
  32. fomtools/codegen/ir.py +456 -0
  33. fomtools/codegen/kernel_rules.py +347 -0
  34. fomtools/codegen/objective.py +463 -0
  35. fomtools/codegen/oracle.py +470 -0
  36. fomtools/codegen/postprocess.py +298 -0
  37. fomtools/codegen/schedule.py +123 -0
  38. fomtools/codegen/spec.py +584 -0
  39. fomtools/codegen/targets/__init__.py +26 -0
  40. fomtools/codegen/targets/base.py +151 -0
  41. fomtools/codegen/targets/embedded_c.py +1751 -0
  42. fomtools/codegen/targets/large_scale_cuda.py +1028 -0
  43. fomtools/codegen/targets/large_scale_openmp.py +119 -0
  44. fomtools/codegen/wrapper.py +167 -0
  45. fomtools/constraint.py +425 -0
  46. fomtools/cvxpygen/__init__.py +62 -0
  47. fomtools/cvxpygen/api.py +200 -0
  48. fomtools/cvxpygen/builders.py +600 -0
  49. fomtools/cvxpygen/glue.py +397 -0
  50. fomtools/cvxpygen/interface.py +470 -0
  51. fomtools/cvxpygen/qpdata.py +240 -0
  52. fomtools/cvxpygen/scaling.py +136 -0
  53. fomtools/iteratetrajectory.py +212 -0
  54. fomtools/linearexpression.py +837 -0
  55. fomtools/nn/__init__.py +3 -0
  56. fomtools/nn/layers.py +256 -0
  57. fomtools/proxable_functions/__init__.py +25 -0
  58. fomtools/proxable_functions/elastic_net.py +108 -0
  59. fomtools/proxable_functions/hinge_loss.py +72 -0
  60. fomtools/proxable_functions/huber_loss.py +137 -0
  61. fomtools/proxable_functions/ind_affine.py +144 -0
  62. fomtools/proxable_functions/ind_ball_l1.py +67 -0
  63. fomtools/proxable_functions/ind_ball_linf.py +69 -0
  64. fomtools/proxable_functions/ind_box.py +108 -0
  65. fomtools/proxable_functions/ind_half_space.py +86 -0
  66. fomtools/proxable_functions/ind_nonnegative.py +65 -0
  67. fomtools/proxable_functions/ind_nonpositive.py +65 -0
  68. fomtools/proxable_functions/ind_point.py +71 -0
  69. fomtools/proxable_functions/ind_polyhedral.py +86 -0
  70. fomtools/proxable_functions/ind_simplex.py +56 -0
  71. fomtools/proxable_functions/labeled_hinge_loss.py +74 -0
  72. fomtools/proxable_functions/least_squares.py +91 -0
  73. fomtools/proxable_functions/linear.py +90 -0
  74. fomtools/proxable_functions/norm_inf.py +80 -0
  75. fomtools/proxable_functions/norm_l1.py +109 -0
  76. fomtools/proxable_functions/proximal_operator.py +97 -0
  77. fomtools/proxable_functions/quadratic.py +152 -0
  78. fomtools/proxable_functions/soft_nonnegative.py +85 -0
  79. fomtools/proxable_functions/sq_l2_norm.py +84 -0
  80. fomtools/proxable_functions/sum_negative.py +101 -0
  81. fomtools/proxable_functions/sum_positive.py +97 -0
  82. fomtools/proxable_functions/total_variation_1d.py +93 -0
  83. fomtools/sets/__init__.py +21 -0
  84. fomtools/sets/affine_subspace.py +31 -0
  85. fomtools/sets/ball.py +58 -0
  86. fomtools/sets/box.py +98 -0
  87. fomtools/sets/polyhedron.py +91 -0
  88. fomtools/sets/set.py +112 -0
  89. fomtools/solvers/__init__.py +20 -0
  90. fomtools/solvers/clarabel.py +269 -0
  91. fomtools/solvers/cuclarabel.py +159 -0
  92. fomtools/solvers/factory.py +75 -0
  93. fomtools/solvers/gurobi.py +567 -0
  94. fomtools/solvers/highs.py +430 -0
  95. fomtools/solvers/mip_solver.py +293 -0
  96. fomtools/solvers/sdp_solver.py +48 -0
  97. fomtools/solvers/solver.py +179 -0
  98. fomtools/stepdecomposers/__init__.py +3 -0
  99. fomtools/stepdecomposers/mip_step_decomposer.py +52 -0
  100. fomtools/stepdecomposers/sdp_step_decomposer.py +201 -0
  101. fomtools/stepdecomposers/simulator_step_decomposer.py +326 -0
  102. fomtools/stepdecomposers/step_decomposer.py +1303 -0
  103. fomtools/steps/__init__.py +7 -0
  104. fomtools/steps/affine.py +133 -0
  105. fomtools/steps/lin_prog.py +128 -0
  106. fomtools/steps/quad_prog.py +224 -0
  107. fomtools/steps/relu.py +223 -0
  108. fomtools/steps/saturated_linear.py +113 -0
  109. fomtools/steps/soft_threshold.py +89 -0
  110. fomtools/steps/step.py +79 -0
  111. fomtools/utils/__init__.py +2 -0
  112. fomtools/utils/convex_hull_cuts.py +206 -0
  113. fomtools/utils/dict_utils.py +69 -0
  114. fomtools/utils/envelopes.py +66 -0
  115. fomtools/utils/math_utils.py +86 -0
  116. fomtools/utils/matrix_utils.py +60 -0
  117. fomtools/utils/range_utils.py +65 -0
  118. fomtools/utils/sparse_utils.py +81 -0
  119. fomtools/verifier.py +1602 -0
  120. fomtools-0.0.1.dist-info/METADATA +212 -0
  121. fomtools-0.0.1.dist-info/RECORD +125 -0
  122. fomtools-0.0.1.dist-info/WHEEL +5 -0
  123. fomtools-0.0.1.dist-info/entry_points.txt +2 -0
  124. fomtools-0.0.1.dist-info/licenses/LICENSE +201 -0
  125. 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