loopmath 0.2.7__tar.gz → 0.2.8__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.
- {loopmath-0.2.7/src/loopmath.egg-info → loopmath-0.2.8}/PKG-INFO +1 -1
- {loopmath-0.2.7 → loopmath-0.2.8}/pyproject.toml +1 -1
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/__init__.py +1 -1
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/compose.py +45 -11
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/design.py +6 -2
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/features.py +2 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/fit.py +36 -13
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/lookahead.py +1 -1
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/pricing.py +22 -3
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/state.py +106 -58
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/base.py +1 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/prices.toml +12 -2
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/benchmarks.py +4 -4
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/commands.py +8 -6
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/skills/loopmath-plan-task/SKILL.md +2 -2
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/estimates.js +1 -1
- {loopmath-0.2.7 → loopmath-0.2.8/src/loopmath.egg-info}/PKG-INFO +1 -1
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath.egg-info/SOURCES.txt +2 -1
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_price.py +5 -5
- loopmath-0.2.8/tests/test_v028_sol_6_1.py +80 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/LICENSE +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/README.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/setup.cfg +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/spec/ocp-v0.2.schema.json +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/spec/ocp-v0.schema.json +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/spec/ocp_conformance.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/__main__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapter_host.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/atrium.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/base.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/bb.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/bb_support.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/omp.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/omp_facts.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/omp_links.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/omp_parse.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/omp_types.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/opencode.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/opencode_store.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/orca.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/otel_genai.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/otel_genai_graph.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/otel_genai_parse.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/otel_genai_types.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/otel_genai_usage.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/paseo.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/pi.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/pi_support.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/adapters/registry.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/block.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/check_pymc.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/commands.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/forest.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/gaussian.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/outcome.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/priors.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/belief/rules.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/builder/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/builder/cli.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/builder/context.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/builder/predict.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/builder/server.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/cli.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/cli_graph.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/cli_registry.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/cli_support.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/e0/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/e0/arms.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/e0/cli_e0.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/e0/estimate.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/e0/estimate_rework.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/e0/figures.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/e0/io.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/e0/verb.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/explain.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/fit.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/fit_assembly.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/fit_bayes.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/fit_masks.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/fit_predict.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/fit_pricing.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/fit_transfer.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/gaps.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/gitwalk.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/grade.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/grade_support.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/artifact_git.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/artifact_join.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/artifact_kinds.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/artifacts.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/bashparse.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/bashread_ops.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/bashwrite_ops.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/bashwrites.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/cache.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/codexio.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/codexio_parse.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/codexio_scan.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/dataset.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/dataset_build.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/dataset_core.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/dataset_edges.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/dataset_nodes.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/extract.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/html_common.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/html_costcurve.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/html_css.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/html_data.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/html_force.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/html_render.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/html_swimlanes.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_cli.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_common.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_parse.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_pricing.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_build.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_dispatch.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_evidence.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_node.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_records.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_result.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_session.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_tools.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_validation.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_prompt_workflow.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_report.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labeler_score.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/labels.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/launch.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/launch_origin.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/ocp.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/ocp_emit.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/ocp_support.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/render.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/runfile.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/runfile_export.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/runfile_finish.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/scan.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/schema.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/graph/token_completeness.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/claude_code.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/claude_code_support.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/codex.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/codex_support.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/ocp.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/ocp_analysis.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/ocp_artifact.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/ocp_common.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/ocp_convert.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ingest/ocp_projection.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/logmatch/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/logmatch/artifacts.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/logmatch/clip.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/logmatch/codex_window.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/logmatch/costs.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/logmatch/match.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/logmatch/settle.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/logmatch/tariff.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/canonical.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/commands.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/conformance.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/contractv3.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/emit.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/graph_contract.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/membership.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/migrate.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/schema/ocp-v0.2.schema.json +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/schema/ocp-v0.3.schema.json +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/schema/ocp-v0.schema.json +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/ocp/version.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/onboard/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/onboard/commands.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/onboard/history.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/onboard/label.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/onboard/usual.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/output.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/pool.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/price.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/price_validation.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/benchmarks.toml +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/build.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/bundle/README.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/bundle/e0.jsonl.gz +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/bundle/lanes.jsonl.gz +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/bundle/manifest.json +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/bundle/rq1.jsonl.gz +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/bundle/sweep.jsonl.gz +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/commands.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/e0.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/history.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/lanes.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/ocpdoc.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/reduce.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/registry.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/rq1.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/show.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/sweep.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/priors/validate.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/receipts.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/backlog.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/curve.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/engine.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/gain.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/message.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/receipts.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/search.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/stats.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/recommend/storeread.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/report/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/report/eligibility.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/report/html.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/report/terminal.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/report/terminal_exclusions.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/report/terminal_format.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/report/terminal_read.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/research_defaults.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/research_paths.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/scoring.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/scoring_comparisons.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/scoring_predictive.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/share/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/share/commands.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/share/export.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/share/import_.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/commands.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/doctor.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/install.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/skills/loopmath/SKILL.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/skills/loopmath-import-runs/SKILL.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/skills/loopmath-onboard/SKILL.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/skills/loopmath-record-run/SKILL.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/skills/loopmath-update-fit/SKILL.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/skill/skills/reference.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/budget.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/commands.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/config.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/finish.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/fitjob.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/home.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/ids.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/lock.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/record.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/report.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/rule_change.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/run_names.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/runs.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/status.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/store/verify.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/surface.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/surface_bootstrap.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/surface_estimation.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/surface_frame.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/surface_presentation.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/surface_support.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/taskmodel.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/types.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/README.md +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/base.css +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/builder.css +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/builder.html +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/builder.js +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/common.js +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/estimates.css +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/graph.css +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/graph.js +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/plans.css +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/plans.js +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/results.css +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/results.js +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/runs.js +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/viz.css +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/assets/viz.js +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/common.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/plans.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/posterior.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/views/runs.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/__init__.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/candidates.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/catalog/best_of_n.toml +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/catalog/implement_review.toml +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/catalog/plan_implement.toml +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/catalog/plan_implement_review.toml +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/catalog/solo.toml +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/catalog/swarm.toml +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/commands.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/diff.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/format.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/graphview.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/ids.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/infer.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/models.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/ocp.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath/workflows/shapes.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath.egg-info/dependency_links.txt +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath.egg-info/entry_points.txt +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath.egg-info/requires.txt +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/src/loopmath.egg-info/top_level.txt +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_atrium.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_bb.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_omp.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_opencode.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_opencode_output_tokens.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_orca.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_otel_genai.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_paseo.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapter_services.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapters.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_adapters_pi.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_analyze_cli.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_arms.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_cli_graph.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_cli_help_lists.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_cli_labeler.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_cli_main_module.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_cli_plan_hidden.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_cli_prices.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_cli_startup.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_color_proof.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_duplicate_guards.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_estimate.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_explain.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_fit.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_gaps.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_gitwalk.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_grade.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_artifact_recording.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_artifacts.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_bashwrites.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_cache.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_codexio.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_dataset.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_extract.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_glue.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_html.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_labeler.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_labeler_evidence_matrix.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_launch.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_ocp.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_render.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_runfile.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_graph_schema.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_home_guard.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_html.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_ingest.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_ingest_claude_code.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_ingest_codex.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_ingest_ocp.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_io.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_not_run_summary.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_ocp_conformance.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_ocp_golden.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_ocp_open_enums.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_ocp_versioning.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_output_html_path.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_packaging_metadata.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_packaging_smoke.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_pool.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_preview_script.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_receipts.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_release_paths.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_report_eligibility.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_research_cli.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_runfile_privacy_n1b.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_scoring.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_split_rebindings.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_starting_prior.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_surface.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_taskmodel_features.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_terminal.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_types_control.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_types_piece_prediction.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_v01_scaffold.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_v027_p3.py +0 -0
- {loopmath-0.2.7 → loopmath-0.2.8}/tests/test_v027_small_fixes.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "loopmath"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.8"
|
|
8
8
|
description = "Plan agent workflows, record how they went, and learn from your own Claude Code and Codex logs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -18,6 +18,13 @@ simulated per draw (run noise and gate outcomes), and the interval is its 10th a
|
|
|
18
18
|
percentiles. Rounds, success and `ell` are parameter-draw quantities. Without a generator,
|
|
19
19
|
`compose` computes the expectations only (the mean path in state.py).
|
|
20
20
|
|
|
21
|
+
Tokens (0.2.8): one execution's dollars are `U = exp(eta_u + sigma_u z1)` and its price per token
|
|
22
|
+
`R = exp(eta_r + sigma_r z2)`, from the rate head; its tokens are `T = U / max(R, f)`, with `f` the model's
|
|
23
|
+
cache-read rate (its floor, none for a model without one). So `T f <= U` in every draw, and every shown pair of
|
|
24
|
+
dollars and tokens clears the floor: per draw, in the mean, at every percentile and summed over pieces. The two
|
|
25
|
+
normals are drawn in 0.2.7's order (dollars, then the second one), so the simulated dollars and the gates after
|
|
26
|
+
them are 0.2.7's. The expected tokens are `E[U] E[1 / max(R, f)]` (`inv_rate_mean`).
|
|
27
|
+
|
|
21
28
|
Per piece, `PieceDraws.exp_*` is the piece's expected full-run contribution, summed over
|
|
22
29
|
the rounds it runs, so pieces add up to the run. `cost_per_round()` gives the expected cost of
|
|
23
30
|
one execution: the per-execution prediction when the piece's cost does not depend on the round
|
|
@@ -28,8 +35,11 @@ from __future__ import annotations
|
|
|
28
35
|
|
|
29
36
|
from dataclasses import dataclass, field
|
|
30
37
|
|
|
38
|
+
import math
|
|
39
|
+
from collections.abc import Mapping
|
|
40
|
+
|
|
31
41
|
import numpy as np
|
|
32
|
-
from scipy.special import expit
|
|
42
|
+
from scipy.special import expit, log_ndtr
|
|
33
43
|
|
|
34
44
|
from .design import Structure
|
|
35
45
|
|
|
@@ -64,12 +74,33 @@ class RunDraws:
|
|
|
64
74
|
reach: dict[tuple[str, int], np.ndarray] = field(default_factory=dict) # (piece, k) -> P(piece runs in round k)
|
|
65
75
|
|
|
66
76
|
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
def inv_rate_mean(m, v, floor: float | None) -> np.ndarray:
|
|
78
|
+
"""`E[1 / max(R, f)]` for `log R ~ N(m, v)` and the floor `f` ($ per token; None or 0: no floor), per entry
|
|
79
|
+
of `m`. With `l = log f`: `exp(-m + v/2) Phi((m - l)/sqrt(v) - sqrt(v)) + exp(-l) Phi((l - m)/sqrt(v))`,
|
|
80
|
+
each term in logs (`log Phi`), so a far tail never multiplies an overflow by 0. With `v = 0` the rate is
|
|
81
|
+
certain: `1 / max(exp(m), f)`."""
|
|
82
|
+
m = np.asarray(m, float)
|
|
83
|
+
v = np.broadcast_to(np.asarray(v, float), m.shape)
|
|
84
|
+
if not floor or floor <= 0:
|
|
85
|
+
return np.exp(-m + 0.5 * v)
|
|
86
|
+
lf = math.log(floor)
|
|
87
|
+
certain = v <= 0
|
|
88
|
+
sd = np.sqrt(np.where(certain, 1.0, v))
|
|
89
|
+
spread = np.exp(-m + 0.5 * v + log_ndtr((m - lf) / sd - sd)) + np.exp(log_ndtr((lf - m) / sd) - lf)
|
|
90
|
+
return np.where(certain, np.exp(-np.maximum(m, lf)), spread)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def compose(st: Structure, cost_eta: dict, rate_eta: dict, gate_eta: dict, *, sigma_usd: float,
|
|
94
|
+
sigma_rate: float, floors: Mapping[str, float] | None = None, rate_var: Mapping | None = None,
|
|
95
|
+
rng: np.random.Generator | None) -> RunDraws:
|
|
96
|
+
"""Compose one configuration. `cost_eta[(piece, k)]`, `rate_eta[(piece, k)]` and `gate_eta[(gate index, k)]`
|
|
97
|
+
are draw arrays; `floors[piece]` is the piece model's floor in $ per token (absent or 0: none). The expected
|
|
98
|
+
tokens take `log R ~ N(rate_eta, rate_var[(piece, k)])`, `sigma_rate ** 2` when `rate_var` is None (the mean
|
|
99
|
+
path passes the rate rows' known parts and adds their unseen variance there). With `rng` None nothing is
|
|
100
|
+
simulated: the `sim_*` arrays stay zero."""
|
|
71
101
|
n = len(next(iter(cost_eta.values())))
|
|
72
|
-
half_u,
|
|
102
|
+
half_u, var_r = 0.5 * sigma_usd ** 2, sigma_rate ** 2
|
|
103
|
+
floors = floors or {}
|
|
73
104
|
exp_u, exp_t = np.zeros(n), np.zeros(n)
|
|
74
105
|
sim_u, sim_t = np.zeros(n), np.zeros(n)
|
|
75
106
|
rounds = np.ones(n)
|
|
@@ -79,7 +110,7 @@ def compose(st: Structure, cost_eta: dict, tokens_eta: dict, gate_eta: dict, *,
|
|
|
79
110
|
pieces[p] = PieceDraws(np.zeros(n), np.zeros(n), np.zeros(n), np.zeros(n), np.ones(n), sim_runs=np.zeros(n))
|
|
80
111
|
if st.piece_loop.get(p) is not None:
|
|
81
112
|
pieces[p].round_free = all(
|
|
82
|
-
np.array_equal(cost_eta[(p, k)], cost_eta[(p, 1)]) and np.array_equal(
|
|
113
|
+
np.array_equal(cost_eta[(p, k)], cost_eta[(p, 1)]) and np.array_equal(rate_eta[(p, k)], rate_eta[(p, 1)])
|
|
83
114
|
for k in range(2, st.k_max + 1))
|
|
84
115
|
gate_after = {g.after: gi for gi, g in enumerate(st.gates)}
|
|
85
116
|
for piece, gi in gate_after.items():
|
|
@@ -88,17 +119,20 @@ def compose(st: Structure, cost_eta: dict, tokens_eta: dict, gate_eta: dict, *,
|
|
|
88
119
|
|
|
89
120
|
def run_piece(piece: str, k: int, weight: np.ndarray, alive: np.ndarray):
|
|
90
121
|
w = st.widths[piece]
|
|
91
|
-
eu,
|
|
122
|
+
eu, er = cost_eta[(piece, k)], rate_eta[(piece, k)]
|
|
123
|
+
f = float(floors.get(piece) or 0.0)
|
|
92
124
|
cu = w * np.exp(eu + half_u)
|
|
93
|
-
ct =
|
|
125
|
+
ct = cu * inv_rate_mean(er, var_r if rate_var is None else rate_var[(piece, k)], f)
|
|
94
126
|
pd = pieces[piece]
|
|
95
127
|
pd.exp_usd += weight * cu
|
|
96
128
|
pd.exp_tokens += weight * ct
|
|
97
129
|
su = np.zeros(n)
|
|
98
130
|
stt = np.zeros(n)
|
|
99
131
|
for _ in range(w if rng is not None else 0):
|
|
100
|
-
|
|
101
|
-
|
|
132
|
+
u = np.exp(eu + sigma_usd * rng.standard_normal(n))
|
|
133
|
+
r = np.exp(er + sigma_rate * rng.standard_normal(n))
|
|
134
|
+
su += u
|
|
135
|
+
stt += u / (np.maximum(r, f) if f > 0 else r)
|
|
102
136
|
pd.sim_usd += alive * su
|
|
103
137
|
pd.sim_tokens += alive * stt
|
|
104
138
|
pd.sim_runs += alive
|
|
@@ -30,8 +30,12 @@ from .pricing import price_term
|
|
|
30
30
|
Term = tuple[str, "str | None", float]
|
|
31
31
|
|
|
32
32
|
# Node names of this design (spec 04 section 4). 2 (loopmath 0.2): shape keys, psrc nodes and role groups.
|
|
33
|
-
# 3 (0.2): `horizon:log2h` is relative to the fit's reference horizon.
|
|
34
|
-
|
|
33
|
+
# 3 (0.2): `horizon:log2h` is relative to the fit's reference horizon. 4 (0.2.8): a `rate` head on the price
|
|
34
|
+
# per token replaces the tokens head. A fit of another version is not read.
|
|
35
|
+
DESIGN_VERSION = 4
|
|
36
|
+
# The version the seed key hashes (spec 04 section 3). It stays 3 from 0.2.8: the same data seeds the same
|
|
37
|
+
# draws as in 0.2.7, so every number that is not a token count is 0.2.7's.
|
|
38
|
+
SEED_VERSION = 3
|
|
35
39
|
HEURISTIC_COST_WEIGHT = 0.7 # spec 04 section 2 and D27: allocated (heuristic) cost rows
|
|
36
40
|
USER_SOURCES = ("live", "backlog", "history", "user", "orchestrator", "onboard", "habit", "")
|
|
37
41
|
HORIZON_NODES = ("horizon:timebox", "horizon:log2h") # fixed terms of a timeboxed run (spec 04 section 1)
|
|
@@ -35,6 +35,8 @@ LN2 = math.log(2.0)
|
|
|
35
35
|
# cost and tokens scale with an elasticity of 1 +- 0.5; logit and score heads start flat.
|
|
36
36
|
HORIZON_PRIOR = {
|
|
37
37
|
"cost": {"horizon:log2h": (LN2, 0.35), "horizon:timebox": (0.0, 1.5)},
|
|
38
|
+
# the price per token (0.2.8): a longer horizon buys more tokens, not dearer ones
|
|
39
|
+
"rate": {"horizon:log2h": (0.0, 0.35), "horizon:timebox": (0.0, 1.5)},
|
|
38
40
|
"logit": {"horizon:log2h": (0.0, 0.25), "horizon:timebox": (0.0, 1.0)},
|
|
39
41
|
"score": {"horizon:log2h": (0.0, 0.25), "horizon:timebox": (0.0, 1.0)},
|
|
40
42
|
}
|
|
@@ -31,12 +31,12 @@ from scipy import sparse
|
|
|
31
31
|
from ..taskmodel import FeatureConfigError, FeatureSet
|
|
32
32
|
from . import design as design_rows
|
|
33
33
|
from . import priors as prior_data
|
|
34
|
-
from .design import (DESIGN_VERSION, Term, Unusable, cost_row, gate_row, parse_run, run_row,
|
|
35
|
-
task_features, task_terms)
|
|
34
|
+
from .design import (DESIGN_VERSION, SEED_VERSION, Term, Unusable, cost_row, gate_row, parse_run, run_row,
|
|
35
|
+
structure, task_features, task_terms)
|
|
36
36
|
from .features import FeatureTally, add_horizon, drop_features, horizon_nodes, horizon_specs
|
|
37
37
|
from .block import leaf_split
|
|
38
38
|
from .forest import Forest, default_scale, fixed_sd, scale_group
|
|
39
|
-
from .pricing import PRICE_NODE, PRICE_PRIOR_SD, STREAMS, fit_offsets, price_term
|
|
39
|
+
from .pricing import PRICE_NODE, PRICE_PRIOR_SD, STREAMS, fit_offsets, price_term, rate_floors
|
|
40
40
|
from .gaussian import N_DRAWS, Factors, GaussianHead, HeadFit, LogisticHead, Prior
|
|
41
41
|
from .state import SCORE_CLAMP, inverse_transform, transform # noqa: F401 (re-exported)
|
|
42
42
|
|
|
@@ -44,8 +44,12 @@ FIT_LOCK = ".fit.lock"
|
|
|
44
44
|
KEEP_FITS = 5 # The newest fits kept, besides the ones a receipt or stored recommendation names
|
|
45
45
|
TASK_LEVELS = ("org", "type", "repo", "subtype", "task")
|
|
46
46
|
MIN_SCORE_RUNS = 3 # spec 04 section 2: a score head needs at least 3 measured runs
|
|
47
|
-
|
|
47
|
+
# `tokens` (log tokens) is 0.2.7's head: from 0.2.8 its rows are built for the seed key and the node index
|
|
48
|
+
# only, never fitted. `rate` (log usd - log tokens, the price per token) is fitted in its place (spec 04 section 2).
|
|
49
|
+
HEAD_KIND = {"cost": ("gaussian", "cost"), "tokens": ("gaussian", "cost"), "rate": ("gaussian", "cost"),
|
|
48
50
|
"gate": ("logistic", "logit"), "success": ("logistic", "logit")}
|
|
51
|
+
KEY_ONLY = ("tokens",) # heads whose rows the seed key and the node index read, and no fit
|
|
52
|
+
NOT_KEYED = ("rate",) # heads the seed key leaves out, so 0.2.8 seeds every draw as 0.2.7 did
|
|
49
53
|
|
|
50
54
|
|
|
51
55
|
class FitBusy(RuntimeError):
|
|
@@ -273,6 +277,9 @@ def collect_rows(docs: Iterable[dict | tuple[str | None, dict]], *, without: tup
|
|
|
273
277
|
acc[i] += v
|
|
274
278
|
if a.tokens:
|
|
275
279
|
heads["tokens"].add(terms, math.log(a.tokens), a.weight, pr.run_id, pr.source, ttype)
|
|
280
|
+
if a.usd and a.tokens:
|
|
281
|
+
heads["rate"].add(terms, math.log(a.usd) - math.log(a.tokens), a.weight, pr.run_id, pr.source,
|
|
282
|
+
ttype)
|
|
276
283
|
for gi, k, passed in pr.gates:
|
|
277
284
|
heads["gate"].add(gate_row(pr.task, pr.source, st, st.gates[gi], k, features), 1.0 if passed else 0.0,
|
|
278
285
|
1.0, pr.run_id, pr.source, ttype)
|
|
@@ -305,6 +312,8 @@ def collect_rows(docs: Iterable[dict | tuple[str | None, dict]], *, without: tup
|
|
|
305
312
|
for hr in heads.values():
|
|
306
313
|
hr.rows = add_horizon(drop_features(hr.rows, tally.nodes), hr.runs, tally.run_horizon, coding)
|
|
307
314
|
add_prices(heads["cost"], {m: len(r) for m, r in model_runs.items()}, model_streams)
|
|
315
|
+
heads["rate"].prices = heads["cost"].prices # the price per token carries the same offset (spec 04 section 2)
|
|
316
|
+
_price_rows(heads["rate"])
|
|
308
317
|
return (heads, score_info, dict(dropped), dict(runs_by_source), {c: dict(n) for c, n in config_support.items()},
|
|
309
318
|
dict(checks), dict(overlap), dict(labels), tally)
|
|
310
319
|
|
|
@@ -313,7 +322,12 @@ def add_prices(hr: HeadRows, runs: dict[str, int], streams: dict[str, list[float
|
|
|
313
322
|
"""The price offset (spec 04 section 2): the fit's offsets from its runs and token mix under the current price
|
|
314
323
|
table, and each cost row with its model's `price:offset` term (`pricing.price_term`, as at prediction)."""
|
|
315
324
|
hr.prices = fit_offsets(runs, streams, design_rows._price_table())
|
|
316
|
-
|
|
325
|
+
_price_rows(hr)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _price_rows(hr: HeadRows) -> None:
|
|
329
|
+
"""Each row with its model's `price:offset` term under `hr.prices`."""
|
|
330
|
+
offsets = hr.prices.get("models")
|
|
317
331
|
if not offsets:
|
|
318
332
|
return
|
|
319
333
|
rows = []
|
|
@@ -325,10 +339,11 @@ def add_prices(hr: HeadRows, runs: dict[str, int], streams: dict[str, list[float
|
|
|
325
339
|
|
|
326
340
|
|
|
327
341
|
def price_spec(hr: HeadRows) -> list:
|
|
328
|
-
"""The prior that holds `price:offset` at 1, on the cost
|
|
342
|
+
"""The prior that holds `price:offset` at 1, on the cost and rate heads of a fit with offsets, --no-prior
|
|
343
|
+
included."""
|
|
329
344
|
if not hr.prices.get("models"):
|
|
330
345
|
return []
|
|
331
|
-
return [prior_data.FactorSpec(
|
|
346
|
+
return [prior_data.FactorSpec(hr.name, [(PRICE_NODE, None, 1.0)], 1.0, PRICE_PRIOR_SD ** 2,
|
|
332
347
|
f"{PRICE_NODE} held at 1, prior N(1, {PRICE_PRIOR_SD}^2)")]
|
|
333
348
|
|
|
334
349
|
|
|
@@ -417,18 +432,21 @@ def seed_for(fit_id: str, head: str) -> int:
|
|
|
417
432
|
|
|
418
433
|
|
|
419
434
|
def input_key(heads_rows: dict[str, HeadRows], specs: list, settings: dict) -> str:
|
|
420
|
-
"""The fit's `seed_key` (spec 04 section 3): the sha256 of the
|
|
435
|
+
"""The fit's `seed_key` (spec 04 section 3): the sha256 of the seed version, the settings that change the
|
|
421
436
|
posterior, the prior factors and every head's rows (terms, response, weight, run, source), each head's rows
|
|
422
437
|
sorted, so the same data and settings seed the same draws whatever the store's reading order.
|
|
423
438
|
|
|
424
439
|
A success row's weight is its q. With `outcome.q` configured, the key takes each row's q under the built-in
|
|
425
|
-
map (`HeadRows.seed_w`), so setting q redraws nothing: only the success head's posterior moves (0.2.7).
|
|
440
|
+
map (`HeadRows.seed_w`), so setting q redraws nothing: only the success head's posterior moves (0.2.7).
|
|
441
|
+
|
|
442
|
+
From 0.2.8 the key reads 0.2.7's heads: the tokens rows, which no head fits any more, and not the rate rows,
|
|
443
|
+
with the seed version 0.2.7 hashed as its design version. The same data seeds the same draws as in 0.2.7."""
|
|
426
444
|
h = hashlib.sha256()
|
|
427
|
-
h.update(repr((
|
|
445
|
+
h.update(repr((SEED_VERSION, design_rows.TIMEBOX_EFFORT_COST, design_rows.TIMEBOX_LEVELS,
|
|
428
446
|
sorted(settings.items()))).encode())
|
|
429
447
|
for spec in specs:
|
|
430
448
|
h.update(repr((spec.head, spec.terms, spec.mean, spec.var)).encode())
|
|
431
|
-
for name in sorted(heads_rows):
|
|
449
|
+
for name in sorted(n for n in heads_rows if n not in NOT_KEYED):
|
|
432
450
|
hr = heads_rows[name]
|
|
433
451
|
h.update(f"\n{name}:{len(hr.rows)}".encode())
|
|
434
452
|
weights = hr.seed_w or hr.w
|
|
@@ -618,9 +636,12 @@ def fit(home: Path, *, no_prior: bool = False, without: tuple[str, ...] = (), fu
|
|
|
618
636
|
continue
|
|
619
637
|
nodes = horizon_nodes(hr.rows)
|
|
620
638
|
if nodes: # the horizon priors, --no-prior included (spec 04 section 1)
|
|
621
|
-
head_specs += horizon_specs(name, hr.kind, nodes)
|
|
622
|
-
if name
|
|
639
|
+
head_specs += horizon_specs(name, "rate" if name == "rate" else hr.kind, nodes)
|
|
640
|
+
if name in ("cost", "rate"): # the price offset (spec 04 section 2)
|
|
623
641
|
head_specs += price_spec(hr)
|
|
642
|
+
if name in KEY_ONLY: # 0.2.7's tokens head: its nodes enter the index where they did, unfitted
|
|
643
|
+
build_matrix(hr.rows, forest, [(n, p) for spec in head_specs for n, p, _ in spec.terms])
|
|
644
|
+
continue
|
|
624
645
|
fitted[name] = fit_head(hr, forest, head_specs, eb=eb)
|
|
625
646
|
fit_id = new_fit_id(fits, now)
|
|
626
647
|
partial = fits / f"{fit_id}.partial"
|
|
@@ -685,6 +706,8 @@ def fit(home: Path, *, no_prior: bool = False, without: tuple[str, ...] = (), fu
|
|
|
685
706
|
"features": {**tally.report, **({"error": features_error} if features_error else {})},
|
|
686
707
|
"horizons": tally.horizon_report(),
|
|
687
708
|
"price_offsets": heads_rows["cost"].prices,
|
|
709
|
+
# the cheapest rate of each priced model, $ per token: a draw's tokens never cost less (spec 04 section 3)
|
|
710
|
+
"rate_floors": rate_floors(design_rows._price_table()),
|
|
688
711
|
}
|
|
689
712
|
if full:
|
|
690
713
|
meta["full"] = _full_check(fitted)
|
|
@@ -394,7 +394,7 @@ def _condition_head(head: HeadState, terms: Sequence[tuple], tau2: float) -> Hea
|
|
|
394
394
|
def conditioned(state: FitState, task: Task, config: Configuration, rule: AcceptanceRule | None = None) -> FitState:
|
|
395
395
|
heads = dict(state.heads)
|
|
396
396
|
terms, n_obs = _explore_cost_obs(state, task, config)
|
|
397
|
-
for name in ("cost", "
|
|
397
|
+
for name in ("cost", "rate"):
|
|
398
398
|
heads[name] = _condition_head(state.heads[name], terms, state.heads[name].sigma ** 2 / n_obs)
|
|
399
399
|
run_terms = state.task_terms(task) + list(state._plan(config)["run"])
|
|
400
400
|
succ = state.heads["success"]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
"""The price offset on the cost
|
|
1
|
+
"""The price offset on the cost and rate heads (spec 04 section 2, 0.2.2), and the rate floors (0.2.8).
|
|
2
2
|
|
|
3
|
-
A model's run cost moves with its list price. Every cost row of a model version `m
|
|
4
|
-
|
|
3
|
+
A model's run cost moves with its list price. Every cost row of a model version `m`, and from 0.2.8 every rate
|
|
4
|
+
row (the price per token), carries the fixed term `price:offset` (not the gate, success or score rows), with
|
|
5
|
+
the value
|
|
5
6
|
|
|
6
7
|
o_m = s_m * log(P_m / R_m), s_m = n0 / (n0 + n_m),
|
|
7
8
|
|
|
@@ -18,6 +19,10 @@ the same at fit and at prediction:
|
|
|
18
19
|
|
|
19
20
|
`fit_offsets` computes the offset of every model with cost rows and of every model in the price table once per
|
|
20
21
|
fit; `meta.json` `price_offsets` stores them, and prediction and the workflow search read them from there.
|
|
22
|
+
|
|
23
|
+
`rate_floors` gives each priced model's cache-read rate in $ per token, the cheapest rate any of its tokens
|
|
24
|
+
bills at (in every row of the packaged table, no nonzero rate is lower). A draw's price per token is held at or
|
|
25
|
+
above it, so its tokens never cost less than its dollars (spec 04 section 3). `meta.json` stores them too.
|
|
21
26
|
"""
|
|
22
27
|
|
|
23
28
|
from __future__ import annotations
|
|
@@ -140,3 +145,17 @@ def price_term(offsets: Mapping[str, float] | None, model: str) -> tuple[tuple[s
|
|
|
140
145
|
return ()
|
|
141
146
|
o = offsets.get(model)
|
|
142
147
|
return ((PRICE_NODE, None, float(o)),) if o else ()
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def rate_floors(table) -> dict[str, float]:
|
|
151
|
+
"""Model (canonical id) to its cache-read rate in $ per token, for every model with a positive one; empty
|
|
152
|
+
without a table. Two table keys of one model keep the lower rate."""
|
|
153
|
+
out: dict[str, float] = {}
|
|
154
|
+
if table is None:
|
|
155
|
+
return out
|
|
156
|
+
for key, rate in table.rates.items():
|
|
157
|
+
floor = float(rate.get("cache_read") or 0.0) / 1e6
|
|
158
|
+
if floor > 0:
|
|
159
|
+
model = canonical_model_id(key)
|
|
160
|
+
out[model] = min(floor, out.get(model, floor))
|
|
161
|
+
return dict(sorted(out.items()))
|