fomtools 0.0.2__tar.gz → 0.0.3__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.
Files changed (377) hide show
  1. {fomtools-0.0.2 → fomtools-0.0.3}/.github/workflows/docs.yml +9 -13
  2. {fomtools-0.0.2 → fomtools-0.0.3}/.gitignore +5 -0
  3. {fomtools-0.0.2 → fomtools-0.0.3}/AGENTS.md +26 -0
  4. fomtools-0.0.3/CONTRIBUTING.md +34 -0
  5. fomtools-0.0.3/Makefile +13 -0
  6. {fomtools-0.0.2/fomtools.egg-info → fomtools-0.0.3}/PKG-INFO +50 -9
  7. {fomtools-0.0.2 → fomtools-0.0.3}/README.md +42 -7
  8. fomtools-0.0.3/docs/api/canonicalizer.md +38 -0
  9. {fomtools-0.0.2 → fomtools-0.0.3}/docs/api/codegen.md +4 -0
  10. fomtools-0.0.3/docs/api/constraint.md +8 -0
  11. fomtools-0.0.3/docs/api/index.md +44 -0
  12. fomtools-0.0.3/docs/api/linearexpression.md +6 -0
  13. fomtools-0.0.3/docs/api/proxablefunctions.md +35 -0
  14. {fomtools-0.0.2 → fomtools-0.0.3}/docs/api/solvers.md +4 -1
  15. {fomtools-0.0.2 → fomtools-0.0.3}/docs/api/steps.md +4 -1
  16. fomtools-0.0.3/docs/api/verifier.md +7 -0
  17. fomtools-0.0.3/docs/assets/logo/favicon-16.png +0 -0
  18. fomtools-0.0.3/docs/assets/logo/favicon-32.png +0 -0
  19. fomtools-0.0.3/docs/assets/logo/favicon-48.png +0 -0
  20. fomtools-0.0.3/docs/assets/logo/favicon.svg +1 -0
  21. fomtools-0.0.3/docs/assets/logo/icon-512.png +0 -0
  22. fomtools-0.0.3/docs/assets/logo/icon-dark.svg +1 -0
  23. fomtools-0.0.3/docs/assets/logo/icon-mono.svg +1 -0
  24. fomtools-0.0.3/docs/assets/logo/icon-small.svg +1 -0
  25. fomtools-0.0.3/docs/assets/logo/icon.svg +1 -0
  26. fomtools-0.0.3/docs/assets/logo/logo-dark.svg +1 -0
  27. fomtools-0.0.3/docs/assets/logo/logo-mono.svg +1 -0
  28. fomtools-0.0.3/docs/assets/logo/logo.svg +1 -0
  29. fomtools-0.0.3/docs/get_started.md +140 -0
  30. fomtools-0.0.3/docs/index.md +149 -0
  31. fomtools-0.0.3/docs/quick_start.md +177 -0
  32. fomtools-0.0.3/docs/stylesheets/extra.css +85 -0
  33. {fomtools-0.0.2/docs/tutorials → fomtools-0.0.3/docs/tutorials/codegen}/_recorded_timings.json +2 -2
  34. fomtools-0.0.3/docs/tutorials/codegen/control.md +91 -0
  35. fomtools-0.0.3/docs/tutorials/codegen/control.py +294 -0
  36. fomtools-0.0.3/docs/tutorials/codegen/lasso.md +66 -0
  37. fomtools-0.0.3/docs/tutorials/codegen/lasso.py +231 -0
  38. fomtools-0.0.3/docs/tutorials/codegen/network.md +87 -0
  39. fomtools-0.0.3/docs/tutorials/codegen/network.py +305 -0
  40. fomtools-0.0.3/docs/tutorials/codegen/nnls.md +65 -0
  41. fomtools-0.0.3/docs/tutorials/codegen/nnls.py +206 -0
  42. fomtools-0.0.3/docs/tutorials/codegen/portfolio.md +80 -0
  43. fomtools-0.0.3/docs/tutorials/codegen/portfolio.py +259 -0
  44. fomtools-0.0.3/docs/tutorials/codegen.md +45 -0
  45. {fomtools-0.0.2 → fomtools-0.0.3}/docs/tutorials/cvxpygen.md +26 -14
  46. fomtools-0.0.3/docs/tutorials/cvxpygen_mpc.py +188 -0
  47. fomtools-0.0.3/docs/tutorials/helper_functions/codegen_benchmarks.py +144 -0
  48. fomtools-0.0.3/docs/tutorials/helper_functions/control.py +190 -0
  49. fomtools-0.0.3/docs/tutorials/helper_functions/lasso.py +116 -0
  50. fomtools-0.0.3/docs/tutorials/helper_functions/network.py +164 -0
  51. fomtools-0.0.3/docs/tutorials/helper_functions/nnls.py +85 -0
  52. fomtools-0.0.3/docs/tutorials/helper_functions/pepit_runner.py +411 -0
  53. fomtools-0.0.3/docs/tutorials/helper_functions/portfolio.py +94 -0
  54. fomtools-0.0.3/docs/tutorials/index.md +21 -0
  55. fomtools-0.0.3/docs/tutorials/verification/control.py +606 -0
  56. fomtools-0.0.3/docs/tutorials/verification/lasso.py +477 -0
  57. fomtools-0.0.3/docs/tutorials/verification/network.py +656 -0
  58. fomtools-0.0.3/docs/tutorials/verification/nnls.py +591 -0
  59. fomtools-0.0.3/docs/tutorials/verification/portfolio.py +387 -0
  60. fomtools-0.0.3/docs/tutorials/verification.md +29 -0
  61. {fomtools-0.0.2/docs/tutorials → fomtools-0.0.3/docs/user_guide}/codegen.md +42 -15
  62. fomtools-0.0.3/docs/user_guide/index.md +246 -0
  63. fomtools-0.0.3/docs/user_guide/sdp.md +76 -0
  64. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/canonicalizers/canonicalizer.py +10 -9
  65. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/canonicalizers/mip.py +18 -18
  66. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/canonicalizers/obbt_handler.py +4 -4
  67. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/canonicalizers/sdp.py +17 -17
  68. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/canonicalizers/simulator.py +23 -22
  69. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/__init__.py +12 -12
  70. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/__init__.py +10 -10
  71. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/budget.py +1 -1
  72. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/claude_sdk.py +4 -4
  73. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/cli_driver.py +9 -9
  74. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/cli_specs.py +7 -7
  75. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/codex_sdk.py +5 -5
  76. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/driver.py +8 -8
  77. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/pidev_sdk.py +6 -6
  78. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/prompts.py +1 -1
  79. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/sdk_base.py +11 -11
  80. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/stub.py +3 -3
  81. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/cli.py +1 -1
  82. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/config.py +29 -17
  83. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/emit.py +2 -2
  84. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/examples.py +7 -7
  85. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/extract.py +5 -5
  86. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/extract_scheduled.py +10 -10
  87. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/extract_unrolled.py +8 -8
  88. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/factorize.py +3 -3
  89. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/generate.py +13 -13
  90. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/ir.py +26 -26
  91. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/kernel_rules.py +1 -1
  92. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/objective.py +6 -6
  93. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/oracle.py +10 -10
  94. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/postprocess.py +3 -3
  95. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/schedule.py +13 -13
  96. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/spec.py +2 -2
  97. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/targets/base.py +7 -7
  98. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/targets/embedded_c.py +8 -8
  99. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/targets/large_scale_cuda.py +3 -3
  100. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/constraint.py +13 -13
  101. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/cvxpygen/__init__.py +3 -3
  102. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/cvxpygen/api.py +4 -4
  103. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/cvxpygen/builders.py +21 -21
  104. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/cvxpygen/glue.py +2 -2
  105. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/cvxpygen/interface.py +5 -5
  106. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/cvxpygen/qpdata.py +3 -3
  107. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/cvxpygen/scaling.py +1 -1
  108. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/iteratetrajectory.py +5 -5
  109. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/linearexpression.py +3 -3
  110. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/__init__.py +28 -0
  111. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/elastic_net.py +44 -23
  112. fomtools-0.0.3/fomtools/proxable_functions/hinge_loss.py +111 -0
  113. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/huber_loss.py +38 -30
  114. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/ind_affine.py +48 -34
  115. fomtools-0.0.3/fomtools/proxable_functions/ind_ball_l1.py +105 -0
  116. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/ind_ball_linf.py +44 -11
  117. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/ind_box.py +47 -24
  118. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/ind_half_space.py +37 -14
  119. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/ind_nonnegative.py +34 -10
  120. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/ind_nonpositive.py +33 -10
  121. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/ind_point.py +40 -16
  122. fomtools-0.0.3/fomtools/proxable_functions/ind_polyhedral.py +119 -0
  123. fomtools-0.0.3/fomtools/proxable_functions/ind_simplex.py +92 -0
  124. fomtools-0.0.3/fomtools/proxable_functions/labeled_hinge_loss.py +124 -0
  125. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/least_squares.py +35 -21
  126. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/linear.py +30 -17
  127. fomtools-0.0.3/fomtools/proxable_functions/norm_inf.py +120 -0
  128. fomtools-0.0.3/fomtools/proxable_functions/norm_l1.py +143 -0
  129. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/quadratic.py +46 -25
  130. fomtools-0.0.3/fomtools/proxable_functions/soft_nonnegative.py +120 -0
  131. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/sq_l2_norm.py +19 -13
  132. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/sum_negative.py +33 -22
  133. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/sum_positive.py +34 -18
  134. fomtools-0.0.3/fomtools/proxable_functions/total_variation_1d.py +157 -0
  135. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/sets/__init__.py +5 -5
  136. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/sets/affine_subspace.py +3 -3
  137. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/sets/ball.py +4 -4
  138. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/sets/box.py +10 -10
  139. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/sets/polyhedron.py +4 -4
  140. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/sets/set.py +12 -12
  141. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/gurobi.py +15 -15
  142. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/highs.py +16 -16
  143. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/stepdecomposers/sdp_step_decomposer.py +1 -1
  144. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/stepdecomposers/simulator_step_decomposer.py +19 -18
  145. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/stepdecomposers/step_decomposer.py +46 -42
  146. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/steps/affine.py +7 -6
  147. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/steps/lin_prog.py +5 -5
  148. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/steps/quad_prog.py +5 -5
  149. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/steps/relu.py +6 -6
  150. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/steps/saturated_linear.py +6 -6
  151. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/steps/soft_threshold.py +3 -3
  152. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/steps/step.py +6 -6
  153. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/utils/matrix_utils.py +2 -2
  154. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/verifier.py +79 -46
  155. {fomtools-0.0.2 → fomtools-0.0.3/fomtools.egg-info}/PKG-INFO +50 -9
  156. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools.egg-info/SOURCES.txt +51 -12
  157. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools.egg-info/requires.txt +10 -1
  158. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools.egg-info/scm_file_list.json +52 -13
  159. fomtools-0.0.3/fomtools.egg-info/scm_version.json +8 -0
  160. fomtools-0.0.3/mkdocs.yml +112 -0
  161. fomtools-0.0.3/overrides/main.html +11 -0
  162. fomtools-0.0.3/overrides/partials/logo.html +3 -0
  163. {fomtools-0.0.2 → fomtools-0.0.3}/pyproject.toml +12 -1
  164. fomtools-0.0.3/scripts/export_marimo.py +142 -0
  165. {fomtools-0.0.2 → fomtools-0.0.3}/skills/README.md +2 -2
  166. fomtools-0.0.3/tests/test_export_marimo.py +206 -0
  167. {fomtools-0.0.2 → fomtools-0.0.3}/uv.lock +35 -2
  168. fomtools-0.0.2/docs/api/canonicalizer.md +0 -8
  169. fomtools-0.0.2/docs/api/constraint.md +0 -5
  170. fomtools-0.0.2/docs/api/linearexpression.md +0 -1
  171. fomtools-0.0.2/docs/api/proxablefunctions.md +0 -45
  172. fomtools-0.0.2/docs/api/verifier.md +0 -2
  173. fomtools-0.0.2/docs/api.md +0 -11
  174. fomtools-0.0.2/docs/index.md +0 -101
  175. fomtools-0.0.2/docs/installation.md +0 -41
  176. fomtools-0.0.2/docs/tutorials/control.py +0 -343
  177. fomtools-0.0.2/docs/tutorials/cvxpygen_mpc.py +0 -147
  178. fomtools-0.0.2/docs/tutorials/lasso.py +0 -303
  179. fomtools-0.0.2/docs/tutorials/network.py +0 -377
  180. fomtools-0.0.2/docs/tutorials/nnls.py +0 -292
  181. fomtools-0.0.2/docs/tutorials/nnls_verification.py +0 -183
  182. fomtools-0.0.2/docs/tutorials/portfolio.py +0 -290
  183. fomtools-0.0.2/docs/tutorials.md +0 -18
  184. fomtools-0.0.2/fomtools/proxable_functions/hinge_loss.py +0 -72
  185. fomtools-0.0.2/fomtools/proxable_functions/ind_ball_l1.py +0 -67
  186. fomtools-0.0.2/fomtools/proxable_functions/ind_polyhedral.py +0 -86
  187. fomtools-0.0.2/fomtools/proxable_functions/ind_simplex.py +0 -56
  188. fomtools-0.0.2/fomtools/proxable_functions/labeled_hinge_loss.py +0 -74
  189. fomtools-0.0.2/fomtools/proxable_functions/norm_inf.py +0 -80
  190. fomtools-0.0.2/fomtools/proxable_functions/norm_l1.py +0 -109
  191. fomtools-0.0.2/fomtools/proxable_functions/soft_nonnegative.py +0 -85
  192. fomtools-0.0.2/fomtools/proxable_functions/total_variation_1d.py +0 -93
  193. fomtools-0.0.2/fomtools.egg-info/scm_version.json +0 -8
  194. fomtools-0.0.2/mkdocs.yml +0 -53
  195. fomtools-0.0.2/wrangler.toml +0 -5
  196. {fomtools-0.0.2 → fomtools-0.0.3}/.github/workflows/ci.yml +0 -0
  197. {fomtools-0.0.2 → fomtools-0.0.3}/.github/workflows/claude-code-review.yml +0 -0
  198. {fomtools-0.0.2 → fomtools-0.0.3}/.github/workflows/claude.yml +0 -0
  199. {fomtools-0.0.2 → fomtools-0.0.3}/.github/workflows/release.yml +0 -0
  200. {fomtools-0.0.2 → fomtools-0.0.3}/.github/workflows/update-skill.yml +0 -0
  201. {fomtools-0.0.2 → fomtools-0.0.3}/.pre-commit-config.yaml +0 -0
  202. {fomtools-0.0.2 → fomtools-0.0.3}/CLAUDE.md +0 -0
  203. {fomtools-0.0.2 → fomtools-0.0.3}/LICENSE +0 -0
  204. {fomtools-0.0.2 → fomtools-0.0.3}/docs/javascripts/mathjax.js +0 -0
  205. /fomtools-0.0.2/docs/tutorials/codegen_speedup_results.md → /fomtools-0.0.3/docs/tutorials/codegen/speedup_results.md +0 -0
  206. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/__init__.py +0 -0
  207. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/canonicalizers/__init__.py +0 -0
  208. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/agent/agents.yaml +0 -0
  209. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/dedup.py +0 -0
  210. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/harness.py +0 -0
  211. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/targets/__init__.py +0 -0
  212. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/targets/large_scale_openmp.py +0 -0
  213. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/codegen/wrapper.py +0 -0
  214. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/nn/__init__.py +0 -0
  215. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/nn/layers.py +0 -0
  216. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/proxable_functions/proximal_operator.py +0 -0
  217. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/__init__.py +0 -0
  218. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/clarabel.py +0 -0
  219. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/cuclarabel.py +0 -0
  220. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/factory.py +0 -0
  221. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/mip_solver.py +0 -0
  222. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/sdp_solver.py +0 -0
  223. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/solvers/solver.py +0 -0
  224. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/stepdecomposers/__init__.py +0 -0
  225. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/stepdecomposers/mip_step_decomposer.py +0 -0
  226. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/steps/__init__.py +0 -0
  227. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/utils/__init__.py +0 -0
  228. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/utils/convex_hull_cuts.py +0 -0
  229. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/utils/dict_utils.py +0 -0
  230. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/utils/envelopes.py +0 -0
  231. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/utils/math_utils.py +0 -0
  232. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/utils/range_utils.py +0 -0
  233. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools/utils/sparse_utils.py +0 -0
  234. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools.egg-info/dependency_links.txt +0 -0
  235. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools.egg-info/entry_points.txt +0 -0
  236. {fomtools-0.0.2 → fomtools-0.0.3}/fomtools.egg-info/top_level.txt +0 -0
  237. {fomtools-0.0.2 → fomtools-0.0.3}/setup.cfg +0 -0
  238. {fomtools-0.0.2 → fomtools-0.0.3}/skills/fomtools/SKILL.md +0 -0
  239. {fomtools-0.0.2 → fomtools-0.0.3}/skills/fomtools/references/api.md +0 -0
  240. {fomtools-0.0.2 → fomtools-0.0.3}/skills/fomtools/references/codegen.md +0 -0
  241. {fomtools-0.0.2 → fomtools-0.0.3}/skills/fomtools/references/cvxpygen.md +0 -0
  242. {fomtools-0.0.2 → fomtools-0.0.3}/skills/update-prompt.md +0 -0
  243. {fomtools-0.0.2 → fomtools-0.0.3}/tests/__init__.py +0 -0
  244. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/__init__.py +0 -0
  245. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/conftest.py +0 -0
  246. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/boxqp/embedded_c/fom_solver.c +0 -0
  247. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/cgqp/large_scale_cuda/fom_solver.cu +0 -0
  248. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/cgqp/large_scale_openmp/fom_solver.c +0 -0
  249. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/cvxpygen_qp/embedded_c/fom_solver.c +0 -0
  250. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/cvxpygen_qp_objective/embedded_c/fom_solver.c +0 -0
  251. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/dr/embedded_c/fom_solver.c +0 -0
  252. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/fista/embedded_c/fom_solver.c +0 -0
  253. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/fista_objective/embedded_c/fom_solver.c +0 -0
  254. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/halpern/embedded_c/fom_solver.c +0 -0
  255. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/indef_kkt/embedded_c/fom_solver.c +0 -0
  256. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/ista/embedded_c/fom_solver.c +0 -0
  257. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/ista/large_scale_cuda/fom_solver.cu +0 -0
  258. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/ista/large_scale_openmp/fom_solver.c +0 -0
  259. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/ista_objective/embedded_c/fom_solver.c +0 -0
  260. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/ista_objective/large_scale_cuda/fom_solver.cu +0 -0
  261. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/mpc/embedded_c/fom_solver.c +0 -0
  262. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/pdhg_lp/embedded_c/fom_solver.c +0 -0
  263. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/pdhg_lp/large_scale_cuda/fom_solver.cu +0 -0
  264. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/scheduled/embedded_c/fom_solver.c +0 -0
  265. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/scheduled_objective/embedded_c/fom_solver.c +0 -0
  266. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/golden/scheduled_objective/large_scale_cuda/fom_solver.cu +0 -0
  267. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_agent_budget.py +0 -0
  268. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_agent_integration.py +0 -0
  269. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_agent_notes.py +0 -0
  270. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cli.py +0 -0
  271. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_codegen_dispatch.py +0 -0
  272. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_bounds.py +0 -0
  273. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_builders.py +0 -0
  274. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_dispatch.py +0 -0
  275. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_e2e.py +0 -0
  276. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_glue.py +0 -0
  277. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_objective.py +0 -0
  278. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_preflight.py +0 -0
  279. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_qpdata.py +0 -0
  280. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_register.py +0 -0
  281. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_scaling.py +0 -0
  282. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_cvxpygen_scheduled.py +0 -0
  283. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_dedup.py +0 -0
  284. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_dr_pipeline.py +0 -0
  285. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_editable_linsolve.py +0 -0
  286. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_editable_ops.py +0 -0
  287. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_emit_scaffold.py +0 -0
  288. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_examples_scale.py +0 -0
  289. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_factorize.py +0 -0
  290. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_fista_pipeline.py +0 -0
  291. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_float32.py +0 -0
  292. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_indefinite_kkt.py +0 -0
  293. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_ir_extraction.py +0 -0
  294. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_large_scale.py +0 -0
  295. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_objective_termination.py +0 -0
  296. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_oracle.py +0 -0
  297. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_pdhg_pipeline.py +0 -0
  298. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_postprocess.py +0 -0
  299. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_profiling.py +0 -0
  300. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_satlin_mpc.py +0 -0
  301. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_scheduled_ir.py +0 -0
  302. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_scheduled_pipeline.py +0 -0
  303. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_spec_roundtrip.py +0 -0
  304. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_static_constraints.py +0 -0
  305. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_stationarity_gate.py +0 -0
  306. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_stub_pipeline.py +0 -0
  307. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_termination_interval.py +0 -0
  308. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_unrolled_emission.py +0 -0
  309. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_unrolled_ir.py +0 -0
  310. {fomtools-0.0.2 → fomtools-0.0.3}/tests/codegen/test_wrapper_roundtrip.py +0 -0
  311. {fomtools-0.0.2 → fomtools-0.0.3}/tests/conftest.py +0 -0
  312. {fomtools-0.0.2 → fomtools-0.0.3}/tests/cvxpy.py +0 -0
  313. {fomtools-0.0.2 → fomtools-0.0.3}/tests/examples/comparison_lasso.py +0 -0
  314. {fomtools-0.0.2 → fomtools-0.0.3}/tests/examples/cut_experiment.py +0 -0
  315. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_LP_pdhg.py +0 -0
  316. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_add_constraint.py +0 -0
  317. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_affine_simulator.py +0 -0
  318. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_audit_regressions.py +0 -0
  319. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_boxpgd_sdp_mip.py +0 -0
  320. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_complementarity.py +0 -0
  321. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_convex_hull_cuts.py +0 -0
  322. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_copy_isolation.py +0 -0
  323. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_docs_examples.py +0 -0
  324. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_douglas_rachford.py +0 -0
  325. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_fixed_point_ista.py +0 -0
  326. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_fixed_point_nnls.py +0 -0
  327. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_ind_ball_l1.py +0 -0
  328. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_ind_polyhedral.py +0 -0
  329. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_ind_simplex.py +0 -0
  330. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_inf_norm_sdp.py +0 -0
  331. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_infinite_bounds.py +0 -0
  332. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_ista.py +0 -0
  333. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_ista_sdp_mip.py +0 -0
  334. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_iterate_trajectory.py +0 -0
  335. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_l1_obj_norm.py +0 -0
  336. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_linear_program.py +0 -0
  337. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_linearexpression.py +0 -0
  338. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_linsolve_simulator.py +0 -0
  339. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_mincost_flow.py +0 -0
  340. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_mip_solution_consistency.py +0 -0
  341. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_nn_verify_jax.py +0 -0
  342. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_nn_verify_torch.py +0 -0
  343. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_nnls_sdp_mip.py +0 -0
  344. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_norm_inf.py +0 -0
  345. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_obbt_handler.py +0 -0
  346. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_objective_bounds.py +0 -0
  347. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_partial_relu.py +0 -0
  348. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_partial_relu_sdp_sim.py +0 -0
  349. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_placeholder.py +0 -0
  350. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_portfolio.py +0 -0
  351. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_prox_decomposer.py +0 -0
  352. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_quadratic_program.py +0 -0
  353. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_range_functions.py +0 -0
  354. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_relu_simulator.py +0 -0
  355. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_satlin.py +0 -0
  356. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_satlin_simulator.py +0 -0
  357. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sdp_canonicalizer.py +0 -0
  358. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sdp_cuts.py +0 -0
  359. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sdp_hull.py +0 -0
  360. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sdp_inequality.py +0 -0
  361. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sdp_nnls.py +0 -0
  362. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sdp_selector.py +0 -0
  363. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sets.py +0 -0
  364. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_simulator.py +0 -0
  365. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_soft_threshold_simulator.py +0 -0
  366. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_solve_kwargs.py +0 -0
  367. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_solver_boundary.py +0 -0
  368. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sparse_utils.py +0 -0
  369. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_stack.py +0 -0
  370. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_subproblem_simulator.py +0 -0
  371. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_sum_squares.py +0 -0
  372. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_total_variation_1d.py +0 -0
  373. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_two_norm_mip.py +0 -0
  374. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_vec_LUhat.py +0 -0
  375. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_verifier.py +0 -0
  376. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_verifier_ista.py +0 -0
  377. {fomtools-0.0.2 → fomtools-0.0.3}/tests/test_warm_start.py +0 -0
@@ -4,7 +4,7 @@ on:
4
4
  push:
5
5
  branches: [ main ]
6
6
  pull_request:
7
- branches: [ main ]
7
+ branches: [ main, documentation ]
8
8
 
9
9
  permissions:
10
10
  contents: write
@@ -54,13 +54,10 @@ jobs:
54
54
  - name: Export marimo notebooks
55
55
  env:
56
56
  GRB_LICENSE_FILE: ${{ github.workspace }}/gurobi.lic
57
- run: |
58
- for file in docs/tutorials/*.py; do
59
- marimo export html "$file" -o "${file%.py}.html"
60
- done
57
+ run: python scripts/export_marimo.py --force
61
58
 
62
59
  - name: Verify html generation
63
- run: ls docs/tutorials
60
+ run: ls -R docs/tutorials
64
61
 
65
62
  - name: Configure Git Credentials
66
63
  run: |
@@ -79,11 +76,10 @@ jobs:
79
76
  mkdocs-material-
80
77
 
81
78
  - name: Build MkDocs site
82
- run: mkdocs build
79
+ run: mkdocs build --strict
83
80
 
84
- - name: Deploy to Cloudflare Pages with Wrangler
85
- uses: cloudflare/wrangler-action@v4.0.0
86
- with:
87
- apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
88
- accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
89
- command: deploy
81
+ # Pull requests only build the site; pushes to main publish it to the gh-pages
82
+ # branch, which GitHub Pages serves at https://stellatogrp.github.io/fomtools/
83
+ - name: Deploy to GitHub Pages
84
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
85
+ run: mkdocs gh-deploy --force
@@ -385,3 +385,8 @@ fomtools.project
385
385
  __marimo__/
386
386
  *.npz
387
387
  .ruff_cache/
388
+
389
+ .vscode/
390
+
391
+ # `marimo export html` output, generated by the docs workflow at build time.
392
+ docs/tutorials/**/*.html
@@ -82,3 +82,29 @@ execution of the CUDA checks; `FOMTOOLS_CODEGEN_BACKEND` selects the agent.
82
82
  - When the public API or docs change, the `update-skill` workflow refreshes
83
83
  `skills/fomtools/`; check its output rather than editing the skill by hand
84
84
  in the same PR.
85
+
86
+ ## Tutorial math notation
87
+
88
+ All `mo.md` cells in `docs/tutorials/` (verification and codegen notebooks) use one notation per concept, following Boyd-style conventions. Keep new notebooks in sync with this table.
89
+
90
+ | Concept | Write | Never |
91
+ |---|---|---|
92
+ | Reals, ones | `\mathbf{R}`, `\mathbf{R}^n_+`, `\mathbf{1}` | `{\bf R}`, `\R`, `\mathbb{R}` |
93
+ | Transpose | `A^T` | `A^\top` |
94
+ | Calligraphic | `\mathcal{X}` | `{\cal X}` |
95
+ | Problem keywords | `\text{minimize}`, `\text{maximize}`, `\text{subject to}` | `\textnormal{...}` |
96
+ | Delimiters | inline `$...$`, display `$$...$$`, problems and updates as bare `\begin{array}{ll}`/`{rcl}` | `\(...\)`, `\[...\]` |
97
+ | Soft-thresholding | `\mathbf{soft}_{\lambda\eta}` (`soft_threshold` step) | `{\cal T}_\lambda`, `S_\lambda` |
98
+ | Projection | `\Pi_C`: `\Pi_{\mathbf{R}^n_+}` (`relu` step), `\Pi_{[l,u]}` (`satlin` step / `IndBox`) | `\mathbf{ReLU}`, `\mathbf{prox}_{\mathbb{I}_C}` |
99
+ | Proximal operator | `\mathbf{prox}_f` | `\operatorname{prox}` |
100
+
101
+ Norms always carry a subscript: `\|v\|_2`, `\|v\|_\infty` (never `\lVert v \rVert` or a bare `\|v\|`).
102
+ Define soft-thresholding where it is first used: `\mathbf{soft}_\kappa(v)_i = \mathbf{sign}(v_i)\max\{|v_i| - \kappa, 0\}`, applied element-wise.
103
+ Matplotlib labels (`label=`, `xlabel`, `ylabel`, `title`) are rendered by mathtext, not KaTeX: write `\geq`/`\leq` there (mathtext rejects `\ge`/`\le`), and keep `\|v\|_2` norms.
104
+
105
+ Symbol roles: `x` problem parameter in `\mathcal{X}`; `z` decision variable and primal iterate, `z^0 \in \mathcal{Z}`, `z^\star` solution; `v, w` dual or auxiliary iterates; `y` (lasso) or `w` (NNLS) for the un-extrapolated proximal output of a momentum method, matching the helper code; `k` iteration, `K` horizon, `\eta` step size, `L` smoothness constant, `r^k` residual, `R` PEP initial radius.
106
+ Search-box bounds are `x_\mathrm{lb}, x_\mathrm{ub}` and `z^0_\mathrm{lb}, z^0_\mathrm{ub}`; problem-data bounds keep `_{\min}, _{\max}`. Code names such as `x_lb` or `s0_samples` appear only in backticks in prose. When a math letter differs from the code name, say so once.
107
+
108
+ Iterations are written `k \to k+1` for `k = 0, 1, \dots`. A momentum coefficient `\beta_k` uses the same index as the helper code (slot `k` uses `beta_k`, and `k` starts at 1), so the update reads `z^{k+1} = w^{k+1} + \beta_{k+1}(w^{k+1} - w^k)` with `\beta_1 = 0`. Use "Nesterov-type momentum" for `\beta_k = (k-1)/(k+2)` and reserve "FISTA" for the `t_k` schedule `\beta_k = (t_{k-1}-1)/t_k`.
109
+
110
+ Known clashes kept on purpose because both uses are standard: control input `u_t` vs. OSQP upper bound `u(x)`, LQR weight `R` vs. PEP radius `R`, and `\mu` as network cost, portfolio return, or strong-convexity constant.
@@ -0,0 +1,34 @@
1
+ # Contributing to FOMTools
2
+
3
+ ## Development setup
4
+
5
+ Follow the environment instructions in [docs/get_started.md](docs/get_started.md) to create a
6
+ virtual environment and install `fomtools` in editable mode with its `dev` and `docs` extras.
7
+
8
+ Install the pre-commit hooks once per clone:
9
+
10
+ pre-commit install
11
+
12
+ ## Tests and linting
13
+
14
+ pytest # Run the test suite
15
+ ruff check # Check code style
16
+ ruff format # Auto-format
17
+ pre-commit run --all-files # Run all hooks
18
+
19
+ ## Previewing the documentation
20
+
21
+ Install the documentation dependencies and start the local MkDocs server:
22
+
23
+ uv sync --extra docs
24
+ make docs-serve
25
+
26
+ The `docs-serve` target recursively discovers marimo notebooks under `docs/tutorials`, exports
27
+ missing or stale notebooks to ignored HTML files, and then starts MkDocs. Restart the server after
28
+ editing a notebook so that its HTML is refreshed.
29
+
30
+ Use these targets to export or validate the documentation without starting the server:
31
+
32
+ make docs-export # Export only missing or stale notebooks
33
+ make docs-export-force # Regenerate every notebook
34
+ make docs-build # Force export, then run a strict MkDocs build
@@ -0,0 +1,13 @@
1
+ .PHONY: docs-export docs-export-force docs-serve docs-build
2
+
3
+ docs-export:
4
+ uv run --extra docs python scripts/export_marimo.py
5
+
6
+ docs-export-force:
7
+ uv run --extra docs python scripts/export_marimo.py --force
8
+
9
+ docs-serve: docs-export
10
+ uv run --extra docs mkdocs serve
11
+
12
+ docs-build: docs-export-force
13
+ uv run --extra docs mkdocs build --strict
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fomtools
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: FOMTools: A Python Toolbox for Analysis of First-Order Methods
5
5
  Author-email: Vinit Ranjan <vranjan1@mit.edu>, Daniel Deza <dd7022@princeton.edu>, Anushka Acharya <aa9078@princeton.edu>, Jisun Park <jisunpark@princeton.edu>, Bartolomeo Stellato <bstellato@princeton.edu>
6
6
  License: Apache 2.0
@@ -41,22 +41,40 @@ Provides-Extra: nn
41
41
  Requires-Dist: torch; extra == "nn"
42
42
  Requires-Dist: jax<0.11.2; extra == "nn"
43
43
  Requires-Dist: flax; extra == "nn"
44
+ Provides-Extra: all
45
+ Requires-Dist: fomtools[codegen,cvxpygen,gurobi,nn]; extra == "all"
46
+ Requires-Dist: fomtools[gpu]; sys_platform != "darwin" and extra == "all"
47
+ Requires-Dist: fomtools[cuda]; extra == "all"
44
48
  Provides-Extra: docs
45
49
  Requires-Dist: fomtools[gurobi]; extra == "docs"
46
50
  Requires-Dist: marimo; extra == "docs"
47
51
  Requires-Dist: matplotlib; extra == "docs"
48
- Requires-Dist: mkdocs; extra == "docs"
52
+ Requires-Dist: mkdocs<2,>=1.6; extra == "docs"
49
53
  Requires-Dist: mkdocstrings-python; extra == "docs"
50
54
  Requires-Dist: mkdocs-marimo; extra == "docs"
51
55
  Requires-Dist: mkdocs-material; extra == "docs"
56
+ Requires-Dist: networkx; extra == "docs"
57
+ Requires-Dist: pepit; extra == "docs"
52
58
  Requires-Dist: pymdown-extensions; extra == "docs"
53
59
  Dynamic: license-file
54
60
 
55
- FOMTools
56
- ========
61
+ <h1>
62
+ <picture>
63
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/stellatogrp/fomtools/main/docs/assets/logo/logo-dark.svg">
64
+ <img alt="FOMTools" src="https://raw.githubusercontent.com/stellatogrp/fomtools/main/docs/assets/logo/logo.svg" height="72">
65
+ </picture>
66
+ </h1>
67
+
68
+ [![PyPI](https://img.shields.io/pypi/v/fomtools.svg)](https://pypi.org/project/fomtools/)
69
+ [![Docs](https://img.shields.io/badge/docs-stellatogrp.github.io%2Ffomtools-blue.svg)](https://stellatogrp.github.io/fomtools/)
57
70
 
58
71
  **Development, analysis, and code generation for first-order methods.**
59
72
 
73
+ [Documentation](https://stellatogrp.github.io/fomtools/) |
74
+ [PyPI](https://pypi.org/project/fomtools/) |
75
+ [Paper](https://arxiv.org/abs/2610.26743) |
76
+ [Benchmarks](https://github.com/stellatogrp/fomtools_experiments)
77
+
60
78
  FOMTools is an open-source Python package for developing, analyzing, and deploying
61
79
  first-order methods for parametric linear and convex quadratic optimization. You write the
62
80
  iteration in Python, with syntax close to its mathematical description, and FOMTools records
@@ -114,7 +132,7 @@ for k in range(K):
114
132
 
115
133
  Steps can also be written with proximal operators and projections, e.g.,
116
134
  `VP.prox(NormL1(lambd), v, eta)` or `VP.project(Box(l, u), v)`. See the
117
- [documentation](https://github.com/stellatogrp/fomtools/tree/main/docs) for the full list of proxable functions and sets.
135
+ [documentation](https://stellatogrp.github.io/fomtools/) for the full list of proxable functions and sets.
118
136
 
119
137
  ## Beyond worst-case verification
120
138
 
@@ -174,11 +192,26 @@ Optional extras:
174
192
  | `codegen` | LLM coding-agent backends for code generation |
175
193
  | `cvxpygen` | CVXPYgen integration |
176
194
  | `nn` | Neural-network verification (PyTorch, JAX, Flax) |
195
+ | `all` | All of the above (GPU packages skipped on macOS) |
177
196
  | `dev` | Development tools |
178
197
  | `docs` | Documentation build dependencies |
179
198
 
180
199
  For example, `pip install "fomtools[gurobi,codegen]"`, or
181
- `pip install -e ".[gurobi,codegen]"` from source.
200
+ `pip install -e ".[gurobi,codegen]"` from source. Use `pip install "fomtools[all]"`
201
+ to install every optional feature.
202
+
203
+ ### Agent skill
204
+
205
+ FOMTools ships an [Agent Skill](https://agentskills.io/) in
206
+ [`skills/fomtools`](skills/fomtools/SKILL.md) that teaches coding agents (Claude
207
+ Code, Codex, Cursor, and others) the FOMTools API. Install it with the
208
+ [`skills` CLI](https://github.com/vercel-labs/skills) (requires Node.js):
209
+
210
+ ```bash
211
+ npx skills add stellatogrp/fomtools -g
212
+ ```
213
+
214
+ See [Get started](https://stellatogrp.github.io/fomtools/get_started/) for details.
182
215
 
183
216
  FOMTools is not a solver. It relies on mathematical programming solvers such as
184
217
  [HiGHS](https://highs.dev) (the default) and [Gurobi](https://www.gurobi.com) to solve
@@ -186,9 +219,14 @@ the verification problems it builds.
186
219
 
187
220
  ## Examples
188
221
 
189
- The [tutorials](https://github.com/stellatogrp/fomtools/tree/main/docs/tutorials) cover sparse coding (Lasso), nonnegative least squares,
190
- network optimization, optimal control, and portfolio rebalancing. Code to reproduce the
191
- experiments in our [paper](https://arxiv.org/abs/2610.26743) is available at
222
+ The [tutorials](https://stellatogrp.github.io/fomtools/tutorials/) cover sparse coding (Lasso), nonnegative least squares,
223
+ network optimization, optimal control, and portfolio rebalancing.
224
+
225
+ ## Benchmarks
226
+
227
+ The benchmarks and the code to reproduce the experiments in our
228
+ [paper](https://arxiv.org/abs/2610.26743) (verification, simulation, and code generation on
229
+ CPU and GPU) are in a separate repository,
192
230
  [stellatogrp/fomtools_experiments](https://github.com/stellatogrp/fomtools_experiments).
193
231
 
194
232
  ## Contributing
@@ -215,3 +253,6 @@ If you use FOMTools for published work, we encourage you to cite our
215
253
  year = {2026},
216
254
  }
217
255
  ```
256
+
257
+ The mixed-integer verification method is described in
258
+ [Exact Verification of First-Order Methods via Mixed-Integer Linear Programming](https://arxiv.org/abs/2412.11330).
@@ -1,8 +1,20 @@
1
- FOMTools
2
- ========
1
+ <h1>
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/stellatogrp/fomtools/main/docs/assets/logo/logo-dark.svg">
4
+ <img alt="FOMTools" src="https://raw.githubusercontent.com/stellatogrp/fomtools/main/docs/assets/logo/logo.svg" height="72">
5
+ </picture>
6
+ </h1>
7
+
8
+ [![PyPI](https://img.shields.io/pypi/v/fomtools.svg)](https://pypi.org/project/fomtools/)
9
+ [![Docs](https://img.shields.io/badge/docs-stellatogrp.github.io%2Ffomtools-blue.svg)](https://stellatogrp.github.io/fomtools/)
3
10
 
4
11
  **Development, analysis, and code generation for first-order methods.**
5
12
 
13
+ [Documentation](https://stellatogrp.github.io/fomtools/) |
14
+ [PyPI](https://pypi.org/project/fomtools/) |
15
+ [Paper](https://arxiv.org/abs/2610.26743) |
16
+ [Benchmarks](https://github.com/stellatogrp/fomtools_experiments)
17
+
6
18
  FOMTools is an open-source Python package for developing, analyzing, and deploying
7
19
  first-order methods for parametric linear and convex quadratic optimization. You write the
8
20
  iteration in Python, with syntax close to its mathematical description, and FOMTools records
@@ -60,7 +72,7 @@ for k in range(K):
60
72
 
61
73
  Steps can also be written with proximal operators and projections, e.g.,
62
74
  `VP.prox(NormL1(lambd), v, eta)` or `VP.project(Box(l, u), v)`. See the
63
- [documentation](https://github.com/stellatogrp/fomtools/tree/main/docs) for the full list of proxable functions and sets.
75
+ [documentation](https://stellatogrp.github.io/fomtools/) for the full list of proxable functions and sets.
64
76
 
65
77
  ## Beyond worst-case verification
66
78
 
@@ -120,11 +132,26 @@ Optional extras:
120
132
  | `codegen` | LLM coding-agent backends for code generation |
121
133
  | `cvxpygen` | CVXPYgen integration |
122
134
  | `nn` | Neural-network verification (PyTorch, JAX, Flax) |
135
+ | `all` | All of the above (GPU packages skipped on macOS) |
123
136
  | `dev` | Development tools |
124
137
  | `docs` | Documentation build dependencies |
125
138
 
126
139
  For example, `pip install "fomtools[gurobi,codegen]"`, or
127
- `pip install -e ".[gurobi,codegen]"` from source.
140
+ `pip install -e ".[gurobi,codegen]"` from source. Use `pip install "fomtools[all]"`
141
+ to install every optional feature.
142
+
143
+ ### Agent skill
144
+
145
+ FOMTools ships an [Agent Skill](https://agentskills.io/) in
146
+ [`skills/fomtools`](skills/fomtools/SKILL.md) that teaches coding agents (Claude
147
+ Code, Codex, Cursor, and others) the FOMTools API. Install it with the
148
+ [`skills` CLI](https://github.com/vercel-labs/skills) (requires Node.js):
149
+
150
+ ```bash
151
+ npx skills add stellatogrp/fomtools -g
152
+ ```
153
+
154
+ See [Get started](https://stellatogrp.github.io/fomtools/get_started/) for details.
128
155
 
129
156
  FOMTools is not a solver. It relies on mathematical programming solvers such as
130
157
  [HiGHS](https://highs.dev) (the default) and [Gurobi](https://www.gurobi.com) to solve
@@ -132,9 +159,14 @@ the verification problems it builds.
132
159
 
133
160
  ## Examples
134
161
 
135
- The [tutorials](https://github.com/stellatogrp/fomtools/tree/main/docs/tutorials) cover sparse coding (Lasso), nonnegative least squares,
136
- network optimization, optimal control, and portfolio rebalancing. Code to reproduce the
137
- experiments in our [paper](https://arxiv.org/abs/2610.26743) is available at
162
+ The [tutorials](https://stellatogrp.github.io/fomtools/tutorials/) cover sparse coding (Lasso), nonnegative least squares,
163
+ network optimization, optimal control, and portfolio rebalancing.
164
+
165
+ ## Benchmarks
166
+
167
+ The benchmarks and the code to reproduce the experiments in our
168
+ [paper](https://arxiv.org/abs/2610.26743) (verification, simulation, and code generation on
169
+ CPU and GPU) are in a separate repository,
138
170
  [stellatogrp/fomtools_experiments](https://github.com/stellatogrp/fomtools_experiments).
139
171
 
140
172
  ## Contributing
@@ -161,3 +193,6 @@ If you use FOMTools for published work, we encourage you to cite our
161
193
  year = {2026},
162
194
  }
163
195
  ```
196
+
197
+ The mixed-integer verification method is described in
198
+ [Exact Verification of First-Order Methods via Mixed-Integer Linear Programming](https://arxiv.org/abs/2412.11330).
@@ -0,0 +1,38 @@
1
+ # Canonicalizers
2
+
3
+ Canonicalizers translate a verification problem into a solver-ready formulation
4
+ (MIP or SDP), including optimization-based bound tightening (OBBT).
5
+
6
+ ::: fomtools.canonicalizers.Canonicalizer
7
+
8
+ ## MIP canonicalizer
9
+
10
+ ::: fomtools.canonicalizers.mip
11
+ options:
12
+ show_root_heading: false
13
+ show_root_toc_entry: false
14
+ heading_level: 3
15
+
16
+ ## OBBT handler
17
+
18
+ ::: fomtools.canonicalizers.obbt_handler
19
+ options:
20
+ show_root_heading: false
21
+ show_root_toc_entry: false
22
+ heading_level: 3
23
+
24
+ ## Simulator
25
+
26
+ ::: fomtools.canonicalizers.simulator
27
+ options:
28
+ show_root_heading: false
29
+ show_root_toc_entry: false
30
+ heading_level: 3
31
+
32
+ ## SDP canonicalizer
33
+
34
+ ::: fomtools.canonicalizers.sdp
35
+ options:
36
+ show_root_heading: false
37
+ show_root_toc_entry: false
38
+ heading_level: 3
@@ -5,6 +5,10 @@ methods, plus a tiny Python wrapper. An LLM coding agent translates each step of
5
5
  the algorithm into the target language and iterates against a Python reference
6
6
  oracle until the generated code is numerically verified.
7
7
 
8
+ The [code generation guide](../user_guide/codegen.md) is the narrative reference for
9
+ the symbols below, and the [tutorials](../tutorials/codegen.md) work through five
10
+ complete examples.
11
+
8
12
  ::: fomtools.codegen.generate_code
9
13
 
10
14
  ::: fomtools.codegen.CodegenConfig
@@ -0,0 +1,8 @@
1
+ # Constraints
2
+
3
+ Constraints are equalities and inequalities over linear expressions, used to
4
+ encode assumptions on the problem data and the initial conditions.
5
+
6
+ ::: fomtools.constraint.Constraint
7
+ ::: fomtools.constraint.EqualityConstraint
8
+ ::: fomtools.constraint.InequalityConstraint
@@ -0,0 +1,44 @@
1
+ # API and modules
2
+
3
+ The FOMTools API is organized around a single entry point, the
4
+ [`Verifier`](verifier.md), and a set of modules that describe the algorithm
5
+ to be verified, the operators it applies, and the numerical backend used
6
+ to analyze it.
7
+
8
+ A typical workflow is: declare the problem data and iterates on a `Verifier`,
9
+ build up the algorithm from [step operators](steps.md) and
10
+ [proxable functions](proxablefunctions.md), state the assumptions and the
11
+ quantity of interest as [linear expressions](linearexpression.md) and
12
+ [constraints](constraint.md), and then let a
13
+ [canonicalizer](canonicalizer.md) translate everything into a mixed-integer
14
+ program, a semidefinite relaxation, or a sampled simulation; the MIP and SDP
15
+ forms are solved by a [solver](solvers.md) to obtain a worst-case bound.
16
+
17
+ The source code of every module is in the
18
+ [`fomtools` package on GitHub](https://github.com/stellatogrp/fomtools/tree/main/fomtools).
19
+
20
+ ## Modules
21
+
22
+ * **[Verifier](verifier.md)** holds the
23
+ optimization variables and their bounds, applies step operations, propagates
24
+ interval bounds, and drives the canonicalizers and OBBT handlers.
25
+ * **[Linear expressions](linearexpression.md)** are affine expressions
26
+ $Ay + b$ of the leaf variables (parameters, initial iterates, and step
27
+ outputs), with arithmetic and `@` support, used for iterates, objectives, and
28
+ performance measures.
29
+ * **[Constraints](constraint.md)** are equalities and inequalities over
30
+ linear expressions, used to encode assumptions on the problem data and the
31
+ initial conditions.
32
+ * **[Step operators](steps.md)** are the building blocks of a first-order
33
+ method, covering affine steps, ReLU, saturated linear, and soft thresholding.
34
+ * **[Canonicalizers](canonicalizer.md)** translate a verification problem
35
+ into a MIP, an SDP relaxation (experimental), or a sampled simulation,
36
+ including optimization-based bound tightening (OBBT).
37
+ * **[Solvers](solvers.md)** are thin wrappers that put the numerical
38
+ backends, such as Gurobi and HiGHS, behind a common interface.
39
+ * **[Proxable functions](proxablefunctions.md)** are convex functions whose
40
+ proximal operators can be used as steps through `vp.prox`, each supplying a
41
+ numerical prox and the encoding needed by the verification problem. Sets for
42
+ `vp.project` are on the same page.
43
+ * **[Code generation](codegen.md)** emits low-level solver code for a
44
+ verified first-order method, together with a small Python wrapper.
@@ -0,0 +1,6 @@
1
+ # Linear expressions
2
+
3
+ Linear expressions are linear combinations of iterates and function values, with
4
+ arithmetic and `@` support, used to state objectives and performance measures.
5
+
6
+ ::: fomtools.linearexpression.LinearExpression
@@ -0,0 +1,35 @@
1
+ # Proxable functions
2
+
3
+ Proxable functions are convex functions whose proximal operators can be used as
4
+ steps, each supplying a numerical prox and the encoding needed by the
5
+ verification problem. Use `vp.prox(function, arg, gamma=1.0)`; support varies by
6
+ backend, and unsupported operations raise explicitly. They all derive from the
7
+ abstract base class below.
8
+
9
+ ::: fomtools.proxable_functions.ProxableFunction
10
+ options:
11
+ show_root_heading: true
12
+ show_root_toc_entry: true
13
+
14
+ ::: fomtools.proxable_functions
15
+ options:
16
+ show_root_heading: false
17
+ show_root_toc_entry: false
18
+ filters:
19
+ - "!^ProxableFunction$"
20
+
21
+ ## Sets and projections
22
+
23
+ Use `vp.project(set_instance, arg)`.
24
+
25
+ ::: fomtools.sets.Set
26
+ ::: fomtools.sets.Polyhedron
27
+ ::: fomtools.sets.HalfSpace
28
+ ::: fomtools.sets.Simplex
29
+ ::: fomtools.sets.Box
30
+ ::: fomtools.sets.NonNegative
31
+ ::: fomtools.sets.NonPositive
32
+ ::: fomtools.sets.Point
33
+ ::: fomtools.sets.L1Ball
34
+ ::: fomtools.sets.LinfBall
35
+ ::: fomtools.sets.AffineSubspace
@@ -1,4 +1,7 @@
1
- ## Solvers
1
+ # Solvers
2
+
3
+ Solvers are thin wrappers that put the numerical backends, such as Gurobi and
4
+ HiGHS, behind a common interface.
2
5
 
3
6
  ::: fomtools.solvers.Solver
4
7
  ::: fomtools.solvers.gurobi.GurobiSolver
@@ -1,4 +1,7 @@
1
- ## Step Operators
1
+ # Step operators
2
+
3
+ Step operators are the building blocks of a first-order method, covering
4
+ affine steps, ReLU, saturated linear, and soft thresholding.
2
5
 
3
6
  ::: fomtools.steps.step.Step
4
7
  ::: fomtools.steps.affine.Affine
@@ -0,0 +1,7 @@
1
+ # Verifier
2
+
3
+ The verifier holds the optimization variables and their bounds, applies step
4
+ operations, propagates interval bounds, and drives the canonicalizers and OBBT
5
+ handlers.
6
+
7
+ ::: fomtools.Verifier
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-label="FOMTools"><title>FOMTools</title><style>.a{stroke:#2D3748}.b{stroke:#E77500}.c{fill:#E77500}@media (prefers-color-scheme:dark){.a{stroke:#E5E7EB}.b{stroke:#00A6F4}.c{fill:#00A6F4}}</style><path d="M21.5 12 L6 32 L21.5 52 M42.5 12 L58 32 L42.5 52" fill="none" class="a" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.5 21.5 L20 32 L28.5 42.5 M35.5 21.5 L44 32 L35.5 42.5" fill="none" class="b" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="32" cy="32" r="5" class="c"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-label="FOMTools"><title>FOMTools</title><path d="M21.5 12 L6 32 L21.5 52 M42.5 12 L58 32 L42.5 52" fill="none" stroke="#E5E7EB" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.5 21.5 L20 32 L28.5 42.5 M35.5 21.5 L44 32 L35.5 42.5" fill="none" stroke="#00A6F4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="32" cy="32" r="5" fill="#00A6F4"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-label="FOMTools"><title>FOMTools</title><path d="M21.5 12 L6 32 L21.5 52 M42.5 12 L58 32 L42.5 52" fill="none" stroke="#131313" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.5 21.5 L20 32 L28.5 42.5 M35.5 21.5 L44 32 L35.5 42.5" fill="none" stroke="#131313" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="32" cy="32" r="5" fill="#131313"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-label="FOMTools"><title>FOMTools</title><path d="M21.5 12 L6 32 L21.5 52 M42.5 12 L58 32 L42.5 52" fill="none" stroke="#2D3748" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/><path d="M30 21 L20 32 L30 43 M34 21 L44 32 L34 43" fill="none" stroke="#E77500" stroke-width="6.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-label="FOMTools"><title>FOMTools</title><path d="M21.5 12 L6 32 L21.5 52 M42.5 12 L58 32 L42.5 52" fill="none" stroke="#2D3748" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.5 21.5 L20 32 L28.5 42.5 M35.5 21.5 L44 32 L35.5 42.5" fill="none" stroke="#E77500" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="32" cy="32" r="5" fill="#E77500"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 253.93 64" width="253.93" height="64" role="img" aria-label="FOMTools"><title>FOMTools</title><path d="M21.5 12 L6 32 L21.5 52 M42.5 12 L58 32 L42.5 52" fill="none" stroke="#E5E7EB" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.5 21.5 L20 32 L28.5 42.5 M35.5 21.5 L44 32 L35.5 42.5" fill="none" stroke="#00A6F4" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="32" cy="32" r="5" fill="#00A6F4"/><path d="M82.33 46V18H101.16V22.3H87.29V29.95H100.16V34.16H87.29V46ZM116.17 46.45Q112.42 46.45 109.48 44.66Q106.53 42.86 104.83 39.62Q103.13 36.38 103.13 32.02Q103.13 27.64 104.83 24.39Q106.53 21.14 109.48 19.34Q112.42 17.55 116.17 17.55Q119.91 17.55 122.86 19.34Q125.81 21.14 127.52 24.39Q129.22 27.64 129.22 32.02Q129.22 36.38 127.52 39.63Q125.81 42.88 122.86 44.67Q119.91 46.45 116.17 46.45ZM116.17 42Q118.47 42 120.28 40.83Q122.09 39.67 123.15 37.44Q124.2 35.21 124.2 32.02Q124.2 28.81 123.15 26.57Q122.09 24.33 120.28 23.17Q118.47 22 116.17 22Q113.88 22 112.07 23.17Q110.26 24.33 109.19 26.57Q108.13 28.81 108.13 32.02Q108.13 35.21 109.19 37.44Q110.26 39.67 112.07 40.83Q113.88 42 116.17 42ZM132.9 46V18H140.04L145.49 32.71Q145.88 33.88 146.49 35.75Q147.09 37.62 147.58 39.25Q148.06 37.62 148.66 35.75Q149.25 33.88 149.64 32.71L155 18H162.18V46H157.29V31.72Q157.29 30.23 157.35 28.07Q157.4 25.91 157.46 23.77Q156.71 26.14 156.03 28.29Q155.36 30.44 154.9 31.72L149.57 46H145.51L140.13 31.72Q139.7 30.5 139.03 28.46Q138.37 26.42 137.63 24.16Q137.69 26.23 137.74 28.27Q137.79 30.31 137.79 31.72V46Z" fill="#E5E7EB"/><path d="M165.45 21.01V18H187.06V21.01H177.96V46H174.58V21.01ZM194.05 46.45Q191.3 46.45 189.23 45.13Q187.15 43.8 186 41.47Q184.84 39.14 184.84 36.12Q184.84 33.07 186 30.72Q187.15 28.37 189.23 27.04Q191.3 25.7 194.05 25.7Q196.81 25.7 198.88 27.04Q200.94 28.37 202.1 30.72Q203.26 33.07 203.26 36.12Q203.26 39.14 202.1 41.47Q200.94 43.8 198.88 45.13Q196.81 46.45 194.05 46.45ZM194.05 43.56Q196.87 43.56 198.45 41.52Q200.02 39.48 200.02 36.12Q200.02 32.71 198.44 30.66Q196.85 28.6 194.05 28.6Q191.25 28.6 189.66 30.65Q188.07 32.7 188.07 36.12Q188.07 39.5 189.65 41.53Q191.23 43.56 194.05 43.56ZM215.17 46.45Q212.43 46.45 210.35 45.13Q208.27 43.8 207.12 41.47Q205.96 39.14 205.96 36.12Q205.96 33.07 207.12 30.72Q208.27 28.37 210.35 27.04Q212.43 25.7 215.17 25.7Q217.93 25.7 220 27.04Q222.07 28.37 223.22 30.72Q224.38 33.07 224.38 36.12Q224.38 39.14 223.22 41.47Q222.07 43.8 220 45.13Q217.93 46.45 215.17 46.45ZM215.17 43.56Q217.99 43.56 219.57 41.52Q221.15 39.48 221.15 36.12Q221.15 32.71 219.56 30.66Q217.97 28.6 215.17 28.6Q212.37 28.6 210.78 30.65Q209.19 32.7 209.19 36.12Q209.19 39.5 210.77 41.53Q212.35 43.56 215.17 43.56ZM231.29 18V46H228.1V18ZM242.94 46.45Q240.82 46.45 239.09 45.76Q237.36 45.06 236.29 43.64Q235.22 42.22 235.09 40.06H238.25Q238.59 43.71 242.87 43.71Q244.94 43.71 246.13 42.84Q247.32 41.98 247.32 40.66Q247.32 39.54 246.5 38.86Q245.67 38.18 244.34 37.88L241.14 37.13Q235.54 35.81 235.54 31.49Q235.54 29.8 236.45 28.5Q237.36 27.19 238.99 26.45Q240.61 25.7 242.74 25.7Q244.81 25.7 246.45 26.48Q248.09 27.26 249.06 28.69Q250.03 30.12 250.09 32.09H246.97Q246.95 30.52 245.8 29.48Q244.66 28.45 242.74 28.45Q240.92 28.45 239.83 29.33Q238.74 30.21 238.74 31.49Q238.74 32.62 239.56 33.31Q240.39 33.99 241.82 34.33L245.01 35.08Q247.87 35.76 249.2 37.1Q250.54 38.45 250.54 40.59Q250.54 42.43 249.54 43.74Q248.54 45.06 246.83 45.76Q245.11 46.45 242.94 46.45Z" fill="#E5E7EB"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 253.93 64" width="253.93" height="64" role="img" aria-label="FOMTools"><title>FOMTools</title><path d="M21.5 12 L6 32 L21.5 52 M42.5 12 L58 32 L42.5 52" fill="none" stroke="#131313" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.5 21.5 L20 32 L28.5 42.5 M35.5 21.5 L44 32 L35.5 42.5" fill="none" stroke="#131313" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="32" cy="32" r="5" fill="#131313"/><path d="M82.33 46V18H101.16V22.3H87.29V29.95H100.16V34.16H87.29V46ZM116.17 46.45Q112.42 46.45 109.48 44.66Q106.53 42.86 104.83 39.62Q103.13 36.38 103.13 32.02Q103.13 27.64 104.83 24.39Q106.53 21.14 109.48 19.34Q112.42 17.55 116.17 17.55Q119.91 17.55 122.86 19.34Q125.81 21.14 127.52 24.39Q129.22 27.64 129.22 32.02Q129.22 36.38 127.52 39.63Q125.81 42.88 122.86 44.67Q119.91 46.45 116.17 46.45ZM116.17 42Q118.47 42 120.28 40.83Q122.09 39.67 123.15 37.44Q124.2 35.21 124.2 32.02Q124.2 28.81 123.15 26.57Q122.09 24.33 120.28 23.17Q118.47 22 116.17 22Q113.88 22 112.07 23.17Q110.26 24.33 109.19 26.57Q108.13 28.81 108.13 32.02Q108.13 35.21 109.19 37.44Q110.26 39.67 112.07 40.83Q113.88 42 116.17 42ZM132.9 46V18H140.04L145.49 32.71Q145.88 33.88 146.49 35.75Q147.09 37.62 147.58 39.25Q148.06 37.62 148.66 35.75Q149.25 33.88 149.64 32.71L155 18H162.18V46H157.29V31.72Q157.29 30.23 157.35 28.07Q157.4 25.91 157.46 23.77Q156.71 26.14 156.03 28.29Q155.36 30.44 154.9 31.72L149.57 46H145.51L140.13 31.72Q139.7 30.5 139.03 28.46Q138.37 26.42 137.63 24.16Q137.69 26.23 137.74 28.27Q137.79 30.31 137.79 31.72V46Z" fill="#131313"/><path d="M165.45 21.01V18H187.06V21.01H177.96V46H174.58V21.01ZM194.05 46.45Q191.3 46.45 189.23 45.13Q187.15 43.8 186 41.47Q184.84 39.14 184.84 36.12Q184.84 33.07 186 30.72Q187.15 28.37 189.23 27.04Q191.3 25.7 194.05 25.7Q196.81 25.7 198.88 27.04Q200.94 28.37 202.1 30.72Q203.26 33.07 203.26 36.12Q203.26 39.14 202.1 41.47Q200.94 43.8 198.88 45.13Q196.81 46.45 194.05 46.45ZM194.05 43.56Q196.87 43.56 198.45 41.52Q200.02 39.48 200.02 36.12Q200.02 32.71 198.44 30.66Q196.85 28.6 194.05 28.6Q191.25 28.6 189.66 30.65Q188.07 32.7 188.07 36.12Q188.07 39.5 189.65 41.53Q191.23 43.56 194.05 43.56ZM215.17 46.45Q212.43 46.45 210.35 45.13Q208.27 43.8 207.12 41.47Q205.96 39.14 205.96 36.12Q205.96 33.07 207.12 30.72Q208.27 28.37 210.35 27.04Q212.43 25.7 215.17 25.7Q217.93 25.7 220 27.04Q222.07 28.37 223.22 30.72Q224.38 33.07 224.38 36.12Q224.38 39.14 223.22 41.47Q222.07 43.8 220 45.13Q217.93 46.45 215.17 46.45ZM215.17 43.56Q217.99 43.56 219.57 41.52Q221.15 39.48 221.15 36.12Q221.15 32.71 219.56 30.66Q217.97 28.6 215.17 28.6Q212.37 28.6 210.78 30.65Q209.19 32.7 209.19 36.12Q209.19 39.5 210.77 41.53Q212.35 43.56 215.17 43.56ZM231.29 18V46H228.1V18ZM242.94 46.45Q240.82 46.45 239.09 45.76Q237.36 45.06 236.29 43.64Q235.22 42.22 235.09 40.06H238.25Q238.59 43.71 242.87 43.71Q244.94 43.71 246.13 42.84Q247.32 41.98 247.32 40.66Q247.32 39.54 246.5 38.86Q245.67 38.18 244.34 37.88L241.14 37.13Q235.54 35.81 235.54 31.49Q235.54 29.8 236.45 28.5Q237.36 27.19 238.99 26.45Q240.61 25.7 242.74 25.7Q244.81 25.7 246.45 26.48Q248.09 27.26 249.06 28.69Q250.03 30.12 250.09 32.09H246.97Q246.95 30.52 245.8 29.48Q244.66 28.45 242.74 28.45Q240.92 28.45 239.83 29.33Q238.74 30.21 238.74 31.49Q238.74 32.62 239.56 33.31Q240.39 33.99 241.82 34.33L245.01 35.08Q247.87 35.76 249.2 37.1Q250.54 38.45 250.54 40.59Q250.54 42.43 249.54 43.74Q248.54 45.06 246.83 45.76Q245.11 46.45 242.94 46.45Z" fill="#131313"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 253.93 64" width="253.93" height="64" role="img" aria-label="FOMTools"><title>FOMTools</title><path d="M21.5 12 L6 32 L21.5 52 M42.5 12 L58 32 L42.5 52" fill="none" stroke="#2D3748" stroke-width="7.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.5 21.5 L20 32 L28.5 42.5 M35.5 21.5 L44 32 L35.5 42.5" fill="none" stroke="#E77500" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="32" cy="32" r="5" fill="#E77500"/><path d="M82.33 46V18H101.16V22.3H87.29V29.95H100.16V34.16H87.29V46ZM116.17 46.45Q112.42 46.45 109.48 44.66Q106.53 42.86 104.83 39.62Q103.13 36.38 103.13 32.02Q103.13 27.64 104.83 24.39Q106.53 21.14 109.48 19.34Q112.42 17.55 116.17 17.55Q119.91 17.55 122.86 19.34Q125.81 21.14 127.52 24.39Q129.22 27.64 129.22 32.02Q129.22 36.38 127.52 39.63Q125.81 42.88 122.86 44.67Q119.91 46.45 116.17 46.45ZM116.17 42Q118.47 42 120.28 40.83Q122.09 39.67 123.15 37.44Q124.2 35.21 124.2 32.02Q124.2 28.81 123.15 26.57Q122.09 24.33 120.28 23.17Q118.47 22 116.17 22Q113.88 22 112.07 23.17Q110.26 24.33 109.19 26.57Q108.13 28.81 108.13 32.02Q108.13 35.21 109.19 37.44Q110.26 39.67 112.07 40.83Q113.88 42 116.17 42ZM132.9 46V18H140.04L145.49 32.71Q145.88 33.88 146.49 35.75Q147.09 37.62 147.58 39.25Q148.06 37.62 148.66 35.75Q149.25 33.88 149.64 32.71L155 18H162.18V46H157.29V31.72Q157.29 30.23 157.35 28.07Q157.4 25.91 157.46 23.77Q156.71 26.14 156.03 28.29Q155.36 30.44 154.9 31.72L149.57 46H145.51L140.13 31.72Q139.7 30.5 139.03 28.46Q138.37 26.42 137.63 24.16Q137.69 26.23 137.74 28.27Q137.79 30.31 137.79 31.72V46Z" fill="#2D3748"/><path d="M165.45 21.01V18H187.06V21.01H177.96V46H174.58V21.01ZM194.05 46.45Q191.3 46.45 189.23 45.13Q187.15 43.8 186 41.47Q184.84 39.14 184.84 36.12Q184.84 33.07 186 30.72Q187.15 28.37 189.23 27.04Q191.3 25.7 194.05 25.7Q196.81 25.7 198.88 27.04Q200.94 28.37 202.1 30.72Q203.26 33.07 203.26 36.12Q203.26 39.14 202.1 41.47Q200.94 43.8 198.88 45.13Q196.81 46.45 194.05 46.45ZM194.05 43.56Q196.87 43.56 198.45 41.52Q200.02 39.48 200.02 36.12Q200.02 32.71 198.44 30.66Q196.85 28.6 194.05 28.6Q191.25 28.6 189.66 30.65Q188.07 32.7 188.07 36.12Q188.07 39.5 189.65 41.53Q191.23 43.56 194.05 43.56ZM215.17 46.45Q212.43 46.45 210.35 45.13Q208.27 43.8 207.12 41.47Q205.96 39.14 205.96 36.12Q205.96 33.07 207.12 30.72Q208.27 28.37 210.35 27.04Q212.43 25.7 215.17 25.7Q217.93 25.7 220 27.04Q222.07 28.37 223.22 30.72Q224.38 33.07 224.38 36.12Q224.38 39.14 223.22 41.47Q222.07 43.8 220 45.13Q217.93 46.45 215.17 46.45ZM215.17 43.56Q217.99 43.56 219.57 41.52Q221.15 39.48 221.15 36.12Q221.15 32.71 219.56 30.66Q217.97 28.6 215.17 28.6Q212.37 28.6 210.78 30.65Q209.19 32.7 209.19 36.12Q209.19 39.5 210.77 41.53Q212.35 43.56 215.17 43.56ZM231.29 18V46H228.1V18ZM242.94 46.45Q240.82 46.45 239.09 45.76Q237.36 45.06 236.29 43.64Q235.22 42.22 235.09 40.06H238.25Q238.59 43.71 242.87 43.71Q244.94 43.71 246.13 42.84Q247.32 41.98 247.32 40.66Q247.32 39.54 246.5 38.86Q245.67 38.18 244.34 37.88L241.14 37.13Q235.54 35.81 235.54 31.49Q235.54 29.8 236.45 28.5Q237.36 27.19 238.99 26.45Q240.61 25.7 242.74 25.7Q244.81 25.7 246.45 26.48Q248.09 27.26 249.06 28.69Q250.03 30.12 250.09 32.09H246.97Q246.95 30.52 245.8 29.48Q244.66 28.45 242.74 28.45Q240.92 28.45 239.83 29.33Q238.74 30.21 238.74 31.49Q238.74 32.62 239.56 33.31Q240.39 33.99 241.82 34.33L245.01 35.08Q247.87 35.76 249.2 37.1Q250.54 38.45 250.54 40.59Q250.54 42.43 249.54 43.74Q248.54 45.06 246.83 45.76Q245.11 46.45 242.94 46.45Z" fill="#2D3748"/></svg>