prodigy-ppl 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. prodigy/__init__.py +0 -0
  2. prodigy/analysis/__init__.py +36 -0
  3. prodigy/analysis/ai_candidates.py +227 -0
  4. prodigy/analysis/analyzer.py +161 -0
  5. prodigy/analysis/config.py +98 -0
  6. prodigy/analysis/equivalence/__init__.py +9 -0
  7. prodigy/analysis/equivalence/equivalence_check.py +151 -0
  8. prodigy/analysis/evtinvariants/__init__.py +0 -0
  9. prodigy/analysis/evtinvariants/heuristics/__init__.py +0 -0
  10. prodigy/analysis/evtinvariants/heuristics/positivity/__init__.py +0 -0
  11. prodigy/analysis/evtinvariants/heuristics/positivity/dominat_root_rejection.py +58 -0
  12. prodigy/analysis/evtinvariants/heuristics/positivity/heuristics_factory.py +25 -0
  13. prodigy/analysis/evtinvariants/heuristics/positivity/individual_sum_terms.py +31 -0
  14. prodigy/analysis/evtinvariants/heuristics/positivity/iterate_terms.py +39 -0
  15. prodigy/analysis/evtinvariants/heuristics/positivity/logical.py +51 -0
  16. prodigy/analysis/evtinvariants/heuristics/positivity/polynomial_positivity.py +24 -0
  17. prodigy/analysis/evtinvariants/heuristics/positivity/positivity.py +31 -0
  18. prodigy/analysis/evtinvariants/heuristics/positivity/rational_function.py +116 -0
  19. prodigy/analysis/evtinvariants/heuristics/strategies.py +115 -0
  20. prodigy/analysis/evtinvariants/heuristics/templates/__init__.py +0 -0
  21. prodigy/analysis/evtinvariants/heuristics/templates/polynomial_function.py +40 -0
  22. prodigy/analysis/evtinvariants/heuristics/templates/rational_function.py +36 -0
  23. prodigy/analysis/evtinvariants/heuristics/templates/templates.py +13 -0
  24. prodigy/analysis/evtinvariants/heuristics/templates/templates_factory.py +14 -0
  25. prodigy/analysis/evtinvariants/invariant_synthesis.py +100 -0
  26. prodigy/analysis/evtinvariants/invariant_verification.py +95 -0
  27. prodigy/analysis/exceptions.py +26 -0
  28. prodigy/analysis/independence/__init__.py +10 -0
  29. prodigy/analysis/independence/independence.py +170 -0
  30. prodigy/analysis/independence/utils.py +50 -0
  31. prodigy/analysis/instructionhandler/__init__.py +9 -0
  32. prodigy/analysis/instructionhandler/assignment_handler.py +50 -0
  33. prodigy/analysis/instructionhandler/function_handler.py +67 -0
  34. prodigy/analysis/instructionhandler/instruction_handler.py +29 -0
  35. prodigy/analysis/instructionhandler/ite_handler.py +58 -0
  36. prodigy/analysis/instructionhandler/loop_handler.py +36 -0
  37. prodigy/analysis/instructionhandler/observe_handler.py +39 -0
  38. prodigy/analysis/instructionhandler/probchoice_handler.py +38 -0
  39. prodigy/analysis/instructionhandler/program_info.py +28 -0
  40. prodigy/analysis/instructionhandler/query_handler.py +208 -0
  41. prodigy/analysis/instructionhandler/queryblock_handler.py +62 -0
  42. prodigy/analysis/instructionhandler/sample_handler.py +91 -0
  43. prodigy/analysis/instructionhandler/while_handler.py +793 -0
  44. prodigy/analysis/loop_strategies.py +326 -0
  45. prodigy/analysis/lowerbounds/__init__.py +0 -0
  46. prodigy/analysis/lowerbounds/egcalc.py +621 -0
  47. prodigy/analysis/lowerbounds/explicit.py +207 -0
  48. prodigy/analysis/lowerbounds/ir.py +152 -0
  49. prodigy/analysis/lowerbounds/parameters.py +539 -0
  50. prodigy/analysis/lowerbounds/problem.py +168 -0
  51. prodigy/analysis/lowerbounds/sandwich.py +418 -0
  52. prodigy/analysis/lowerbounds/subinvariant.py +207 -0
  53. prodigy/analysis/lowerbounds/synthesis.py +344 -0
  54. prodigy/analysis/optimization/__init__.py +9 -0
  55. prodigy/analysis/optimization/gf_optimizer.py +59 -0
  56. prodigy/analysis/optimization/optimizer.py +32 -0
  57. prodigy/analysis/result.py +628 -0
  58. prodigy/analysis/session.py +846 -0
  59. prodigy/analysis/solver/__init__.py +0 -0
  60. prodigy/analysis/solver/mock_solver.py +29 -0
  61. prodigy/analysis/solver/smtz3_solver.py +131 -0
  62. prodigy/analysis/solver/solver.py +13 -0
  63. prodigy/analysis/solver/solver_type.py +18 -0
  64. prodigy/analysis/solver/sympy_solver.py +65 -0
  65. prodigy/cli.py +587 -0
  66. prodigy/distribution/__init__.py +20 -0
  67. prodigy/distribution/distribution.py +777 -0
  68. prodigy/distribution/fast_generating_function.py +518 -0
  69. prodigy/distribution/generating_function.py +1522 -0
  70. prodigy/distribution/symengine_distribution.py +1142 -0
  71. prodigy/pgcl/LICENSE +202 -0
  72. prodigy/pgcl/NOTICE +9 -0
  73. prodigy/pgcl/__init__.py +49 -0
  74. prodigy/pgcl/ast/__init__.py +138 -0
  75. prodigy/pgcl/ast/ast.py +10 -0
  76. prodigy/pgcl/ast/declarations.py +148 -0
  77. prodigy/pgcl/ast/expressions.py +425 -0
  78. prodigy/pgcl/ast/instructions.py +218 -0
  79. prodigy/pgcl/ast/program.py +145 -0
  80. prodigy/pgcl/ast/types.py +68 -0
  81. prodigy/pgcl/ast/walk.py +170 -0
  82. prodigy/pgcl/check.py +729 -0
  83. prodigy/pgcl/compiler.py +107 -0
  84. prodigy/pgcl/parser.py +615 -0
  85. prodigy/pgcl/pgcl_checks.py +55 -0
  86. prodigy/pgcl/pgcl_operations.py +67 -0
  87. prodigy/pgcl/pysmt/__init__.py +12 -0
  88. prodigy/pgcl/pysmt/context.py +66 -0
  89. prodigy/pgcl/pysmt/expr.py +124 -0
  90. prodigy/pgcl/substitute.py +350 -0
  91. prodigy/pgcl/util/__init__.py +32 -0
  92. prodigy/pgcl/util/lark_expr_parser.py +134 -0
  93. prodigy/pgcl/util/ref.py +166 -0
  94. prodigy/pgfexamples/README.md +48 -0
  95. prodigy/pgfexamples/equivalence/loop_free/bernoulli.pgcl +4 -0
  96. prodigy/pgfexamples/equivalence/loop_free/bernoulli2.pgcl +4 -0
  97. prodigy/pgfexamples/equivalence/loop_free/dice_sampling.pgcl +9 -0
  98. prodigy/pgfexamples/equivalence/loop_free/dice_sampling2.pgcl +11 -0
  99. prodigy/pgfexamples/equivalence/loop_free/uniform_sampling.pgcl +4 -0
  100. prodigy/pgfexamples/equivalence/loop_free/uniform_sampling2.pgcl +12 -0
  101. prodigy/pgfexamples/equivalence/loopy/17_die_even.pgcl +11 -0
  102. prodigy/pgfexamples/equivalence/loopy/bit_flip_conditioning.pgcl +17 -0
  103. prodigy/pgfexamples/equivalence/loopy/condand.pgcl +10 -0
  104. prodigy/pgfexamples/equivalence/loopy/dep_bern.pgcl +12 -0
  105. prodigy/pgfexamples/equivalence/loopy/endless_conditioning.pgcl +7 -0
  106. prodigy/pgfexamples/equivalence/loopy/geometric.pgcl +9 -0
  107. prodigy/pgfexamples/equivalence/loopy/geometric_observe.pgcl +11 -0
  108. prodigy/pgfexamples/equivalence/loopy/geometric_shifted.pgcl +10 -0
  109. prodigy/pgfexamples/equivalence/loopy/invariants/17_die_even_invariant.pgcl +15 -0
  110. prodigy/pgfexamples/equivalence/loopy/invariants/bit_flip_conditioning_invariant.pgcl +33 -0
  111. prodigy/pgfexamples/equivalence/loopy/invariants/condand_invariant.pgcl +16 -0
  112. prodigy/pgfexamples/equivalence/loopy/invariants/dep_bern_invariant.pgcl +15 -0
  113. prodigy/pgfexamples/equivalence/loopy/invariants/endless_conditioning_invariant.pgcl +6 -0
  114. prodigy/pgfexamples/equivalence/loopy/invariants/geometric_invariant.pgcl +11 -0
  115. prodigy/pgfexamples/equivalence/loopy/invariants/geometric_observe_invariant.pgcl +12 -0
  116. prodigy/pgfexamples/equivalence/loopy/invariants/geometric_shifted_invariant.pgcl +12 -0
  117. prodigy/pgfexamples/equivalence/loopy/invariants/ky_die_2_invariant.pgcl +20 -0
  118. prodigy/pgfexamples/equivalence/loopy/invariants/ky_die_invariant.pgcl +38 -0
  119. prodigy/pgfexamples/equivalence/loopy/invariants/n_geometric_invariant.pgcl +11 -0
  120. prodigy/pgfexamples/equivalence/loopy/invariants/nested_while_invariant1.pgcl +16 -0
  121. prodigy/pgfexamples/equivalence/loopy/invariants/nested_while_invariant2.pgcl +11 -0
  122. prodigy/pgfexamples/equivalence/loopy/invariants/random_walk_invariant.pgcl +13 -0
  123. prodigy/pgfexamples/equivalence/loopy/invariants/rejection_sampling_invariant.pgcl +7 -0
  124. prodigy/pgfexamples/equivalence/loopy/invariants/running_paper_example_invariant.pgcl +11 -0
  125. prodigy/pgfexamples/equivalence/loopy/invariants/sequential_loops_invariant1.pgcl +12 -0
  126. prodigy/pgfexamples/equivalence/loopy/invariants/sequential_loops_invariant2.pgcl +13 -0
  127. prodigy/pgfexamples/equivalence/loopy/invariants/skip_rejection_sampling_invariant.pgcl +7 -0
  128. prodigy/pgfexamples/equivalence/loopy/invariants/trivial_iid_invariant.pgcl +11 -0
  129. prodigy/pgfexamples/equivalence/loopy/ky_die.pgcl +35 -0
  130. prodigy/pgfexamples/equivalence/loopy/ky_die_2.pgcl +19 -0
  131. prodigy/pgfexamples/equivalence/loopy/n_geometric.pgcl +9 -0
  132. prodigy/pgfexamples/equivalence/loopy/nested_while.pgcl +15 -0
  133. prodigy/pgfexamples/equivalence/loopy/random_walk.pgcl +10 -0
  134. prodigy/pgfexamples/equivalence/loopy/running_paper_example.pgcl +9 -0
  135. prodigy/pgfexamples/equivalence/loopy/sequential_loops.pgcl +17 -0
  136. prodigy/pgfexamples/equivalence/loopy/skip_rejection_sampling.pgcl +6 -0
  137. prodigy/pgfexamples/equivalence/loopy/trivial_iid.pgcl +12 -0
  138. prodigy/pgfexamples/independence/fuzzy_or.pgcl +47 -0
  139. prodigy/pgfexamples/independence/infinite_multiplication.pgcl +11 -0
  140. prodigy/pgfexamples/independence/many_variables.pgcl +72 -0
  141. prodigy/pgfexamples/independence/modgrade_fullyisolated.pgcl +26 -0
  142. prodigy/pgfexamples/independence/oblivious_transfer.pgcl +53 -0
  143. prodigy/pgfexamples/independence/private_information_retriveal.pgcl +68 -0
  144. prodigy/pgfexamples/independence/twocoins_fail.pgcl +10 -0
  145. prodigy/pgfexamples/inference/loop_free/conditioning/burgler_alarm.pgcl +36 -0
  146. prodigy/pgfexamples/inference/loop_free/conditioning/caesar.pgcl +25 -0
  147. prodigy/pgfexamples/inference/loop_free/conditioning/conditioning_divergence.pgcl +10 -0
  148. prodigy/pgfexamples/inference/loop_free/conditioning/digitRecognition.pgcl +15755 -0
  149. prodigy/pgfexamples/inference/loop_free/conditioning/evidence1.pgcl +10 -0
  150. prodigy/pgfexamples/inference/loop_free/conditioning/evidence2.pgcl +15 -0
  151. prodigy/pgfexamples/inference/loop_free/conditioning/grass.pgcl +31 -0
  152. prodigy/pgfexamples/inference/loop_free/conditioning/infer_geom_mix.pgcl +27 -0
  153. prodigy/pgfexamples/inference/loop_free/conditioning/lin_regression_unbiased.pgcl +25 -0
  154. prodigy/pgfexamples/inference/loop_free/conditioning/lucky_throw.pgcl +19 -0
  155. prodigy/pgfexamples/inference/loop_free/conditioning/monty_hall_nested.pgcl +20 -0
  156. prodigy/pgfexamples/inference/loop_free/conditioning/murder_mystery.pgcl +16 -0
  157. prodigy/pgfexamples/inference/loop_free/conditioning/skip_lin_regression_biased.pgcl +25 -0
  158. prodigy/pgfexamples/inference/loop_free/conditioning/telephone_operator.pgcl +19 -0
  159. prodigy/pgfexamples/inference/loop_free/conditioning/twocoins.pgcl +17 -0
  160. prodigy/pgfexamples/inference/loop_free/conditioning/undefined_normalization.pgcl +4 -0
  161. prodigy/pgfexamples/inference/loop_free/dnd_handicap.pgcl +39 -0
  162. prodigy/pgfexamples/inference/loop_free/function.pgcl +7 -0
  163. prodigy/pgfexamples/inference/loop_free/fuzzy_or.pgcl +48 -0
  164. prodigy/pgfexamples/inference/loop_free/max.pgcl +24 -0
  165. prodigy/pgfexamples/inference/loop_free/monty_hall.pgcl +69 -0
  166. prodigy/pgfexamples/inference/loop_free/pi.pgcl +7 -0
  167. prodigy/pgfexamples/inference/loop_free/piranha.pgcl +22 -0
  168. prodigy/pgfexamples/inference/loop_free/poor_scale.pgcl +8 -0
  169. prodigy/pgfexamples/inference/loop_free/prob_collatz.pgcl +12 -0
  170. prodigy/pgfexamples/inference/loop_free/scalability.pgcl +9 -0
  171. prodigy/pgfexamples/inference/loopy/conditioning/dep_bern.pgcl +14 -0
  172. prodigy/pgfexamples/inference/loopy/conditioning/trivial_iid.pgcl +13 -0
  173. prodigy/pgfexamples/inference/loopy/skip_exceeding_sum.pgcl +13 -0
  174. prodigy/pgfexamples/inference/loopy/skip_geom_dist.pgcl +10 -0
  175. prodigy/pgfexamples/inference/loopy/skip_random_walk.pgcl +15 -0
  176. prodigy/pgfexamples/inference/loopy/uniform_sampling.pgcl +30 -0
  177. prodigy/pgfexamples/invariant_synthesis/cond_and.pgcl +7 -0
  178. prodigy/pgfexamples/invariant_synthesis/dueling_cowboys.pgcl +15 -0
  179. prodigy/pgfexamples/invariant_synthesis/fast_dice_roller.pgcl +35 -0
  180. prodigy/pgfexamples/invariant_synthesis/faulty_decrement.pgcl +7 -0
  181. prodigy/pgfexamples/invariant_synthesis/geometric.pgcl +7 -0
  182. prodigy/pgfexamples/invariant_synthesis/geometric_counter.pgcl +8 -0
  183. prodigy/pgfexamples/invariant_synthesis/modulo_geometric.pgcl +10 -0
  184. prodigy/pgfexamples/invariant_synthesis/nontermination.pgcl +8 -0
  185. prodigy/pgfexamples/invariant_synthesis/random_walk.pgcl +7 -0
  186. prodigy/pgfexamples/invariant_synthesis/random_walk_counter.pgcl +13 -0
  187. prodigy/pgfexamples/invariant_synthesis/skip_sequential_loops.pgcl +12 -0
  188. prodigy/pgfexamples/invariant_synthesis/subdist_enter.pgcl +7 -0
  189. prodigy/pgfexamples/invariant_synthesis/thirds_geometric.pgcl +22 -0
  190. prodigy/pgfexamples/lower_bounds/conditioning/README.md +6 -0
  191. prodigy/pgfexamples/lower_bounds/conditioning/noisy_geometric.pgcl +16 -0
  192. prodigy/pgfexamples/lower_bounds/conditioning/rw_counter_observe.pgcl +20 -0
  193. prodigy/pgfexamples/lower_bounds/exact/coupon_collector.pgcl +18 -0
  194. prodigy/pgfexamples/lower_bounds/exact/dueling_cowboys.pgcl +14 -0
  195. prodigy/pgfexamples/lower_bounds/exact/escape_counter.pgcl +12 -0
  196. prodigy/pgfexamples/lower_bounds/exact/fast_dice_roller.pgcl +35 -0
  197. prodigy/pgfexamples/lower_bounds/exact/faulty_decrement.pgcl +6 -0
  198. prodigy/pgfexamples/lower_bounds/exact/gamblers_ruin_counter.pgcl +11 -0
  199. prodigy/pgfexamples/lower_bounds/exact/geometric.pgcl +6 -0
  200. prodigy/pgfexamples/lower_bounds/exact/geometric_counter.pgcl +7 -0
  201. prodigy/pgfexamples/lower_bounds/exact/hark_counterexample.pgcl +14 -0
  202. prodigy/pgfexamples/lower_bounds/exact/lossy_retransmission.pgcl +12 -0
  203. prodigy/pgfexamples/lower_bounds/exact/modulo_geometric.pgcl +9 -0
  204. prodigy/pgfexamples/lower_bounds/exact/nontermination.pgcl +6 -0
  205. prodigy/pgfexamples/lower_bounds/exact/random_walk.pgcl +6 -0
  206. prodigy/pgfexamples/lower_bounds/exact/random_walk_counter.pgcl +12 -0
  207. prodigy/pgfexamples/lower_bounds/exact/subdist_enter.pgcl +6 -0
  208. prodigy/pgfexamples/lower_bounds/exact/thirds_geometric.pgcl +21 -0
  209. prodigy/pgfexamples/lower_bounds/sandwich/escape_counter.pgcl +13 -0
  210. prodigy/pgfexamples/lower_bounds/sandwich/escape_noisy.pgcl +13 -0
  211. prodigy/pgfexamples/lower_bounds/sandwich/escape_walk.pgcl +10 -0
  212. prodigy/pgfexamples/lower_bounds/sandwich/jump_counter.pgcl +13 -0
  213. prodigy/pgfexamples/lower_bounds/sandwich/quadrant_drift.pgcl +12 -0
  214. prodigy/pgfexamples/lower_bounds/sandwich/quadrant_timeout.pgcl +14 -0
  215. prodigy/pgfexamples/lower_bounds/sandwich/rw_counter_1120.pgcl +12 -0
  216. prodigy/pgfexamples/lower_bounds/sandwich/rw_counter_23.pgcl +15 -0
  217. prodigy/pgfexamples/lower_bounds/sandwich/rw_counter_35.pgcl +12 -0
  218. prodigy/pgfexamples/lower_bounds/sandwich/symmetric_noisy.pgcl +14 -0
  219. prodigy/pgfexamples/template_parameter_synthesis/bit_flip_conditioning_generalized_parameter.pgcl +18 -0
  220. prodigy/pgfexamples/template_parameter_synthesis/bit_flip_conditioning_parameter.pgcl +17 -0
  221. prodigy/pgfexamples/template_parameter_synthesis/brp_obs_parameter.pgcl +13 -0
  222. prodigy/pgfexamples/template_parameter_synthesis/dueling_cowboys_parameter.pgcl +13 -0
  223. prodigy/pgfexamples/template_parameter_synthesis/geometric_observe_parameter.pgcl +12 -0
  224. prodigy/pgfexamples/template_parameter_synthesis/geometric_parameter.pgcl +9 -0
  225. prodigy/pgfexamples/template_parameter_synthesis/invariants/bit_flip_conditioning_generalized_parameter_invariant.pgcl +34 -0
  226. prodigy/pgfexamples/template_parameter_synthesis/invariants/bit_flip_conditioning_parameter_invariant.pgcl +36 -0
  227. prodigy/pgfexamples/template_parameter_synthesis/invariants/brp_obs_parameter_invariant.pgcl +47 -0
  228. prodigy/pgfexamples/template_parameter_synthesis/invariants/dueling_cowboys_parameter_invariant.pgcl +19 -0
  229. prodigy/pgfexamples/template_parameter_synthesis/invariants/geometric_observe_parameter_invariant.pgcl +12 -0
  230. prodigy/pgfexamples/template_parameter_synthesis/invariants/geometric_parameter_invariant.pgcl +12 -0
  231. prodigy/pgfexamples/template_parameter_synthesis/invariants/ky_die_parameter_invariant.pgcl +40 -0
  232. prodigy/pgfexamples/template_parameter_synthesis/invariants/n_geometric_parameter_invariant.pgcl +12 -0
  233. prodigy/pgfexamples/template_parameter_synthesis/invariants/negative_binomial_parameter_invariant.pgcl +13 -0
  234. prodigy/pgfexamples/template_parameter_synthesis/invariants/negative_binomial_reversed_parameter_invariant.pgcl +13 -0
  235. prodigy/pgfexamples/template_parameter_synthesis/invariants/random_walk_parameter_invariant.pgcl +13 -0
  236. prodigy/pgfexamples/template_parameter_synthesis/ky_die_parameter.pgcl +35 -0
  237. prodigy/pgfexamples/template_parameter_synthesis/n_geometric_parameter.pgcl +10 -0
  238. prodigy/pgfexamples/template_parameter_synthesis/negative_binomial_parameter.pgcl +14 -0
  239. prodigy/pgfexamples/template_parameter_synthesis/negative_binomial_reversed_parameter.pgcl +14 -0
  240. prodigy/pgfexamples/template_parameter_synthesis/random_walk_parameter.pgcl +11 -0
  241. prodigy/pgfexamples/template_parameter_synthesis/telephone_operator_parameter.pgcl +19 -0
  242. prodigy/util/__init__.py +89 -0
  243. prodigy/util/color.py +19 -0
  244. prodigy/util/logger.py +39 -0
  245. prodigy/util/order.py +30 -0
  246. prodigy/util/plotter.py +172 -0
  247. prodigy/web/__init__.py +0 -0
  248. prodigy/web/app.py +199 -0
  249. prodigy/web/diagnostics.py +211 -0
  250. prodigy/web/examples.py +189 -0
  251. prodigy/web/frontend/README.md +15 -0
  252. prodigy/web/frontend/build.mjs +35 -0
  253. prodigy/web/frontend/codemirror-entry.js +64 -0
  254. prodigy/web/frontend/package-lock.json +657 -0
  255. prodigy/web/frontend/package.json +21 -0
  256. prodigy/web/jobs.py +316 -0
  257. prodigy/web/requests.py +109 -0
  258. prodigy/web/static/app/api.js +45 -0
  259. prodigy/web/static/app/app.css +485 -0
  260. prodigy/web/static/app/components/charts.js +133 -0
  261. prodigy/web/static/app/components/dom.js +71 -0
  262. prodigy/web/static/app/components/format.js +106 -0
  263. prodigy/web/static/app/components/math.js +20 -0
  264. prodigy/web/static/app/components/result-view.css +181 -0
  265. prodigy/web/static/app/components/result-view.js +495 -0
  266. prodigy/web/static/app/document.js +283 -0
  267. prodigy/web/static/app/editor.js +244 -0
  268. prodigy/web/static/app/library.js +100 -0
  269. prodigy/web/static/app/main.js +544 -0
  270. prodigy/web/static/app/setup.js +283 -0
  271. prodigy/web/static/app/store.js +20 -0
  272. prodigy/web/static/vendor/codemirror.js +13 -0
  273. prodigy/web/static/vendor/katex/LICENSE +21 -0
  274. prodigy/web/static/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  275. prodigy/web/static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  276. prodigy/web/static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  277. prodigy/web/static/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  278. prodigy/web/static/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  279. prodigy/web/static/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  280. prodigy/web/static/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  281. prodigy/web/static/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  282. prodigy/web/static/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  283. prodigy/web/static/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  284. prodigy/web/static/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  285. prodigy/web/static/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  286. prodigy/web/static/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  287. prodigy/web/static/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  288. prodigy/web/static/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  289. prodigy/web/static/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  290. prodigy/web/static/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  291. prodigy/web/static/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  292. prodigy/web/static/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  293. prodigy/web/static/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  294. prodigy/web/static/vendor/katex/katex.min.css +1 -0
  295. prodigy/web/static/vendor/katex/katex.min.js +1 -0
  296. prodigy/web/templates/app.html +124 -0
  297. prodigy_ppl-0.1.0.dist-info/METADATA +120 -0
  298. prodigy_ppl-0.1.0.dist-info/RECORD +301 -0
  299. prodigy_ppl-0.1.0.dist-info/WHEEL +4 -0
  300. prodigy_ppl-0.1.0.dist-info/entry_points.txt +2 -0
  301. prodigy_ppl-0.1.0.dist-info/licenses/LICENSE +201 -0
prodigy/__init__.py ADDED
File without changes
@@ -0,0 +1,36 @@
1
+ """
2
+ ================
3
+ Forward Analysis
4
+ ================
5
+
6
+ The semantics transformation of the forwards analysis is mainly specified in the instruction handlers. They provide
7
+ the actual semantics on a generic level without knowing any specific encoding of a probability distribution.
8
+
9
+ The Semantics
10
+ #############
11
+
12
+ The semantics of a probabilistic program is defined as a distribution transformer. Each individual program instruction
13
+ is handled via a dedicated instruction handler. These handlers describe on a generic level, how the input distribution
14
+ is changed after executing the program instruction. This is oftentimes not computable, i.e., when the input distribution
15
+ has infinite support, or in case of while-loop instructions.
16
+
17
+ Distribution
18
+ ############
19
+
20
+ Distributions are the core objects to transform by a probabilistic program. This class specifies a generic interface
21
+ with desired convenience methods needed, in order to abstract away from an actual distribution encoding.
22
+ In fact, we deliver two types of distribution backends:
23
+
24
+ #. A `sympy` implementation of generating functions
25
+ #. A `GiNaC` C++ implementation shipped as a `pybind11` module.
26
+
27
+ .. automodule:: prodigy.distribution
28
+
29
+ Analysis Configuration
30
+ ######################
31
+
32
+ Sometimes, intermediate steps of the computation are desired. This and more configurations can be setup in a
33
+ `ForwardAnalysisConfig` object. Here also different backend Engines can be chosen.
34
+
35
+ .. automodule:: prodigy.analysis.config
36
+ """
@@ -0,0 +1,227 @@
1
+ """
2
+ Loop invariants proposed by a language model and checked by Prodigy.
3
+
4
+ The model only proposes candidates. Every candidate goes through the same exact check as an
5
+ invariant typed in by hand (strategies ``evt_invariant`` and ``evt_subinvariant``), so a wrong
6
+ answer makes an attempt fail but never makes a result unsound. When a candidate is rejected, the
7
+ next request tells the model why (e.g. Φ(I) − I), so it can correct itself.
8
+
9
+ Answers are untrusted input. Before any computer algebra system sees a candidate (SymPy's parser
10
+ evaluates Python code), it must consist of numbers, the program's variables and parameters,
11
+ ``+ - * / ^``, parentheses, ``sqrt`` and ``exp``, and parse as a pGCL expression.
12
+
13
+ Configuration, read from the environment of ``prodigy`` (it never reaches the browser):
14
+
15
+ * ``ANTHROPIC_API_KEY``: Claude API, model ``PRODIGY_AI_MODEL`` (default ``claude-sonnet-5-5``);
16
+ ``ANTHROPIC_WORKSPACE_ID`` for a key that is not scoped to a workspace.
17
+ * ``OPENAI_API_KEY`` and/or ``PRODIGY_AI_BASE_URL`` with ``PRODIGY_AI_MODEL``: an OpenAI-compatible
18
+ chat-completions API, e.g. ``http://localhost:11434/v1`` for a local model served by Ollama.
19
+ * ``PRODIGY_AI_PROVIDER`` (``anthropic`` or ``openai``) chooses if both are configured;
20
+ ``PRODIGY_AI_TIMEOUT``: seconds per request (default 120).
21
+ """
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ import os
26
+ import re
27
+ import urllib.error
28
+ import urllib.request
29
+ from dataclasses import dataclass, field
30
+ from typing import Any, Callable, Dict, Mapping, Optional, Sequence, Tuple
31
+
32
+ from prodigy.pgcl.parser import parse_expr
33
+
34
+ DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-5-5"
35
+ ANTHROPIC_URL = "https://api.anthropic.com/v1/messages"
36
+ ANTHROPIC_VERSION = "2026-10-21"
37
+ FUNCTIONS = frozenset({"sqrt", "exp"})
38
+ FORMS = ("evt_invariant", "evt_subinvariant")
39
+
40
+
41
+ class AIConfigurationError(Exception):
42
+ """No language model is configured, or its configuration is incomplete."""
43
+
44
+
45
+ class AIRequestError(Exception):
46
+ """The request to the language model failed."""
47
+
48
+
49
+ class CandidateError(ValueError):
50
+ """An answer contains no admissible candidate."""
51
+
52
+
53
+ @dataclass(frozen=True)
54
+ class Provider:
55
+ name: str
56
+ model: str
57
+ ask: Callable[[str, str], str]
58
+ """(system prompt, user prompt) -> text of the answer"""
59
+ diagnostics: Dict[str, Any] = field(default_factory=dict)
60
+ """Why the last answer ended (``stop_reason``) and the kinds of its content blocks."""
61
+
62
+
63
+ def _post(url: str, headers: Dict[str, str], body: Dict[str, Any], timeout: float) -> Dict[str, Any]:
64
+ request = urllib.request.Request(url, data=json.dumps(body).encode("utf-8"), method="POST",
65
+ headers={"content-type": "application/json", **headers})
66
+ try:
67
+ with urllib.request.urlopen(request, timeout=timeout) as response:
68
+ return json.loads(response.read().decode("utf-8"))
69
+ except urllib.error.HTTPError as exc:
70
+ detail = exc.read().decode("utf-8", errors="replace")[:500]
71
+ raise AIRequestError(f"{url} answered {exc.code}: {detail}") from exc
72
+ except (urllib.error.URLError, OSError) as exc:
73
+ raise AIRequestError(f"{url} could not be reached: {exc}") from exc
74
+
75
+
76
+ def get_provider(env: Optional[Mapping[str, str]] = None) -> Provider:
77
+ """The configured language model (see the module documentation)."""
78
+ env = os.environ if env is None else env
79
+ choice = env.get("PRODIGY_AI_PROVIDER", "").strip().lower()
80
+ if not choice:
81
+ if env.get("ANTHROPIC_API_KEY"):
82
+ choice = "anthropic"
83
+ elif env.get("OPENAI_API_KEY") or env.get("PRODIGY_AI_BASE_URL"):
84
+ choice = "openai"
85
+ timeout = float(env.get("PRODIGY_AI_TIMEOUT") or 120)
86
+ if choice == "anthropic":
87
+ return _anthropic(env, timeout)
88
+ if choice == "openai":
89
+ return _openai(env, timeout)
90
+ if choice:
91
+ raise AIConfigurationError(f"Unknown PRODIGY_AI_PROVIDER {choice!r} (anthropic or openai).")
92
+ raise AIConfigurationError(
93
+ "No language model is configured. Set ANTHROPIC_API_KEY (Claude API), or OPENAI_API_KEY or "
94
+ "PRODIGY_AI_BASE_URL together with PRODIGY_AI_MODEL (OpenAI-compatible API, e.g. a local model) "
95
+ "in the environment of prodigy, and start it again.")
96
+
97
+
98
+ def _anthropic(env: Mapping[str, str], timeout: float) -> Provider:
99
+ key = env.get("ANTHROPIC_API_KEY")
100
+ if not key:
101
+ raise AIConfigurationError("PRODIGY_AI_PROVIDER=anthropic needs ANTHROPIC_API_KEY.")
102
+ model = env.get("PRODIGY_AI_MODEL") or DEFAULT_ANTHROPIC_MODEL
103
+ headers = {"authorization": f"Bearer {key}", "anthropic-version": ANTHROPIC_VERSION}
104
+ if env.get("ANTHROPIC_WORKSPACE_ID"):
105
+ headers["anthropic-workspace-id"] = env["ANTHROPIC_WORKSPACE_ID"]
106
+
107
+ diagnostics: Dict[str, Any] = {}
108
+
109
+ def ask(system: str, user: str) -> str:
110
+ # room for the model's reasoning; only the tokens used are billed
111
+ reply = _post(ANTHROPIC_URL, headers, {"model": model, "max_tokens": 16000, "system": system,
112
+ "messages": [{"role": "user", "content": user}]}, timeout)
113
+ blocks = reply.get("content") or []
114
+ diagnostics.clear()
115
+ diagnostics.update(stop_reason=reply.get("stop_reason"), content=[b.get("type") for b in blocks])
116
+ return "".join(block.get("text", "") for block in blocks if block.get("type") == "text")
117
+
118
+ return Provider("anthropic", model, ask, diagnostics)
119
+
120
+
121
+ def _openai(env: Mapping[str, str], timeout: float) -> Provider:
122
+ model = env.get("PRODIGY_AI_MODEL")
123
+ if not model:
124
+ raise AIConfigurationError("An OpenAI-compatible API needs PRODIGY_AI_MODEL (the name of the model).")
125
+ url = (env.get("PRODIGY_AI_BASE_URL") or "https://api.openai.com/v1").rstrip("/") + "/chat/completions"
126
+ headers = {"authorization": f"Bearer {env['OPENAI_API_KEY']}"} if env.get("OPENAI_API_KEY") else {}
127
+
128
+ diagnostics: Dict[str, Any] = {}
129
+
130
+ def ask(system: str, user: str) -> str:
131
+ reply = _post(url, headers, {"model": model, "messages": [{"role": "system", "content": system},
132
+ {"role": "user", "content": user}]}, timeout)
133
+ try:
134
+ choice = reply["choices"][0]
135
+ diagnostics.clear()
136
+ diagnostics.update(stop_reason=choice.get("finish_reason"))
137
+ return choice["message"]["content"] or ""
138
+ except (KeyError, IndexError, TypeError, AttributeError) as exc:
139
+ raise AIRequestError(f"{url}: unexpected answer {str(reply)[:300]}") from exc
140
+
141
+ return Provider("openai", model, ask, diagnostics)
142
+
143
+
144
+ # ---------------------------------------------------------------------------------------
145
+ # Prompts and answers
146
+ # ---------------------------------------------------------------------------------------
147
+
148
+ SYSTEM_PROMPT = (
149
+ "You help the verifier Prodigy analyse probabilistic programs with loops. Prodigy represents a "
150
+ "distribution over program states by its probability generating function (PGF) in the program "
151
+ "variables: the coefficient of x^i*c^j is the probability of the state x = i, c = j. You propose a "
152
+ "generating function; Prodigy checks it exactly and rejects it if it is wrong. Your candidate is a "
153
+ "single closed-form expression in the program variables and parameters, using numbers, + - * / ^, "
154
+ "parentheses, sqrt and exp. Keep any reasoning short and end your answer with the line\n"
155
+ "ANSWER: <expression>\n"
156
+ "If you cannot find a candidate, end with the line ANSWER: none")
157
+
158
+ _TASKS = {
159
+ "evt_invariant": (
160
+ "Find the generating function I of the expected visiting times at the head of the loop: the least "
161
+ "solution of I = G + B(<I>_guard), where G is the PGF entering the loop, <F>_guard keeps the terms "
162
+ "of F whose states satisfy the guard, and B is the PGF transformer of one execution of the loop "
163
+ "body. Then <I>_(not guard) is the output distribution of the loop. I must have non-negative "
164
+ "coefficients; Prodigy accepts it as exact only if I(1, ..., 1) is finite."),
165
+ "evt_subinvariant": (
166
+ "Find an occupation sub-invariant nu: a generating function with non-negative coefficients and "
167
+ "finite mass nu(1, ..., 1) such that nu <= G + B(<nu>_guard) coefficient-wise, where G is the PGF "
168
+ "entering the loop, <F>_guard keeps the terms of F whose states satisfy the guard, and B is the "
169
+ "PGF transformer of one execution of the loop body. Then <nu>_(not guard) is a lower bound on the "
170
+ "output distribution. The expected visiting times are the best choice if their mass is finite; "
171
+ "otherwise choose a smaller nu with finite mass."),
172
+ }
173
+
174
+ _EXAMPLE = ("Example: for `nat x; nat c; x := 1; while (x = 1) { {x := 0} [1/2] {c := c + 1} }` the loop "
175
+ "is entered with G = x, and its expected visiting times are (x + 1/2)/(1 - c/2).")
176
+
177
+
178
+ def prompt(form: str, program: str, loop: str, variables: Sequence[str], parameters: Sequence[str],
179
+ entering: str, rejected: Sequence[Tuple[str, str]]) -> str:
180
+ """The request for a candidate of kind ``form`` (see :data:`FORMS`) for ``loop``."""
181
+ parts = [f"Program:\n{program}", f"The loop:\n{loop}",
182
+ f"Program variables: {', '.join(variables)}",
183
+ f"Parameters (unknown constants): {', '.join(parameters) if parameters else 'none'}",
184
+ f"G, the PGF entering the loop: {entering}", _TASKS[form], _EXAMPLE]
185
+ if rejected:
186
+ parts.append("Prodigy rejected these candidates; do not propose them again:\n"
187
+ + "\n".join(f"- {candidate}: {reason}" for candidate, reason in rejected))
188
+ return "\n\n".join(parts)
189
+
190
+
191
+ _FENCE = re.compile(r"```[A-Za-z]*\n?(.*?)```", re.S)
192
+ _ANSWER = re.compile(r"^[\s*_#>]*ANSWER[\s*_]*:[\s*_`$]*(.*?)[\s*_`$]*$", re.I | re.M)
193
+ _PREFIX = re.compile(r"^(?:[A-Za-z_]\w*\s*(?:\([^)]*\))?\s*=\s*)+")
194
+ _ALLOWED = re.compile(r"[0-9A-Za-z_+\-*/^().\s]+")
195
+ _IDENTIFIER = re.compile(r"[A-Za-z_]\w*")
196
+
197
+
198
+ def candidate_from_answer(answer: str, names: Sequence[str]) -> str:
199
+ """The candidate in a model's answer: its last ``ANSWER:`` line, else the last line of its last
200
+ code block or of the answer.
201
+
202
+ Raises :class:`CandidateError` unless it is an expression over ``names``, numbers,
203
+ ``+ - * / ^``, parentheses, ``sqrt`` and ``exp`` that parses as a pGCL expression."""
204
+ marked = _ANSWER.findall(answer)
205
+ if marked:
206
+ line = marked[-1].strip()
207
+ if line.lower().strip(".") in ("none", "unknown", ""):
208
+ raise CandidateError("The model found no candidate (ANSWER: none).")
209
+ else:
210
+ blocks = _FENCE.findall(answer)
211
+ lines = [line.strip() for line in (blocks[-1] if blocks else answer).splitlines() if line.strip()]
212
+ if not lines:
213
+ raise CandidateError("The answer contains no text.")
214
+ line = lines[-1]
215
+ candidate = _PREFIX.sub("", line.strip("`$ ")).rstrip(".;").strip().replace("**", "^")
216
+ if not _ALLOWED.fullmatch(candidate):
217
+ raise CandidateError(f"{candidate!r} contains characters other than numbers, variables, "
218
+ "+ - * / ^ and parentheses.")
219
+ unknown = sorted(set(_IDENTIFIER.findall(candidate)) - set(names) - FUNCTIONS)
220
+ if unknown:
221
+ raise CandidateError(f"{candidate!r} uses {', '.join(unknown)}, which are neither program "
222
+ "variables nor parameters.")
223
+ try:
224
+ parse_expr(candidate)
225
+ except Exception as exc: # pylint: disable=broad-except # lark raises several error types
226
+ raise CandidateError(f"{candidate!r} is not a well-formed expression: {exc}") from exc
227
+ return candidate
@@ -0,0 +1,161 @@
1
+ from __future__ import annotations
2
+
3
+ import functools
4
+ import logging
5
+ from typing import Callable, Optional, Union, Sequence, get_args
6
+
7
+ from prodigy.pgcl import Program, Instr, SkipInstr, AbortInstr, WhileInstr, LoopInstr, QueryInstr, Query, \
8
+ ObserveInstr, ChoiceInstr, AsgnInstr, IfInstr
9
+
10
+ from prodigy.analysis.config import ForwardAnalysisConfig
11
+ from prodigy.analysis.exceptions import ObserveZeroEventError
12
+ from prodigy.analysis.instructionhandler.assignment_handler import AssignmentHandler
13
+ from prodigy.analysis.instructionhandler.ite_handler import ITEHandler
14
+ from prodigy.analysis.instructionhandler.loop_handler import LoopHandler
15
+ from prodigy.analysis.instructionhandler.observe_handler import ObserveHandler
16
+ from prodigy.analysis.instructionhandler.probchoice_handler import PChoiceHandler
17
+ from prodigy.analysis.instructionhandler.program_info import ProgramInfo
18
+ from prodigy.analysis.instructionhandler.query_handler import QueryHandler
19
+ from prodigy.analysis.instructionhandler.queryblock_handler import QueryBlockHandler
20
+ from prodigy.analysis.instructionhandler.while_handler import WhileHandler
21
+ from prodigy.analysis.session import current_session
22
+ from prodigy.distribution import Distribution
23
+ from prodigy.util.color import Style
24
+ from prodigy.util.logger import log_setup
25
+
26
+ logger = log_setup(str(__name__).rsplit(".", maxsplit=1)[-1], logging.DEBUG)
27
+
28
+
29
+ def condition_distribution(
30
+ dist: Distribution, error_prob: Distribution,
31
+ config: ForwardAnalysisConfig) -> tuple[Distribution, Distribution]:
32
+ # lets the session rescale the residual mass of approximated loops
33
+ current_session().on_normalize(error_prob)
34
+ one = config.factory.one(*error_prob.get_variables())
35
+ zero = one * "0"
36
+ if dist == zero and error_prob == one:
37
+ raise ObserveZeroEventError(
38
+ "Undefined semantics: Probability of observing a valid run is 0.")
39
+ result = dist / (one - error_prob)
40
+ return result, error_prob
41
+
42
+
43
+ def compute_discrete_distribution(
44
+ program: Program | ProgramInfo, dist: Distribution,
45
+ config: ForwardAnalysisConfig,
46
+ step_callback: Optional[Callable[[Instr, Distribution, Distribution], None]] = None
47
+ ) -> tuple[Distribution, Distribution]:
48
+ """
49
+ Computes the output distribution of ``program`` for the input ``dist``.
50
+
51
+ :param step_callback: if given, called with (instruction, distribution, error_prob) after each
52
+ top-level instruction.
53
+ """
54
+ logger.debug("Compute the distribution for\n%s\nand distribution %s", str(program), dist)
55
+
56
+ # Inject the context from the parsed program into the initial distribution.
57
+ prog_info = program if isinstance(program,
58
+ ProgramInfo) else ProgramInfo(program)
59
+ variables = set(prog_info.variables.keys()).union(dist.get_variables())
60
+ parameters = set(prog_info.parameters.keys()).union(dist.get_parameters())
61
+ initial_dist = dist.set_variables(*variables).set_parameters(*parameters)
62
+ error_prob = config.factory.one(*variables) * 0
63
+ if step_callback is None:
64
+ dist, error_prob = compute_semantics(prog_info.instructions,
65
+ prog_info, initial_dist,
66
+ error_prob, config)
67
+ else:
68
+ dist = initial_dist
69
+ for instr in prog_info.instructions:
70
+ dist, error_prob = compute_semantics([instr], prog_info, dist, error_prob, config)
71
+ step_callback(instr, dist, error_prob)
72
+ if config.normalize:
73
+ dist, error_prob = condition_distribution(dist, error_prob, config)
74
+ return dist, error_prob
75
+
76
+
77
+ def compute_semantics(
78
+ instruction: Union[Instr, Sequence[Instr]],
79
+ prog_info: ProgramInfo,
80
+ distribution: Distribution,
81
+ error_prob: Distribution,
82
+ config=ForwardAnalysisConfig()
83
+ ) -> tuple[Distribution, Distribution]:
84
+ def _show_steps(inp: tuple[Distribution, Distribution],
85
+ instr: Instr) -> tuple[Distribution, Distribution]:
86
+ dist, error_prob = inp
87
+ res, error_prob = compute_semantics(instr, prog_info, dist,
88
+ error_prob, config)
89
+ if isinstance(instr, (WhileInstr, IfInstr, LoopInstr)):
90
+ print("\n")
91
+ output = f"\n{Style.BLUE}Instruction:{Style.RESET} {instr}\t {Style.GREEN}Result:{Style.RESET} {res}"
92
+ print(output, prog_info.so_vars)
93
+ if config.step_wise:
94
+ current_session().provider.next_step()
95
+ return res, error_prob
96
+
97
+ def _dont_show_steps(
98
+ inp: tuple[Distribution, Distribution],
99
+ instr: Instr) -> tuple[Distribution, Distribution]:
100
+ dist, error_prob = inp
101
+ return compute_semantics(instr, prog_info, dist, error_prob,
102
+ config)
103
+
104
+ if not isinstance(instruction, list):
105
+ current_session().on_instruction(instruction)
106
+
107
+ if isinstance(instruction, list):
108
+ func = _show_steps if config.show_intermediate_steps else _dont_show_steps
109
+ return functools.reduce(func, instruction,
110
+ (distribution, error_prob))
111
+
112
+ elif isinstance(instruction, SkipInstr):
113
+ return distribution, error_prob
114
+
115
+ elif isinstance(instruction, AbortInstr):
116
+ return distribution.factory().undefined(
117
+ *distribution.get_variables()), error_prob
118
+
119
+ elif isinstance(instruction, WhileInstr):
120
+ logger.info("\n%s gets handled", instruction)
121
+ return WhileHandler.compute(instruction, prog_info, distribution,
122
+ error_prob, config, compute_semantics)
123
+
124
+ elif isinstance(instruction, IfInstr):
125
+ return ITEHandler.compute(instruction, prog_info, distribution,
126
+ error_prob, config, compute_semantics)
127
+
128
+ elif isinstance(instruction, AsgnInstr):
129
+ return AssignmentHandler.compute(instruction, prog_info,
130
+ distribution, error_prob, config, compute_semantics)
131
+
132
+ elif isinstance(instruction, ChoiceInstr):
133
+ return PChoiceHandler.compute(instruction, prog_info, distribution,
134
+ error_prob, config, compute_semantics)
135
+
136
+ elif isinstance(instruction, ObserveInstr):
137
+ logger.info("%s gets handled", instruction)
138
+ return ObserveHandler.compute(instruction, prog_info, distribution,
139
+ error_prob, config, compute_semantics)
140
+
141
+ elif isinstance(instruction, get_args(Query)):
142
+ logger.info("%s gets handled", instruction)
143
+ if config.normalize:
144
+ distribution, error_prob = condition_distribution(
145
+ distribution, error_prob,
146
+ config) # evaluate queries on conditioned distribution
147
+ error_prob *= "0"
148
+ return QueryHandler.compute(instruction, prog_info, distribution,
149
+ error_prob, config, compute_semantics)
150
+
151
+ elif isinstance(instruction, LoopInstr):
152
+ logger.info("%s gets handled", instruction)
153
+ return LoopHandler.compute(instruction, prog_info, distribution,
154
+ error_prob, config, compute_semantics)
155
+
156
+ elif isinstance(instruction, QueryInstr):
157
+ logger.info("entering query block")
158
+ return QueryBlockHandler.compute(instruction, prog_info,
159
+ distribution, error_prob, config, compute_semantics)
160
+
161
+ raise TypeError("illegal instruction")
@@ -0,0 +1,98 @@
1
+ """
2
+ -----------------------
3
+ Forward Analysis Config
4
+ -----------------------
5
+ """
6
+ from enum import Enum, auto
7
+ from typing import Type
8
+
9
+ import attr
10
+
11
+ from prodigy.analysis.optimization import Optimizer
12
+ from prodigy.analysis.optimization.gf_optimizer import GFOptimizer
13
+ from prodigy.distribution.generating_function import (GeneratingFunction,
14
+ SympyPGF)
15
+ from prodigy.distribution.symengine_distribution import SymenginePGF
16
+ from .evtinvariants.heuristics.positivity.heuristics_factory import PositivityHeuristics
17
+ from .evtinvariants.heuristics.strategies import SynthesisStrategies
18
+ from .evtinvariants.heuristics.templates.templates_factory import TemplateHeuristics
19
+ from .exceptions import ConfigurationError
20
+ from .solver.solver_type import SolverType
21
+ from ..distribution.distribution import CommonDistributionsFactory
22
+
23
+
24
+ @attr.s
25
+ class ForwardAnalysisConfig:
26
+ """Global configurable options for forward analysis."""
27
+
28
+ class Engine(Enum):
29
+ """
30
+ This enumeration specifies the type of backend used for distribution encodings and mathematical operations.
31
+ """
32
+ SYMPY = auto()
33
+ GINAC = auto()
34
+ SYMENGINE = auto()
35
+
36
+ show_intermediate_steps: bool = attr.ib(default=False)
37
+ """Enables the printing of results after each instruction."""
38
+
39
+ step_wise: bool = attr.ib(default=False)
40
+ """Enables step-by-step computation"""
41
+
42
+ use_simplification: bool = attr.ib(default=False)
43
+ """Enables simplification heuristics for expressions."""
44
+
45
+ use_latex: bool = attr.ib(default=False)
46
+ """Toggle to print LaTeX-Code instead of ASCII expressions."""
47
+
48
+ engine: Engine = attr.ib(default=Engine.SYMPY)
49
+ """Selects the distribution backend."""
50
+
51
+ normalize: bool = attr.ib(default=True)
52
+ """Switch to compute the normalized distribution"""
53
+
54
+ strategy: SynthesisStrategies = attr.ib(default=SynthesisStrategies.DEFAULT)
55
+ """The Strategy for dealing with synthesis."""
56
+
57
+ templ_heuristic: TemplateHeuristics = attr.ib(default=TemplateHeuristics.DEFAULT)
58
+ """ The heuristics to use for template genesis"""
59
+
60
+ positivity_heuristic: PositivityHeuristics = attr.ib(default=PositivityHeuristics.DEFAULT)
61
+ """ The heuristics to validate positivity"""
62
+
63
+ solver_type: SolverType = attr.ib(default=SolverType.SYMPY)
64
+ """The solver to use for equation systems."""
65
+
66
+ show_all_invs: bool = attr.ib(default=False)
67
+ """Toggels printing of spurious invariants"""
68
+
69
+ @property
70
+ def optimizer(self) -> Type[Optimizer]:
71
+ if self.engine == ForwardAnalysisConfig.Engine.SYMPY:
72
+ return GFOptimizer
73
+ else:
74
+ raise ConfigurationError(
75
+ "The configured engine does not implement an optimizer.")
76
+
77
+ @property
78
+ def factory(self) -> Type[CommonDistributionsFactory]:
79
+ if self.engine == self.Engine.SYMPY:
80
+ return SympyPGF
81
+ elif self.engine == self.Engine.GINAC:
82
+ # pygin is optional (prodigy-ppl[ginac]); only the GiNaC engine imports it
83
+ try:
84
+ # pylint: disable=import-outside-toplevel
85
+ from prodigy.distribution.fast_generating_function import ProdigyPGF
86
+ except ImportError as error:
87
+ raise ConfigurationError(
88
+ "The GiNaC engine needs pygin: pip install \"pygin @ "
89
+ "git+https://github.com/LKlinke/prodigy-ginac-bindings.git@dynamic-variables\"") from error
90
+ return ProdigyPGF
91
+ elif self.engine == self.Engine.SYMENGINE:
92
+ return SymenginePGF
93
+ else:
94
+ return CommonDistributionsFactory
95
+
96
+ def __attrs_post_init__(self):
97
+ GeneratingFunction.use_latex_output = self.use_latex
98
+ GeneratingFunction.use_simplification = self.use_simplification
@@ -0,0 +1,9 @@
1
+ """
2
+ ====================
3
+ Equivalence Checking
4
+ ====================
5
+
6
+ This module performs equivalence checks on two probabilistic programs.
7
+
8
+ .. automodule:: prodigy.analysis.forward.equivalence.equivalence_check
9
+ """