universal-physics-tensor 0.47.1 → 1.0.1
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.
- package/LICENSE +21 -21
- package/README.md +396 -383
- package/bin/upt.mjs +7 -1
- package/dist/atlas/benchmark/hybrid-retrieval.d.ts +108 -0
- package/dist/atlas/benchmark/hybrid-retrieval.d.ts.map +1 -0
- package/dist/atlas/benchmark/hybrid-retrieval.js +241 -0
- package/dist/atlas/benchmark/hybrid-retrieval.js.map +1 -0
- package/dist/atlas/catalog-formal-ref.d.ts +24 -0
- package/dist/atlas/catalog-formal-ref.d.ts.map +1 -0
- package/dist/atlas/catalog-formal-ref.js +36 -0
- package/dist/atlas/catalog-formal-ref.js.map +1 -0
- package/dist/atlas/composition-table.d.ts +11 -46
- package/dist/atlas/composition-table.d.ts.map +1 -1
- package/dist/atlas/composition-table.js +7 -124
- package/dist/atlas/composition-table.js.map +1 -1
- package/dist/atlas/conventions.d.ts +4 -58
- package/dist/atlas/conventions.d.ts.map +1 -1
- package/dist/atlas/conventions.js +3 -88
- package/dist/atlas/conventions.js.map +1 -1
- package/dist/atlas/derive-evidence.d.ts +50 -3
- package/dist/atlas/derive-evidence.d.ts.map +1 -1
- package/dist/atlas/derive-evidence.js +73 -4
- package/dist/atlas/derive-evidence.js.map +1 -1
- package/dist/atlas/diffusion/bridges-closure.d.ts.map +1 -1
- package/dist/atlas/diffusion/bridges-closure.js +5 -1
- package/dist/atlas/diffusion/bridges-closure.js.map +1 -1
- package/dist/atlas/index.d.ts +9 -7
- package/dist/atlas/index.d.ts.map +1 -1
- package/dist/atlas/index.js +6 -5
- package/dist/atlas/index.js.map +1 -1
- package/dist/atlas/oscillators/bridges-exact.d.ts.map +1 -1
- package/dist/atlas/oscillators/bridges-exact.js +6 -0
- package/dist/atlas/oscillators/bridges-exact.js.map +1 -1
- package/dist/atlas/oscillators/bridges-limits.d.ts +2 -0
- package/dist/atlas/oscillators/bridges-limits.d.ts.map +1 -1
- package/dist/atlas/oscillators/bridges-limits.js +11 -19
- package/dist/atlas/oscillators/bridges-limits.js.map +1 -1
- package/dist/atlas/oscillators/limit-witnesses.d.ts +93 -0
- package/dist/atlas/oscillators/limit-witnesses.d.ts.map +1 -0
- package/dist/atlas/oscillators/limit-witnesses.js +152 -0
- package/dist/atlas/oscillators/limit-witnesses.js.map +1 -0
- package/dist/atlas/oscillators/models.d.ts +2 -1
- package/dist/atlas/oscillators/models.d.ts.map +1 -1
- package/dist/atlas/oscillators/models.js +4 -3
- package/dist/atlas/oscillators/models.js.map +1 -1
- package/dist/atlas/oscillators/norm-transport-witness.d.ts +37 -0
- package/dist/atlas/oscillators/norm-transport-witness.d.ts.map +1 -0
- package/dist/atlas/oscillators/norm-transport-witness.js +58 -0
- package/dist/atlas/oscillators/norm-transport-witness.js.map +1 -0
- package/dist/atlas/oscillators/norm-transport.d.ts +44 -0
- package/dist/atlas/oscillators/norm-transport.d.ts.map +1 -0
- package/dist/atlas/oscillators/norm-transport.js +66 -0
- package/dist/atlas/oscillators/norm-transport.js.map +1 -0
- package/dist/atlas/oscillators/norms.d.ts +11 -0
- package/dist/atlas/oscillators/norms.d.ts.map +1 -0
- package/dist/atlas/oscillators/norms.js +11 -0
- package/dist/atlas/oscillators/norms.js.map +1 -0
- package/dist/atlas/oscillators/pendulum-motion.d.ts +38 -0
- package/dist/atlas/oscillators/pendulum-motion.d.ts.map +1 -0
- package/dist/atlas/oscillators/pendulum-motion.js +122 -0
- package/dist/atlas/oscillators/pendulum-motion.js.map +1 -0
- package/dist/atlas/oscillators/phase-carriage.d.ts +38 -0
- package/dist/atlas/oscillators/phase-carriage.d.ts.map +1 -0
- package/dist/atlas/oscillators/phase-carriage.js +96 -0
- package/dist/atlas/oscillators/phase-carriage.js.map +1 -0
- package/dist/atlas/oscillators/phase-translation.d.ts +46 -0
- package/dist/atlas/oscillators/phase-translation.d.ts.map +1 -0
- package/dist/atlas/oscillators/phase-translation.js +178 -0
- package/dist/atlas/oscillators/phase-translation.js.map +1 -0
- package/dist/atlas/oscillators/position-translation.d.ts +59 -0
- package/dist/atlas/oscillators/position-translation.d.ts.map +1 -0
- package/dist/atlas/oscillators/position-translation.js +254 -0
- package/dist/atlas/oscillators/position-translation.js.map +1 -0
- package/dist/atlas/path-bound.d.ts +126 -9
- package/dist/atlas/path-bound.d.ts.map +1 -1
- package/dist/atlas/path-bound.js +372 -23
- package/dist/atlas/path-bound.js.map +1 -1
- package/dist/atlas/physjs-ref.d.ts +112 -0
- package/dist/atlas/physjs-ref.d.ts.map +1 -0
- package/dist/atlas/physjs-ref.js +842 -0
- package/dist/atlas/physjs-ref.js.map +1 -0
- package/dist/atlas/regime.d.ts +12 -136
- package/dist/atlas/regime.d.ts.map +1 -1
- package/dist/atlas/regime.js +8 -254
- package/dist/atlas/regime.js.map +1 -1
- package/dist/atlas/serialize.d.ts.map +1 -1
- package/dist/atlas/serialize.js +25 -0
- package/dist/atlas/serialize.js.map +1 -1
- package/dist/atlas/translation-registry.d.ts +22 -0
- package/dist/atlas/translation-registry.d.ts.map +1 -0
- package/dist/atlas/translation-registry.js +31 -0
- package/dist/atlas/translation-registry.js.map +1 -0
- package/dist/atlas/translation.d.ts +116 -0
- package/dist/atlas/translation.d.ts.map +1 -0
- package/dist/atlas/translation.js +34 -0
- package/dist/atlas/translation.js.map +1 -0
- package/dist/atlas/types.d.ts +74 -240
- package/dist/atlas/types.d.ts.map +1 -1
- package/dist/atlas/types.js +5 -37
- package/dist/atlas/types.js.map +1 -1
- package/dist/atlas/waves/bridges-closure.d.ts.map +1 -1
- package/dist/atlas/waves/bridges-closure.js +4 -0
- package/dist/atlas/waves/bridges-closure.js.map +1 -1
- package/dist/atlas/waves/bridges.d.ts.map +1 -1
- package/dist/atlas/waves/bridges.js +3 -0
- package/dist/atlas/waves/bridges.js.map +1 -1
- package/dist/atlas/waves/models.js +1 -1
- package/dist/atlas/waves/models.js.map +1 -1
- package/dist/atlas/witness-dominance.d.ts +50 -0
- package/dist/atlas/witness-dominance.d.ts.map +1 -0
- package/dist/atlas/witness-dominance.js +86 -0
- package/dist/atlas/witness-dominance.js.map +1 -0
- package/dist/atlas/witness-specs.d.ts +30 -0
- package/dist/atlas/witness-specs.d.ts.map +1 -1
- package/dist/atlas/witness-specs.js +107 -0
- package/dist/atlas/witness-specs.js.map +1 -1
- package/dist/bridges/be53-yang-mills-confrontation.d.ts +81 -0
- package/dist/bridges/be53-yang-mills-confrontation.d.ts.map +1 -0
- package/dist/bridges/be53-yang-mills-confrontation.js +110 -0
- package/dist/bridges/be53-yang-mills-confrontation.js.map +1 -0
- package/dist/bridges/confrontations.d.ts +1 -1
- package/dist/bridges/confrontations.d.ts.map +1 -1
- package/dist/bridges/confrontations.js +291 -3
- package/dist/bridges/confrontations.js.map +1 -1
- package/dist/bridges/equations/be-13-einstein-trace.d.ts +2 -3
- package/dist/bridges/equations/be-13-einstein-trace.d.ts.map +1 -1
- package/dist/bridges/equations/be-13-einstein-trace.js +2 -3
- package/dist/bridges/equations/be-13-einstein-trace.js.map +1 -1
- package/dist/bridges/equations/be-38-mond.d.ts +7 -5
- package/dist/bridges/equations/be-38-mond.d.ts.map +1 -1
- package/dist/bridges/equations/be-38-mond.js +7 -5
- package/dist/bridges/equations/be-38-mond.js.map +1 -1
- package/dist/bridges/equations/be-53-yang-mills-beta.d.ts +21 -0
- package/dist/bridges/equations/be-53-yang-mills-beta.d.ts.map +1 -1
- package/dist/bridges/equations/be-53-yang-mills-beta.js +12 -0
- package/dist/bridges/equations/be-53-yang-mills-beta.js.map +1 -1
- package/dist/bridges/evaluator-inputs.d.ts +21 -0
- package/dist/bridges/evaluator-inputs.d.ts.map +1 -0
- package/dist/bridges/evaluator-inputs.js +75 -0
- package/dist/bridges/evaluator-inputs.js.map +1 -0
- package/dist/bridges/evaluators.d.ts +38 -0
- package/dist/bridges/evaluators.d.ts.map +1 -1
- package/dist/bridges/evaluators.js +41 -15
- package/dist/bridges/evaluators.js.map +1 -1
- package/dist/bridges/gravitational-lensing.d.ts +1 -1
- package/dist/bridges/gravitational-lensing.js +1 -1
- package/dist/bridges/index.d.ts +1 -1
- package/dist/bridges/index.d.ts.map +1 -1
- package/dist/bridges/index.js +13 -13
- package/dist/bridges/index.js.map +1 -1
- package/dist/bridges/observations/types.d.ts +110 -2
- package/dist/bridges/observations/types.d.ts.map +1 -1
- package/dist/bridges/observations/types.js +29 -0
- package/dist/bridges/observations/types.js.map +1 -1
- package/dist/bridges/perihelion-precession.d.ts +1 -1
- package/dist/bridges/perihelion-precession.js +1 -1
- package/dist/canonical/canonical-equation.d.ts +1 -1
- package/dist/canonical/canonical-equation.d.ts.map +1 -1
- package/dist/canonical/entries/atomic.d.ts.map +1 -1
- package/dist/canonical/entries/atomic.js +32 -10
- package/dist/canonical/entries/atomic.js.map +1 -1
- package/dist/canonical/entries/dimensional-classics.js +2 -2
- package/dist/canonical/entries/dimensional-classics.js.map +1 -1
- package/dist/canonical/entries/mechanics.d.ts.map +1 -1
- package/dist/canonical/entries/mechanics.js +10 -6
- package/dist/canonical/entries/mechanics.js.map +1 -1
- package/dist/canonical/entries/relativity.d.ts.map +1 -1
- package/dist/canonical/entries/relativity.js +41 -8
- package/dist/canonical/entries/relativity.js.map +1 -1
- package/dist/canonical/entries/thermo-nuclear-cosmo.js +5 -5
- package/dist/canonical/entries/thermo-nuclear-cosmo.js.map +1 -1
- package/dist/canonical/linkage.d.ts.map +1 -1
- package/dist/canonical/linkage.js +14 -8
- package/dist/canonical/linkage.js.map +1 -1
- package/dist/canonical/normal-form.d.ts +17 -0
- package/dist/canonical/normal-form.d.ts.map +1 -1
- package/dist/canonical/normal-form.js +21 -4
- package/dist/canonical/normal-form.js.map +1 -1
- package/dist/cases/brownian-sphere.d.ts +68 -0
- package/dist/cases/brownian-sphere.d.ts.map +1 -0
- package/dist/cases/brownian-sphere.js +353 -0
- package/dist/cases/brownian-sphere.js.map +1 -0
- package/dist/cases/damped-resonator.d.ts +23 -0
- package/dist/cases/damped-resonator.d.ts.map +1 -0
- package/dist/cases/damped-resonator.js +224 -0
- package/dist/cases/damped-resonator.js.map +1 -0
- package/dist/cases/index.d.ts +11 -0
- package/dist/cases/index.d.ts.map +1 -0
- package/dist/cases/index.js +29 -0
- package/dist/cases/index.js.map +1 -0
- package/dist/cases/kepler-rv.d.ts +13 -0
- package/dist/cases/kepler-rv.d.ts.map +1 -0
- package/dist/cases/kepler-rv.js +168 -0
- package/dist/cases/kepler-rv.js.map +1 -0
- package/dist/cases/lumped-cooling.d.ts +46 -0
- package/dist/cases/lumped-cooling.d.ts.map +1 -0
- package/dist/cases/lumped-cooling.js +261 -0
- package/dist/cases/lumped-cooling.js.map +1 -0
- package/dist/cases/quadrature.d.ts +14 -0
- package/dist/cases/quadrature.d.ts.map +1 -0
- package/dist/cases/quadrature.js +41 -0
- package/dist/cases/quadrature.js.map +1 -0
- package/dist/cases/resistor-noise.d.ts +14 -0
- package/dist/cases/resistor-noise.d.ts.map +1 -0
- package/dist/cases/resistor-noise.js +210 -0
- package/dist/cases/resistor-noise.js.map +1 -0
- package/dist/cases/skin-depth.d.ts +21 -0
- package/dist/cases/skin-depth.d.ts.map +1 -0
- package/dist/cases/skin-depth.js +174 -0
- package/dist/cases/skin-depth.js.map +1 -0
- package/dist/cases/types.d.ts +115 -0
- package/dist/cases/types.d.ts.map +1 -0
- package/dist/cases/types.js +20 -0
- package/dist/cases/types.js.map +1 -0
- package/dist/cli/commands/_atlas-map.d.ts +409 -0
- package/dist/cli/commands/_atlas-map.d.ts.map +1 -0
- package/dist/cli/commands/_atlas-map.js +1014 -0
- package/dist/cli/commands/_atlas-map.js.map +1 -0
- package/dist/cli/commands/_atlas-route.d.ts +111 -0
- package/dist/cli/commands/_atlas-route.d.ts.map +1 -0
- package/dist/cli/commands/_atlas-route.js +140 -0
- package/dist/cli/commands/_atlas-route.js.map +1 -0
- package/dist/cli/commands/_discovery-opts.d.ts.map +1 -1
- package/dist/cli/commands/_discovery-opts.js +10 -1
- package/dist/cli/commands/_discovery-opts.js.map +1 -1
- package/dist/cli/commands/atlas.d.ts +20 -0
- package/dist/cli/commands/atlas.d.ts.map +1 -1
- package/dist/cli/commands/atlas.js +333 -19
- package/dist/cli/commands/atlas.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +12 -3
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/axes.js +4 -4
- package/dist/cli/commands/candidates.d.ts.map +1 -1
- package/dist/cli/commands/candidates.js +3 -2
- package/dist/cli/commands/candidates.js.map +1 -1
- package/dist/cli/commands/canonical.d.ts.map +1 -1
- package/dist/cli/commands/canonical.js +39 -10
- package/dist/cli/commands/canonical.js.map +1 -1
- package/dist/cli/commands/confront.d.ts.map +1 -1
- package/dist/cli/commands/confront.js +210 -28
- package/dist/cli/commands/confront.js.map +1 -1
- package/dist/cli/commands/connectors.d.ts.map +1 -1
- package/dist/cli/commands/connectors.js +5 -4
- package/dist/cli/commands/connectors.js.map +1 -1
- package/dist/cli/commands/coverage.js +3 -3
- package/dist/cli/commands/derive.d.ts.map +1 -1
- package/dist/cli/commands/derive.js +21 -9
- package/dist/cli/commands/derive.js.map +1 -1
- package/dist/cli/commands/discover.d.ts.map +1 -1
- package/dist/cli/commands/discover.js +149 -32
- package/dist/cli/commands/discover.js.map +1 -1
- package/dist/cli/commands/eval.d.ts.map +1 -1
- package/dist/cli/commands/eval.js +76 -17
- package/dist/cli/commands/eval.js.map +1 -1
- package/dist/cli/commands/evaluate.d.ts +30 -0
- package/dist/cli/commands/evaluate.d.ts.map +1 -1
- package/dist/cli/commands/evaluate.js +440 -25
- package/dist/cli/commands/evaluate.js.map +1 -1
- package/dist/cli/commands/explain.d.ts.map +1 -1
- package/dist/cli/commands/explain.js +38 -11
- package/dist/cli/commands/explain.js.map +1 -1
- package/dist/cli/commands/frontier.d.ts +3 -0
- package/dist/cli/commands/frontier.d.ts.map +1 -0
- package/dist/cli/commands/frontier.js +28 -0
- package/dist/cli/commands/frontier.js.map +1 -0
- package/dist/cli/commands/ground.d.ts.map +1 -1
- package/dist/cli/commands/ground.js +37 -12
- package/dist/cli/commands/ground.js.map +1 -1
- package/dist/cli/commands/index.d.ts +5 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +5 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/map.d.ts +8 -0
- package/dist/cli/commands/map.d.ts.map +1 -1
- package/dist/cli/commands/map.js +385 -57
- package/dist/cli/commands/map.js.map +1 -1
- package/dist/cli/commands/metric.d.ts +3 -0
- package/dist/cli/commands/metric.d.ts.map +1 -0
- package/dist/cli/commands/metric.js +136 -0
- package/dist/cli/commands/metric.js.map +1 -0
- package/dist/cli/commands/path.d.ts +109 -1
- package/dist/cli/commands/path.d.ts.map +1 -1
- package/dist/cli/commands/path.js +1019 -109
- package/dist/cli/commands/path.js.map +1 -1
- package/dist/cli/commands/predict.d.ts.map +1 -1
- package/dist/cli/commands/predict.js +3 -2
- package/dist/cli/commands/predict.js.map +1 -1
- package/dist/cli/commands/priority.d.ts.map +1 -1
- package/dist/cli/commands/priority.js +3 -2
- package/dist/cli/commands/priority.js.map +1 -1
- package/dist/cli/commands/probe.d.ts +7 -0
- package/dist/cli/commands/probe.d.ts.map +1 -1
- package/dist/cli/commands/probe.js +234 -52
- package/dist/cli/commands/probe.js.map +1 -1
- package/dist/cli/commands/recover.d.ts.map +1 -1
- package/dist/cli/commands/recover.js +17 -6
- package/dist/cli/commands/recover.js.map +1 -1
- package/dist/cli/commands/regime.d.ts +1 -1
- package/dist/cli/commands/regime.d.ts.map +1 -1
- package/dist/cli/commands/regime.js +134 -33
- package/dist/cli/commands/regime.js.map +1 -1
- package/dist/cli/commands/retrieve.d.ts +3 -0
- package/dist/cli/commands/retrieve.d.ts.map +1 -0
- package/dist/cli/commands/retrieve.js +65 -0
- package/dist/cli/commands/retrieve.js.map +1 -0
- package/dist/cli/commands/search.d.ts +3 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/search.js +70 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/symbolic.d.ts.map +1 -1
- package/dist/cli/commands/symbolic.js +107 -16
- package/dist/cli/commands/symbolic.js.map +1 -1
- package/dist/cli/commands/testplan.d.ts +3 -0
- package/dist/cli/commands/testplan.d.ts.map +1 -0
- package/dist/cli/commands/testplan.js +131 -0
- package/dist/cli/commands/testplan.js.map +1 -0
- package/dist/cli/conventions.d.ts +22 -0
- package/dist/cli/conventions.d.ts.map +1 -0
- package/dist/cli/conventions.js +48 -0
- package/dist/cli/conventions.js.map +1 -0
- package/dist/cli/euler-guard.d.ts +9 -0
- package/dist/cli/euler-guard.d.ts.map +1 -0
- package/dist/cli/euler-guard.js +11 -0
- package/dist/cli/euler-guard.js.map +1 -0
- package/dist/cli/eval-numbers.d.ts +26 -0
- package/dist/cli/eval-numbers.d.ts.map +1 -0
- package/dist/cli/eval-numbers.js +49 -0
- package/dist/cli/eval-numbers.js.map +1 -0
- package/dist/cli/expr-print.d.ts +25 -0
- package/dist/cli/expr-print.d.ts.map +1 -0
- package/dist/cli/expr-print.js +123 -0
- package/dist/cli/expr-print.js.map +1 -0
- package/dist/cli/graphs.d.ts +26 -0
- package/dist/cli/graphs.d.ts.map +1 -1
- package/dist/cli/graphs.js +19 -0
- package/dist/cli/graphs.js.map +1 -1
- package/dist/cli/main.d.ts +4 -10
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +370 -167
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/map-evidence.d.ts +47 -0
- package/dist/cli/map-evidence.d.ts.map +1 -0
- package/dist/cli/map-evidence.js +53 -0
- package/dist/cli/map-evidence.js.map +1 -0
- package/dist/cli/output.d.ts +21 -1
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +5 -1
- package/dist/cli/output.js.map +1 -1
- package/dist/{composition → cli}/poster-source.d.ts +3 -2
- package/dist/cli/poster-source.d.ts.map +1 -0
- package/dist/{composition → cli}/poster-source.js +2 -1
- package/dist/cli/poster-source.js.map +1 -0
- package/dist/cli/record-reach.d.ts +44 -0
- package/dist/cli/record-reach.d.ts.map +1 -0
- package/dist/cli/record-reach.js +228 -0
- package/dist/cli/record-reach.js.map +1 -0
- package/dist/cli/record-tables.d.ts +38 -0
- package/dist/cli/record-tables.d.ts.map +1 -0
- package/dist/cli/record-tables.js +110 -0
- package/dist/cli/record-tables.js.map +1 -0
- package/dist/cli/record.d.ts +141 -0
- package/dist/cli/record.d.ts.map +1 -0
- package/dist/cli/record.js +612 -0
- package/dist/cli/record.js.map +1 -0
- package/dist/cli/search-index.d.ts +56 -0
- package/dist/cli/search-index.d.ts.map +1 -0
- package/dist/cli/search-index.js +190 -0
- package/dist/cli/search-index.js.map +1 -0
- package/dist/cli/statuses.d.ts +25 -0
- package/dist/cli/statuses.d.ts.map +1 -0
- package/dist/cli/statuses.js +276 -0
- package/dist/cli/statuses.js.map +1 -0
- package/dist/cli/version.d.ts +8 -0
- package/dist/cli/version.d.ts.map +1 -1
- package/dist/cli/version.js +32 -1
- package/dist/cli/version.js.map +1 -1
- package/dist/cli-api.d.ts +33 -15
- package/dist/cli-api.d.ts.map +1 -1
- package/dist/cli-api.js +31 -11
- package/dist/cli-api.js.map +1 -1
- package/dist/composition/bridge-analysis.d.ts.map +1 -1
- package/dist/composition/bridge-analysis.js +2 -1
- package/dist/composition/bridge-analysis.js.map +1 -1
- package/dist/composition/canonical-compare.d.ts +29 -16
- package/dist/composition/canonical-compare.d.ts.map +1 -1
- package/dist/composition/canonical-compare.js +355 -59
- package/dist/composition/canonical-compare.js.map +1 -1
- package/dist/composition/canonical-graph.d.ts +2 -2
- package/dist/composition/canonical-graph.js +3 -3
- package/dist/composition/canonical-graph.js.map +1 -1
- package/dist/composition/canonical-prefactors.d.ts +24 -1
- package/dist/composition/canonical-prefactors.d.ts.map +1 -1
- package/dist/composition/canonical-prefactors.js +97 -1
- package/dist/composition/canonical-prefactors.js.map +1 -1
- package/dist/composition/compose-symbolic.js +1 -1
- package/dist/composition/compose-symbolic.js.map +1 -1
- package/dist/composition/compose.d.ts.map +1 -1
- package/dist/composition/compose.js +17 -9
- package/dist/composition/compose.js.map +1 -1
- package/dist/composition/composition-recovery.d.ts +47 -0
- package/dist/composition/composition-recovery.d.ts.map +1 -0
- package/dist/composition/composition-recovery.js +77 -0
- package/dist/composition/composition-recovery.js.map +1 -0
- package/dist/composition/consequence.d.ts +39 -0
- package/dist/composition/consequence.d.ts.map +1 -1
- package/dist/composition/consequence.js +37 -0
- package/dist/composition/consequence.js.map +1 -1
- package/dist/composition/discovery.d.ts +20 -0
- package/dist/composition/discovery.d.ts.map +1 -1
- package/dist/composition/discovery.js +27 -5
- package/dist/composition/discovery.js.map +1 -1
- package/dist/composition/edge.d.ts +1 -1
- package/dist/composition/edge.d.ts.map +1 -1
- package/dist/composition/edge.js.map +1 -1
- package/dist/composition/edges/_catalog-helpers.d.ts +4 -0
- package/dist/composition/edges/_catalog-helpers.d.ts.map +1 -1
- package/dist/composition/edges/_catalog-helpers.js +15 -0
- package/dist/composition/edges/_catalog-helpers.js.map +1 -1
- package/dist/composition/edges/calibration.d.ts.map +1 -1
- package/dist/composition/edges/calibration.js +57 -0
- package/dist/composition/edges/calibration.js.map +1 -1
- package/dist/composition/edges/catalog-fields.d.ts.map +1 -1
- package/dist/composition/edges/catalog-fields.js +2 -1
- package/dist/composition/edges/catalog-fields.js.map +1 -1
- package/dist/composition/edges/catalog-gravitation-cosmology.d.ts.map +1 -1
- package/dist/composition/edges/catalog-gravitation-cosmology.js +2 -1
- package/dist/composition/edges/catalog-gravitation-cosmology.js.map +1 -1
- package/dist/composition/edges/catalog-quantum.d.ts.map +1 -1
- package/dist/composition/edges/catalog-quantum.js +26 -0
- package/dist/composition/edges/catalog-quantum.js.map +1 -1
- package/dist/composition/edges/catalog-tranche.d.ts.map +1 -1
- package/dist/composition/edges/catalog-tranche.js +2 -1
- package/dist/composition/edges/catalog-tranche.js.map +1 -1
- package/dist/composition/expr-eval.d.ts.map +1 -1
- package/dist/composition/expr-eval.js +4 -1
- package/dist/composition/expr-eval.js.map +1 -1
- package/dist/composition/expr-simplify.js +1 -1
- package/dist/composition/expr-simplify.js.map +1 -1
- package/dist/composition/frontier-account.d.ts +78 -0
- package/dist/composition/frontier-account.d.ts.map +1 -0
- package/dist/composition/frontier-account.js +127 -0
- package/dist/composition/frontier-account.js.map +1 -0
- package/dist/composition/graph-viz.d.ts +7 -22
- package/dist/composition/graph-viz.d.ts.map +1 -1
- package/dist/composition/graph-viz.js +4 -27
- package/dist/composition/graph-viz.js.map +1 -1
- package/dist/composition/grounding.d.ts +49 -0
- package/dist/composition/grounding.d.ts.map +1 -1
- package/dist/composition/grounding.js +38 -0
- package/dist/composition/grounding.js.map +1 -1
- package/dist/composition/index.d.ts +0 -2
- package/dist/composition/index.d.ts.map +1 -1
- package/dist/composition/index.js +1 -1
- package/dist/composition/index.js.map +1 -1
- package/dist/composition/probe/expression-gaps.d.ts +27 -0
- package/dist/composition/probe/expression-gaps.d.ts.map +1 -0
- package/dist/composition/probe/expression-gaps.js +47 -0
- package/dist/composition/probe/expression-gaps.js.map +1 -0
- package/dist/composition/probe/frontier.d.ts +2 -1
- package/dist/composition/probe/frontier.d.ts.map +1 -1
- package/dist/composition/probe/frontier.js +3 -2
- package/dist/composition/probe/frontier.js.map +1 -1
- package/dist/composition/probe/index.d.ts +4 -1
- package/dist/composition/probe/index.d.ts.map +1 -1
- package/dist/composition/probe/index.js +3 -1
- package/dist/composition/probe/index.js.map +1 -1
- package/dist/composition/probe/pipeline.d.ts +2 -0
- package/dist/composition/probe/pipeline.d.ts.map +1 -1
- package/dist/composition/probe/pipeline.js +6 -2
- package/dist/composition/probe/pipeline.js.map +1 -1
- package/dist/composition/probe/problem.d.ts +7 -0
- package/dist/composition/probe/problem.d.ts.map +1 -1
- package/dist/composition/probe/problem.js +15 -5
- package/dist/composition/probe/problem.js.map +1 -1
- package/dist/composition/probe/search-budget.d.ts.map +1 -1
- package/dist/composition/probe/search-budget.js +6 -2
- package/dist/composition/probe/search-budget.js.map +1 -1
- package/dist/composition/probe/study.d.ts +340 -0
- package/dist/composition/probe/study.d.ts.map +1 -0
- package/dist/composition/probe/study.js +1519 -0
- package/dist/composition/probe/study.js.map +1 -0
- package/dist/composition/proposed-bridges.js +1 -1
- package/dist/composition/proposed-bridges.js.map +1 -1
- package/dist/composition/quantities.d.ts +4 -16
- package/dist/composition/quantities.d.ts.map +1 -1
- package/dist/composition/quantities.js +4 -16
- package/dist/composition/quantities.js.map +1 -1
- package/dist/composition/retrodiction.d.ts.map +1 -1
- package/dist/composition/retrodiction.js +6 -2
- package/dist/composition/retrodiction.js.map +1 -1
- package/dist/composition/uncertainty.d.ts +1 -1
- package/dist/composition/uncertainty.d.ts.map +1 -1
- package/dist/composition/user-equation.d.ts +79 -8
- package/dist/composition/user-equation.d.ts.map +1 -1
- package/dist/composition/user-equation.js +224 -32
- package/dist/composition/user-equation.js.map +1 -1
- package/dist/core/constants.d.ts +9 -4
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +9 -4
- package/dist/core/constants.js.map +1 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +2 -1
- package/dist/core/types.js.map +1 -1
- package/dist/dimensional/curvature.d.ts +7 -56
- package/dist/dimensional/curvature.d.ts.map +1 -1
- package/dist/dimensional/curvature.js +7 -76
- package/dist/dimensional/curvature.js.map +1 -1
- package/dist/dimensional/dimension-spec.d.ts +7 -1
- package/dist/dimensional/dimension-spec.d.ts.map +1 -1
- package/dist/dimensional/dimension-spec.js +131 -3
- package/dist/dimensional/dimension-spec.js.map +1 -1
- package/dist/dimensional/formula-names.d.ts +30 -0
- package/dist/dimensional/formula-names.d.ts.map +1 -0
- package/dist/dimensional/formula-names.js +37 -0
- package/dist/dimensional/formula-names.js.map +1 -0
- package/dist/dimensional/natural-units.d.ts +33 -0
- package/dist/dimensional/natural-units.d.ts.map +1 -0
- package/dist/dimensional/natural-units.js +58 -0
- package/dist/dimensional/natural-units.js.map +1 -0
- package/dist/{composition → dimensional}/symbolic-constants.d.ts +21 -2
- package/dist/dimensional/symbolic-constants.d.ts.map +1 -0
- package/dist/dimensional/symbolic-constants.js +116 -0
- package/dist/dimensional/symbolic-constants.js.map +1 -0
- package/dist/dimensional/unit-convention.d.ts +30 -0
- package/dist/dimensional/unit-convention.d.ts.map +1 -0
- package/dist/dimensional/unit-convention.js +60 -0
- package/dist/dimensional/unit-convention.js.map +1 -0
- package/dist/dimensional/units.d.ts +43 -0
- package/dist/dimensional/units.d.ts.map +1 -0
- package/dist/dimensional/units.js +197 -0
- package/dist/dimensional/units.js.map +1 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/numerical/bianchi-residual.d.ts +55 -0
- package/dist/numerical/bianchi-residual.d.ts.map +1 -0
- package/dist/numerical/bianchi-residual.js +79 -0
- package/dist/numerical/bianchi-residual.js.map +1 -0
- package/dist/numerical/binding-value.d.ts +67 -0
- package/dist/numerical/binding-value.d.ts.map +1 -0
- package/dist/numerical/binding-value.js +347 -0
- package/dist/numerical/binding-value.js.map +1 -0
- package/dist/numerical/connection-lowering-helpers.d.ts.map +1 -1
- package/dist/numerical/connection-lowering-helpers.js +13 -26
- package/dist/numerical/connection-lowering-helpers.js.map +1 -1
- package/dist/numerical/curvature-lowering-helpers.d.ts.map +1 -1
- package/dist/numerical/curvature-lowering-helpers.js +9 -0
- package/dist/numerical/curvature-lowering-helpers.js.map +1 -1
- package/dist/numerical/float64-engine.d.ts.map +1 -1
- package/dist/numerical/float64-engine.js +23 -16
- package/dist/numerical/float64-engine.js.map +1 -1
- package/dist/numerical/formula-dimension.d.ts +7 -0
- package/dist/numerical/formula-dimension.d.ts.map +1 -1
- package/dist/numerical/formula-dimension.js +23 -6
- package/dist/numerical/formula-dimension.js.map +1 -1
- package/dist/numerical/formula-mathts.d.ts.map +1 -1
- package/dist/numerical/formula-mathts.js +68 -6
- package/dist/numerical/formula-mathts.js.map +1 -1
- package/dist/numerical/formula.d.ts +27 -0
- package/dist/numerical/formula.d.ts.map +1 -1
- package/dist/numerical/formula.js +68 -6
- package/dist/numerical/formula.js.map +1 -1
- package/dist/numerical/spacetime-metrics.d.ts +243 -0
- package/dist/numerical/spacetime-metrics.d.ts.map +1 -0
- package/dist/numerical/spacetime-metrics.js +1056 -0
- package/dist/numerical/spacetime-metrics.js.map +1 -0
- package/dist/relations/composition-table.d.ts +61 -0
- package/dist/relations/composition-table.d.ts.map +1 -0
- package/dist/relations/composition-table.js +140 -0
- package/dist/relations/composition-table.js.map +1 -0
- package/dist/relations/conventions.d.ts +63 -0
- package/dist/relations/conventions.d.ts.map +1 -0
- package/dist/relations/conventions.js +93 -0
- package/dist/relations/conventions.js.map +1 -0
- package/dist/relations/regime.d.ts +159 -0
- package/dist/relations/regime.d.ts.map +1 -0
- package/dist/relations/regime.js +304 -0
- package/dist/relations/regime.js.map +1 -0
- package/dist/relations/types.d.ts +259 -0
- package/dist/relations/types.d.ts.map +1 -0
- package/dist/relations/types.js +37 -0
- package/dist/relations/types.js.map +1 -0
- package/package.json +166 -163
- package/dist/composition/poster-source.d.ts.map +0 -1
- package/dist/composition/poster-source.js.map +0 -1
- package/dist/composition/symbolic-constants.d.ts.map +0 -1
- package/dist/composition/symbolic-constants.js +0 -65
- package/dist/composition/symbolic-constants.js.map +0 -1
|
@@ -2,26 +2,855 @@ import { registerCommand } from '../command.js';
|
|
|
2
2
|
import { CliError, EXIT_CHECK_FAILED } from '../errors.js';
|
|
3
3
|
import { emitJson } from '../output.js';
|
|
4
4
|
import { parseAt, resolveAtPoint, showInequality } from './regime.js';
|
|
5
|
+
import { readBinding } from '../../numerical/binding-value.js';
|
|
6
|
+
import { explainsRefusal, missingForComposite, routeClaim, selectRoute, transportReport } from './_atlas-route.js';
|
|
5
7
|
const FLAGS = [
|
|
6
8
|
{ name: '--at', valueStyle: 'either', repeatable: true },
|
|
9
|
+
{ name: '--sweep', valueStyle: 'either' },
|
|
10
|
+
{ name: '--compare', valueStyle: 'either' },
|
|
11
|
+
{ name: '--csv', valueStyle: 'none' },
|
|
12
|
+
{ name: '--tolerance', valueStyle: 'attached' },
|
|
7
13
|
{ name: '--json', valueStyle: 'none' },
|
|
8
14
|
];
|
|
9
|
-
const HELP = `upt path <from> <to> [--at group=value ...] [--
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const HELP = `upt path <from> <to> [--at group=value ...] [--tolerance=[observable:]EPS]
|
|
16
|
+
[--sweep name=lo:hi:n[:log]] [--compare=<to2>] [--csv] [--json]
|
|
17
|
+
The chain of bridges from one model to another (across families when
|
|
18
|
+
a bridge ends in another family's model), the relation the chain
|
|
19
|
+
composes to, the composed (K, delta) with the norm it holds in,
|
|
20
|
+
whether every bridge's REGIME holds at --at (the bound is claimed only
|
|
21
|
+
inside it), and whether every horizon still holds (pass t=<time> plus
|
|
22
|
+
the parameters, e.g. --at theta0=0.2 T0=1 t=10).
|
|
23
|
+
When the composition table declines to compose the relations, the path
|
|
24
|
+
carries NO bound: the command prints 'no composite claim' and exits 0.
|
|
25
|
+
That refusal is the answer, and no number is invented in its place.
|
|
26
|
+
An exact equivalence carries a bound only in a norm it DECLARES a
|
|
27
|
+
transport of, in the declared direction, with a witness (ab-spring-lc:
|
|
28
|
+
relative period error, spring → lc; the horizon is restated on the
|
|
29
|
+
circuit clock). Any other norm or direction is refused as
|
|
30
|
+
'norm-not-stated', and the refusal names the missing declaration.
|
|
31
|
+
--at values are numbers, units, or constant expressions (theta0=pi/2).
|
|
32
|
+
A regime or horizon that was checked and failed prints no bound
|
|
33
|
+
number: the domain supremum is not a claim at that point.
|
|
34
|
+
--sweep name=lo:hi:n[:log] evaluates the path at n samples (2 to 200,
|
|
35
|
+
endpoints included) of one parameter not fixed by --at: per row the
|
|
36
|
+
regime, the horizon and the closed-form point error. A row outside a
|
|
37
|
+
regime or past a horizon carries no error, because no bound is claimed
|
|
38
|
+
there. A sweep exits 0: each row is its own verdict. --csv writes the
|
|
39
|
+
rows as CSV.
|
|
40
|
+
--compare=<to2> (with --sweep) sweeps a second route from the same
|
|
41
|
+
source beside the first: per row each route's regime, horizon and
|
|
42
|
+
error in its OWN norm (never compared with the other's), and NEITHER,
|
|
43
|
+
with no number, where no encoded limit applies.
|
|
44
|
+
--tolerance=EPS asks whether the path is accurate enough: ADEQUATE only
|
|
45
|
+
when every regime holds, every horizon holds at the given t, and the
|
|
46
|
+
closed-form point error is <= EPS; INADEQUATE (exit 3) when any of
|
|
47
|
+
them fails; UNDETERMINED when the point does not settle it. EPS is in
|
|
48
|
+
the bound's own norm. With --sweep, each row is judged.
|
|
49
|
+
--tolerance=<observable>:EPS asks in ANOTHER observable, only through
|
|
50
|
+
a translation the first bridge declares (ab-pendulum-linear: phase, the
|
|
51
|
+
exact accumulated error, and position, an upper bound on |θ − θ_lin|;
|
|
52
|
+
both in rad, t in the unit of T0), carried past each later bridge only
|
|
53
|
+
by that bridge's declared carriage (ab-spring-lc carries phase). It
|
|
54
|
+
reports the horizon t* at which the error reaches EPS, ADEQUATE iff
|
|
55
|
+
t <= t* (inclusive; past t* an upper bound is UNDETERMINED, not
|
|
56
|
+
INADEQUATE), and the evidence of the translation and of each carriage,
|
|
57
|
+
derived by running their witnesses, plus the translation's witness
|
|
58
|
+
run at this point with a control. Otherwise it is UNDETERMINED.
|
|
59
|
+
A route may cross families. A bound crosses only through the relation,
|
|
60
|
+
uniformity, Lipschitz, and norm gates, and, across families, only
|
|
61
|
+
through a witnessed norm transport; a matching norm name is not one.
|
|
62
|
+
A bridge with two or more premises is named when both models appear
|
|
63
|
+
among its premises and its conclusion. That line is the bridge; it is
|
|
64
|
+
not a step of the chain, and a missing chain still exits 0.
|
|
65
|
+
e.g. upt path model-pendulum model-spring --at theta0=0.2 T0=1 t=10
|
|
66
|
+
upt path model-pendulum model-spring --at T0=1 t=10 --sweep theta0=0.1:0.8:8
|
|
67
|
+
upt path model-pendulum model-lc --at theta0=0.3 T0=2 t=5 --tolerance=phase:0.1
|
|
68
|
+
upt path model-telegraph model-fick --compare=model-wave-1d --at D=1 q=1 t=1 --sweep tau=0.001:1000:13:log`;
|
|
19
69
|
const EPISTEMICS = 'a path EXISTING is not a warrant: the bound is the warrant. A no-claim carries no number, ' +
|
|
20
70
|
'and none is synthesized for it.';
|
|
71
|
+
/** Bridges with two or more premises that mention both endpoints. Not a chain. */
|
|
72
|
+
function multiPremiseBridges(api, from, to) {
|
|
73
|
+
const rows = [];
|
|
74
|
+
const seen = new Set();
|
|
75
|
+
for (const f of api.ATLAS_FAMILIES) {
|
|
76
|
+
for (const b of f.bridges) {
|
|
77
|
+
if (b.premises.length < 2 || seen.has(b.id))
|
|
78
|
+
continue;
|
|
79
|
+
const ends = new Set([...b.premises, b.conclusion]);
|
|
80
|
+
if (!ends.has(from) || !ends.has(to))
|
|
81
|
+
continue;
|
|
82
|
+
seen.add(b.id);
|
|
83
|
+
rows.push({ id: b.id, premises: [...b.premises], conclusion: b.conclusion });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return rows;
|
|
87
|
+
}
|
|
88
|
+
function printMultiPremise(out, rows) {
|
|
89
|
+
for (const b of rows) {
|
|
90
|
+
out(` multi-premise bridge: ${b.id}: ${b.premises.join(' + ')} → ${b.conclusion}`);
|
|
91
|
+
}
|
|
92
|
+
if (rows.length > 0) {
|
|
93
|
+
out(' A path composes one premise at a time. This bridge needs every premise named above.');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
21
96
|
/** The literal phrase the no-composite-claim case must print. */
|
|
22
97
|
const NO_COMPOSITE_PHRASE = 'no composite claim';
|
|
98
|
+
const MAX_SAMPLES = 200;
|
|
99
|
+
/** `name=lo:hi:n` or `name=lo:hi:n:log`, bounded; the endpoints are both sampled. */
|
|
100
|
+
export function parseSweep(spec) {
|
|
101
|
+
const m = /^([^=\s]+)=([^:]+):([^:]+):([^:]+)(?::(linear|log))?$/.exec(spec);
|
|
102
|
+
if (m === null)
|
|
103
|
+
throw new CliError(`upt path: --sweep '${spec}' is not name=lo:hi:n[:log], e.g. --sweep theta0=0.05:0.9:18`);
|
|
104
|
+
const [, name, loS, hiS, nS, sp] = m;
|
|
105
|
+
const endpoint = (raw) => {
|
|
106
|
+
try {
|
|
107
|
+
return readBinding(raw).value;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return Number.NaN;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const lo = endpoint(loS);
|
|
114
|
+
const hi = endpoint(hiS);
|
|
115
|
+
const n = Number(nS);
|
|
116
|
+
const spacing = sp === 'log' ? 'log' : 'linear';
|
|
117
|
+
if (!Number.isFinite(lo) || !Number.isFinite(hi) || !(lo < hi)) {
|
|
118
|
+
throw new CliError(`upt path: --sweep '${spec}' needs finite lo < hi`);
|
|
119
|
+
}
|
|
120
|
+
if (!Number.isInteger(n) || n < 2 || n > MAX_SAMPLES) {
|
|
121
|
+
throw new CliError(`upt path: --sweep '${spec}' needs an integer sample count from 2 to ${MAX_SAMPLES}`);
|
|
122
|
+
}
|
|
123
|
+
if (spacing === 'log' && lo <= 0)
|
|
124
|
+
throw new CliError(`upt path: --sweep '${spec}' is log-spaced, so lo must be > 0`);
|
|
125
|
+
const values = Array.from({ length: n }, (_, i) => spacing === 'log' ? lo * (hi / lo) ** (i / (n - 1)) : lo + ((hi - lo) * i) / (n - 1));
|
|
126
|
+
return { name, values, spacing };
|
|
127
|
+
}
|
|
128
|
+
function modelFamilyOf(api, id) {
|
|
129
|
+
if (id === null)
|
|
130
|
+
return undefined;
|
|
131
|
+
return api.ATLAS_FAMILIES.find((f) => f.models.some((m) => m.id === id))?.family;
|
|
132
|
+
}
|
|
133
|
+
function filingFamilyOf(api, id) {
|
|
134
|
+
return api.ATLAS_FAMILIES.find((f) => f.bridges.some((b) => b.id === id))?.family;
|
|
135
|
+
}
|
|
136
|
+
/** The model a step leaves, entered at `entry`. An exact step may leave by either end. */
|
|
137
|
+
function leaveModel(bridge, entry) {
|
|
138
|
+
if (bridge.premises.length !== 1)
|
|
139
|
+
return null;
|
|
140
|
+
const premise = bridge.premises[0];
|
|
141
|
+
if (entry === premise)
|
|
142
|
+
return bridge.conclusion;
|
|
143
|
+
if (bridge.relation === 'exact-equivalence' && entry === bridge.conclusion)
|
|
144
|
+
return premise;
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Families of the models a route visits, in order, starting at `from`.
|
|
149
|
+
* Adjacent duplicates collapse. A family visited again after a different one
|
|
150
|
+
* stays in the list. `family` on each step stays the filing family.
|
|
151
|
+
*/
|
|
152
|
+
function routeFamilyLabels(api, bridges, from) {
|
|
153
|
+
const modelFamilies = [];
|
|
154
|
+
const push = (id) => {
|
|
155
|
+
const family = modelFamilyOf(api, id);
|
|
156
|
+
if (family !== undefined && modelFamilies[modelFamilies.length - 1] !== family)
|
|
157
|
+
modelFamilies.push(family);
|
|
158
|
+
return family;
|
|
159
|
+
};
|
|
160
|
+
if (bridges.length === 0) {
|
|
161
|
+
push(from);
|
|
162
|
+
return { crossFamily: false, modelFamilies, steps: [] };
|
|
163
|
+
}
|
|
164
|
+
let at = from;
|
|
165
|
+
const steps = bridges.map((b) => {
|
|
166
|
+
const entry = at;
|
|
167
|
+
const exit = entry === null ? null : leaveModel(b, entry);
|
|
168
|
+
const fromModelFamily = modelFamilies.length === 0 ? push(entry) : modelFamilyOf(api, entry);
|
|
169
|
+
const toModelFamily = push(exit);
|
|
170
|
+
at = exit;
|
|
171
|
+
return {
|
|
172
|
+
id: b.id,
|
|
173
|
+
relation: b.relation,
|
|
174
|
+
from: b.premises[0],
|
|
175
|
+
to: b.conclusion,
|
|
176
|
+
family: filingFamilyOf(api, b.id),
|
|
177
|
+
fromModelFamily,
|
|
178
|
+
toModelFamily,
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
return { crossFamily: modelFamilies.length > 1, modelFamilies, steps };
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The translation a path can use for `observable`: the first bridge's, carried
|
|
185
|
+
* through every later bridge only by that bridge's declared carriage of the
|
|
186
|
+
* same observable. A later bridge without one stops it, whatever its relation.
|
|
187
|
+
*/
|
|
188
|
+
function pathTranslation(api, bridges, observable) {
|
|
189
|
+
const tr = api.translationsOf(bridges[0].id).find((x) => x.observable === observable);
|
|
190
|
+
if (tr === undefined)
|
|
191
|
+
return { tr: null, blockedBy: null };
|
|
192
|
+
const carriages = [];
|
|
193
|
+
for (const b of bridges.slice(1)) {
|
|
194
|
+
const c = api.carriageOf(b.id, observable);
|
|
195
|
+
if (c === undefined)
|
|
196
|
+
return { tr: null, blockedBy: b.id };
|
|
197
|
+
carriages.push(c);
|
|
198
|
+
}
|
|
199
|
+
return { tr, carriages };
|
|
200
|
+
}
|
|
201
|
+
/** The observables a path can be asked in: its first bridge's translations that every later bridge carries. */
|
|
202
|
+
function pathObservables(api, bridges) {
|
|
203
|
+
return api
|
|
204
|
+
.translationsOf(bridges[0].id)
|
|
205
|
+
.filter((t) => pathTranslation(api, bridges, t.observable).tr !== null);
|
|
206
|
+
}
|
|
207
|
+
/** What a tolerance in the bound's own norm is judged in, and what else this path can be asked in. */
|
|
208
|
+
function toleranceScope(api, bridges) {
|
|
209
|
+
const declared = pathObservables(api, bridges);
|
|
210
|
+
if (declared.length === 0) {
|
|
211
|
+
return "judged in the bound's own norm only; no translation to another observable (phase, trajectory, amplitude) is encoded for this path";
|
|
212
|
+
}
|
|
213
|
+
const asks = declared.map((t) => `--tolerance=${t.observable}:EPS (${t.unit})`).join(', ');
|
|
214
|
+
const through = bridges.length > 1 ? `, carried by ${bridges.slice(1).map((b) => b.id).join(', ')}` : '';
|
|
215
|
+
return `judged in the bound's own norm only; ${bridges[0].id} declares a translation${through}, asked with ${asks}`;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Whether the path is adequate for a requested tolerance at one point: every
|
|
219
|
+
* regime holds, every horizon holds at the given t, and the closed-form point
|
|
220
|
+
* error is within it. Anything the point does not settle is `undetermined`,
|
|
221
|
+
* never `adequate`.
|
|
222
|
+
* @internal
|
|
223
|
+
*/
|
|
224
|
+
export function judgeTolerance(tolerance, e, tGiven) {
|
|
225
|
+
if (e.allRegimesHold === false)
|
|
226
|
+
return { verdict: 'inadequate', reason: 'outside a regime on the path: no bound is claimed' };
|
|
227
|
+
if (e.allRegimesHold === 'unknown')
|
|
228
|
+
return { verdict: 'undetermined', reason: 'a regime coordinate was not supplied' };
|
|
229
|
+
if (e.horizons.length > 0 && !tGiven)
|
|
230
|
+
return { verdict: 'undetermined', reason: 'no t= given, so the horizon was not evaluated' };
|
|
231
|
+
if (e.horizons.some((h) => h.holds === false))
|
|
232
|
+
return { verdict: 'inadequate', reason: 'past the horizon: the bound is not claimed there' };
|
|
233
|
+
if (e.horizons.some((h) => h.holds === null)) {
|
|
234
|
+
return { verdict: 'undetermined', reason: 'a family change did not restate a horizon onto the next clock' };
|
|
235
|
+
}
|
|
236
|
+
if (e.horizons.length > 0 && !e.allHold)
|
|
237
|
+
return { verdict: 'inadequate', reason: 'past the horizon: the bound is not claimed there' };
|
|
238
|
+
if (e.pointBound === null)
|
|
239
|
+
return { verdict: 'undetermined', reason: e.pointBoundReason ?? 'no point bound' };
|
|
240
|
+
return e.pointBound.delta <= tolerance
|
|
241
|
+
? { verdict: 'adequate', reason: `error ${e.pointBound.delta} <= tolerance ${tolerance}` }
|
|
242
|
+
: { verdict: 'inadequate', reason: `error ${e.pointBound.delta} exceeds tolerance ${tolerance}` };
|
|
243
|
+
}
|
|
244
|
+
export function parseTolerance(raw) {
|
|
245
|
+
if (raw === undefined)
|
|
246
|
+
return null;
|
|
247
|
+
const colon = raw.indexOf(':');
|
|
248
|
+
const observable = colon === -1 ? null : raw.slice(0, colon);
|
|
249
|
+
const number = colon === -1 ? raw : raw.slice(colon + 1);
|
|
250
|
+
if (observable !== null && !/^[a-z][a-z-]*$/.test(observable)) {
|
|
251
|
+
throw new CliError(`upt path: --tolerance=${raw} is not EPS or <observable>:EPS, e.g. --tolerance=phase:0.1`);
|
|
252
|
+
}
|
|
253
|
+
let v = Number.NaN;
|
|
254
|
+
try {
|
|
255
|
+
if (number !== '')
|
|
256
|
+
v = readBinding(number).value;
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
v = Number.NaN;
|
|
260
|
+
}
|
|
261
|
+
if (number === '' || !Number.isFinite(v) || v <= 0)
|
|
262
|
+
throw new CliError(`upt path: --tolerance=${raw} must be a finite number > 0`);
|
|
263
|
+
return { observable, value: v };
|
|
264
|
+
}
|
|
265
|
+
const showTolerance = (r, unit) => r.observable === null ? String(r.value) : `${r.observable}:${r.value}${unit === undefined ? '' : ` ${unit}`}`;
|
|
266
|
+
/**
|
|
267
|
+
* Whether the path is adequate for a tolerance in another observable. Only a
|
|
268
|
+
* path whose first bridge declares a translation into that observable, and
|
|
269
|
+
* whose every later bridge declares that it carries it, is judged; every
|
|
270
|
+
* regime, the translated bridge's closed-form point value and its own horizon
|
|
271
|
+
* still gate it, and anything the point does not settle is `undetermined`. An
|
|
272
|
+
* upper-bound translation past its horizon is `undetermined` too: there the
|
|
273
|
+
* BOUND exceeds the tolerance, which does not show that the error does.
|
|
274
|
+
* @internal
|
|
275
|
+
*/
|
|
276
|
+
export function judgeObservable(api, request, bridges, e, at) {
|
|
277
|
+
const found = pathTranslation(api, bridges, request.observable);
|
|
278
|
+
const tr = found.tr;
|
|
279
|
+
const first = bridges[0];
|
|
280
|
+
const bound = first.bound;
|
|
281
|
+
const pointValue = e.allRegimesHold === true && bound?.deltaAt !== undefined && bound.deltaAtBasis === 'closed-form' ? bound.deltaAt(at) : null;
|
|
282
|
+
const none = {
|
|
283
|
+
translation: tr,
|
|
284
|
+
carriages: found.tr === null ? [] : found.carriages,
|
|
285
|
+
boundErrorAtPoint: pointValue !== null && Number.isFinite(pointValue) ? pointValue : null,
|
|
286
|
+
domainSupremum: tr === null ? (bridges.length === 1 ? (bound?.delta ?? null) : null) : (bound?.delta ?? null),
|
|
287
|
+
observableErrorAt: null,
|
|
288
|
+
horizon: null,
|
|
289
|
+
domainHorizon: null,
|
|
290
|
+
bridgeHorizonHolds: null,
|
|
291
|
+
};
|
|
292
|
+
if (found.tr === null) {
|
|
293
|
+
const declared = api.translationsOf(first.id);
|
|
294
|
+
const reason = found.blockedBy !== null
|
|
295
|
+
? `${first.id}'s translation into '${request.observable}' does not reach the end of this path: '${found.blockedBy}' ` +
|
|
296
|
+
`declares no carriage of '${request.observable}' through its map, and a translation composes only through one`
|
|
297
|
+
: `no translation from '${bound?.norm ?? 'no bound'}' into '${request.observable}' is encoded for ${first.id}` +
|
|
298
|
+
(declared.length === 0 ? '' : ` (it declares: ${declared.map((x) => x.observable).join(', ')})`);
|
|
299
|
+
return { verdict: 'undetermined', reason, ...none };
|
|
300
|
+
}
|
|
301
|
+
if (e.allRegimesHold === false)
|
|
302
|
+
return { verdict: 'inadequate', reason: 'outside a regime on the path: no bound is claimed', ...none };
|
|
303
|
+
if (e.allRegimesHold === 'unknown')
|
|
304
|
+
return { verdict: 'undetermined', reason: 'a regime coordinate was not supplied', ...none };
|
|
305
|
+
if (bound === undefined || bound.deltaAt === undefined || bound.deltaAtBasis !== 'closed-form') {
|
|
306
|
+
return { verdict: 'undetermined', reason: `${first.id} states no closed-form point value to translate`, ...none };
|
|
307
|
+
}
|
|
308
|
+
if (none.boundErrorAtPoint === null) {
|
|
309
|
+
return { verdict: 'undetermined', reason: 'a parameter the point value needs was not supplied', ...none };
|
|
310
|
+
}
|
|
311
|
+
const missing = found.tr.parameters.filter((p) => at[p] === undefined);
|
|
312
|
+
if (missing.length > 0) {
|
|
313
|
+
return { verdict: 'undetermined', reason: `the translation needs ${missing.join(', ')} (via --at)`, ...none };
|
|
314
|
+
}
|
|
315
|
+
const tx = found.tr;
|
|
316
|
+
const eps = none.boundErrorAtPoint;
|
|
317
|
+
const floor = tx.floor?.(eps);
|
|
318
|
+
if (floor !== undefined && floor > request.value) {
|
|
319
|
+
return {
|
|
320
|
+
verdict: 'undetermined',
|
|
321
|
+
reason: `the translation's time-independent term is ${floor} ${tx.unit} at this point, above the tolerance: this bound ` +
|
|
322
|
+
'certifies no t, which is not a finding that the error exceeds the tolerance',
|
|
323
|
+
...none,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
const horizon = tx.horizonFor(eps, request.value, at);
|
|
327
|
+
const domainHorizon = tx.horizonFor(bound.delta, request.value, at);
|
|
328
|
+
if (Number.isNaN(horizon))
|
|
329
|
+
return { verdict: 'undetermined', reason: 'the translation is undefined at this point', ...none };
|
|
330
|
+
const t = at['t'];
|
|
331
|
+
const judged = { ...none, horizon, domainHorizon: Number.isNaN(domainHorizon) ? null : domainHorizon };
|
|
332
|
+
if (t === undefined) {
|
|
333
|
+
return {
|
|
334
|
+
verdict: 'undetermined',
|
|
335
|
+
reason: `no t= given; the ${tx.observable} horizon here is t* = ${horizon} (${tx.timeUnit})`,
|
|
336
|
+
...judged,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
const observableErrorAt = tx.errorAt(eps, t, at);
|
|
340
|
+
const bridgeHorizonHolds = bound.horizonHolds(t, at);
|
|
341
|
+
const withT = { ...judged, observableErrorAt, bridgeHorizonHolds };
|
|
342
|
+
if (!bridgeHorizonHolds) {
|
|
343
|
+
return { verdict: 'inadequate', reason: `past ${first.id}'s own horizon (${bound.horizon}): the bound is not claimed there`, ...withT };
|
|
344
|
+
}
|
|
345
|
+
const what = tx.errorKind === 'upper-bound' ? `bound on the ${tx.observable} error` : `accumulated ${tx.observable} error`;
|
|
346
|
+
if (t <= horizon) {
|
|
347
|
+
return { verdict: 'adequate', reason: `t = ${t} <= t* = ${horizon}: ${what} ${observableErrorAt} ${tx.unit} <= ${request.value}`, ...withT };
|
|
348
|
+
}
|
|
349
|
+
return tx.errorKind === 'upper-bound'
|
|
350
|
+
? {
|
|
351
|
+
verdict: 'undetermined',
|
|
352
|
+
reason: `t = ${t} > t* = ${horizon}: the ${what} is ${observableErrorAt} ${tx.unit}, above ${request.value}; ` +
|
|
353
|
+
'the error itself may still be within it, so this is not shown inadequate',
|
|
354
|
+
...withT,
|
|
355
|
+
}
|
|
356
|
+
: { verdict: 'inadequate', reason: `t = ${t} > t* = ${horizon}: ${what} ${observableErrorAt} ${tx.unit} exceeds ${request.value}`, ...withT };
|
|
357
|
+
}
|
|
358
|
+
/** Evidence DERIVED by running a record's witnesses now. */
|
|
359
|
+
function runWitnesses(api, witnesses, checks) {
|
|
360
|
+
const runs = checks.map((c) => api.runTranslationCheck(c));
|
|
361
|
+
const passing = new Set(runs.filter((r) => r.status === 'checked').map((r) => r.witnessId));
|
|
362
|
+
return {
|
|
363
|
+
tags: [...api.deriveEvidence({ witnesses }, passing)].sort(),
|
|
364
|
+
witnesses: runs.map((r) => ({
|
|
365
|
+
id: r.witnessId,
|
|
366
|
+
claim: witnesses.find((w) => w.id === r.witnessId)?.tolerance ?? null,
|
|
367
|
+
status: r.status,
|
|
368
|
+
detail: r.detail,
|
|
369
|
+
})),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/** The translation's evidence, and each carriage's, DERIVED by running their witnesses now; never the bound's. */
|
|
373
|
+
function translationEvidence(api, tr, carriages) {
|
|
374
|
+
return {
|
|
375
|
+
...runWitnesses(api, tr.witnesses, tr.checks),
|
|
376
|
+
note: "the translation's own evidence, distinct from the bound's; it carries no formal reference",
|
|
377
|
+
carriages: carriages.map((c) => ({
|
|
378
|
+
bridgeId: c.bridgeId,
|
|
379
|
+
observable: c.observable,
|
|
380
|
+
map: c.map,
|
|
381
|
+
derivation: c.derivation,
|
|
382
|
+
premisesNotChecked: [...c.premises],
|
|
383
|
+
timeMap: c.timeMap,
|
|
384
|
+
...runWitnesses(api, c.witnesses, c.checks),
|
|
385
|
+
})),
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* The translation's witness run at THIS point, bounded in cost, and, when
|
|
390
|
+
* asked, its control: the same measurement against a plausible wrong map. A
|
|
391
|
+
* control that is not refuted here shows this witness cannot tell the two
|
|
392
|
+
* maps apart at this point, and is reported as such.
|
|
393
|
+
*/
|
|
394
|
+
function pointWitness(api, tr, eps, withControl) {
|
|
395
|
+
const pc = tr.pointCheck(eps);
|
|
396
|
+
if ('unavailable' in pc)
|
|
397
|
+
return { unavailable: pc.unavailable };
|
|
398
|
+
const r = api.runTranslationCheck(pc.check);
|
|
399
|
+
const base = { id: r.witnessId, claim: pc.claim, status: r.status, detail: r.detail };
|
|
400
|
+
if (!withControl)
|
|
401
|
+
return base;
|
|
402
|
+
const c = api.runTranslationCheck(pc.control);
|
|
403
|
+
return {
|
|
404
|
+
...base,
|
|
405
|
+
control: { id: c.witnessId, claim: pc.controlClaim, status: c.status, detail: c.detail, discriminates: c.status === 'refuted' },
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
/** A judgement with its point witness; a witness refuted here withdraws any verdict to undetermined. @internal */
|
|
409
|
+
export function judgeAtPoint(api, request, bridges, e, at, withControl) {
|
|
410
|
+
const j = judgeObservable(api, request, bridges, e, at);
|
|
411
|
+
if (j.translation === null || j.horizon === null || j.boundErrorAtPoint === null)
|
|
412
|
+
return { ...j, pointWitness: null };
|
|
413
|
+
const pw = pointWitness(api, j.translation, j.boundErrorAtPoint, withControl);
|
|
414
|
+
if ('status' in pw && pw.status === 'refuted') {
|
|
415
|
+
return {
|
|
416
|
+
...j,
|
|
417
|
+
verdict: 'undetermined',
|
|
418
|
+
reason: `the translation's witness at this point (${pw.id}) is refuted, so its horizon is not relied on here: ${pw.detail}`,
|
|
419
|
+
pointWitness: pw,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
return { ...j, pointWitness: pw };
|
|
423
|
+
}
|
|
424
|
+
function thresholdOrigin(request, tr, bridges) {
|
|
425
|
+
return (`t* is derived from the requested tolerance ${request.value} ${tr.unit} through the translation; ` +
|
|
426
|
+
`${bridges[0].id}'s own horizon (${bridges[0].bound.horizon}) is the record's fixed threshold, judged separately`);
|
|
427
|
+
}
|
|
428
|
+
function observableReport(request, j, bridges, evidence) {
|
|
429
|
+
const tr = j.translation;
|
|
430
|
+
return {
|
|
431
|
+
observable: request.observable,
|
|
432
|
+
value: request.value,
|
|
433
|
+
verdict: j.verdict,
|
|
434
|
+
reason: j.reason,
|
|
435
|
+
...(tr === null
|
|
436
|
+
? { translation: null }
|
|
437
|
+
: {
|
|
438
|
+
unit: tr.unit,
|
|
439
|
+
translation: {
|
|
440
|
+
bridgeId: tr.bridgeId,
|
|
441
|
+
fromNorm: tr.fromNorm,
|
|
442
|
+
errorKind: tr.errorKind,
|
|
443
|
+
definition: tr.definition,
|
|
444
|
+
derivation: tr.derivation,
|
|
445
|
+
premisesNotChecked: [...tr.premises],
|
|
446
|
+
timeUnit: tr.timeUnit,
|
|
447
|
+
notCovered: [...tr.notCovered],
|
|
448
|
+
carriedBy: j.carriages.map((c) => c.bridgeId),
|
|
449
|
+
},
|
|
450
|
+
boundErrorAtPoint: j.boundErrorAtPoint,
|
|
451
|
+
domainSupremum: j.domainSupremum,
|
|
452
|
+
observableErrorAt: j.observableErrorAt,
|
|
453
|
+
horizon: j.horizon,
|
|
454
|
+
domainHorizon: j.domainHorizon,
|
|
455
|
+
horizonConvention: tr.boundary,
|
|
456
|
+
thresholdOrigin: thresholdOrigin(request, tr, bridges),
|
|
457
|
+
bridgeHorizon: { horizon: bridges[0].bound.horizon, holds: j.bridgeHorizonHolds },
|
|
458
|
+
evidence,
|
|
459
|
+
pointWitness: j.pointWitness,
|
|
460
|
+
}),
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function printObservable(out, request, j, bridges, evidence, composite) {
|
|
464
|
+
const tr = j.translation;
|
|
465
|
+
out(` tolerance ${showTolerance(request, tr?.unit)}: ${j.verdict.toUpperCase()} — ${j.reason}`);
|
|
466
|
+
if (tr === null)
|
|
467
|
+
return;
|
|
468
|
+
const show = (v) => (v === null ? 'not evaluated' : String(v));
|
|
469
|
+
const first = bridges[0];
|
|
470
|
+
const kind = tr.errorKind === 'upper-bound' ? 'an UPPER BOUND on the error, not the error' : 'the error itself';
|
|
471
|
+
out(` translation (${tr.bridgeId}; ${kind}): ${tr.fromNorm} → ${tr.observable}: ${tr.definition}`);
|
|
472
|
+
out(` ${tr.derivation}`);
|
|
473
|
+
out(` premises not machine-checked: ${tr.premises.join('; ')}`);
|
|
474
|
+
for (const c of evidence?.carriages ?? []) {
|
|
475
|
+
out(` carried by ${c.bridgeId} (its declared carriage of ${c.observable}): ${c.map}`);
|
|
476
|
+
out(` ${c.derivation}; ${c.timeMap}`);
|
|
477
|
+
out(` premises not machine-checked: ${c.premisesNotChecked.join('; ')}`);
|
|
478
|
+
}
|
|
479
|
+
if (j.carriages.length > 0 && composite === 'no-claim') {
|
|
480
|
+
out(` the composite bound is still '${NO_COMPOSITE_PHRASE}': the composition table is not consulted or widened; ` +
|
|
481
|
+
`this judgement is in ${tr.observable} only, through the declared carriage`);
|
|
482
|
+
}
|
|
483
|
+
else if (j.carriages.length > 0) {
|
|
484
|
+
out(` the composite bound above is in '${first.bound.norm}', carried by a declared norm transport; ` +
|
|
485
|
+
`this judgement is a separate claim in ${tr.observable}, through the declared carriage, and neither implies the other`);
|
|
486
|
+
}
|
|
487
|
+
const what = tr.errorKind === 'upper-bound' ? `bound on the ${tr.observable} error` : `accumulated ${tr.observable} error`;
|
|
488
|
+
out(` ${first.bound.norm} at this point: ${show(j.boundErrorAtPoint)}; domain supremum: ${show(j.domainSupremum)}`);
|
|
489
|
+
out(` ${what} at t: ${j.observableErrorAt === null ? 'not evaluated' : `${j.observableErrorAt} ${tr.unit}`}`);
|
|
490
|
+
out(` ${tr.observable} horizon t* at this point: ${show(j.horizon)} (${tr.timeUnit}; ${tr.boundary})`);
|
|
491
|
+
out(` ${tr.observable} horizon over the whole domain ${first.bound.domain} (from the supremum): ${show(j.domainHorizon)}`);
|
|
492
|
+
out(` threshold origin: ${thresholdOrigin(request, tr, bridges)}`);
|
|
493
|
+
out(` ${first.id}'s own horizon at t: ${j.bridgeHorizonHolds === null ? 'not evaluated' : j.bridgeHorizonHolds ? 'holds' : 'VIOLATED'} — ${first.bound.horizon}`);
|
|
494
|
+
out(` not covered by this translation: ${tr.notCovered.join('; ')}`);
|
|
495
|
+
if (evidence !== null) {
|
|
496
|
+
out(` translation evidence (fixture, the regression anchor): ${evidence.tags.join(', ')} (${evidence.note})`);
|
|
497
|
+
for (const w of evidence.witnesses)
|
|
498
|
+
out(` - ${w.id} [numeric, run now; ${w.claim ?? 'no claim stated'}]: ${w.status} — ${w.detail}`);
|
|
499
|
+
for (const c of evidence.carriages) {
|
|
500
|
+
out(` carriage evidence (${c.bridgeId}): ${c.tags.join(', ')}`);
|
|
501
|
+
for (const w of c.witnesses)
|
|
502
|
+
out(` - ${w.id} [numeric, run now; ${w.claim ?? 'no claim stated'}]: ${w.status} — ${w.detail}`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const pw = j.pointWitness;
|
|
506
|
+
if (pw === null) {
|
|
507
|
+
out(' witness at this point: not run (the translation was not evaluated here)');
|
|
508
|
+
}
|
|
509
|
+
else if ('unavailable' in pw) {
|
|
510
|
+
out(` witness at this point: not run — ${pw.unavailable}`);
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
out(` witness at this point: ${pw.id} [${pw.claim}]: ${pw.status} — ${pw.detail}`);
|
|
514
|
+
if (pw.control !== undefined) {
|
|
515
|
+
out(` control ${pw.control.id} [${pw.control.claim}]: ${pw.control.status}` +
|
|
516
|
+
(pw.control.discriminates
|
|
517
|
+
? ' — the check fails on the wrong map here, so it can fail'
|
|
518
|
+
: ' — NOT refuted: at this point the witness cannot tell the wrong map from the declared one') +
|
|
519
|
+
` (${pw.control.detail})`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/** A row's status on one path: what the point command would say there, with no error where no bound is claimed. */
|
|
524
|
+
function sweepCell(e, result) {
|
|
525
|
+
const regime = e.allRegimesHold === true ? 'holds' : e.allRegimesHold === false ? 'violated' : 'unknown';
|
|
526
|
+
const horizon = e.horizons.length === 0 || e.horizons[0].holds === null ? 'not-evaluated' : e.allHold ? 'holds' : 'violated';
|
|
527
|
+
let error = e.pointBound?.delta ?? null;
|
|
528
|
+
let reason = result.kind === 'no-claim' ? 'no composite claim' : e.pointBoundReason;
|
|
529
|
+
if (error !== null && horizon === 'violated') {
|
|
530
|
+
error = null;
|
|
531
|
+
reason = 'past the horizon: the bound is not claimed there';
|
|
532
|
+
}
|
|
533
|
+
return { regime, horizon, error, reason };
|
|
534
|
+
}
|
|
535
|
+
function checkSweep(spec, point) {
|
|
536
|
+
const sweep = parseSweep(spec);
|
|
537
|
+
if (sweep.name in point) {
|
|
538
|
+
throw new CliError(`upt path: '${sweep.name}' is both swept and fixed by --at; give it one role`);
|
|
539
|
+
}
|
|
540
|
+
return sweep;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* One path evaluated at every sample of one parameter. Each row is what the
|
|
544
|
+
* point command would say there; no trajectory is interpolated. A row outside
|
|
545
|
+
* a regime or past a horizon carries no error, because no bound is claimed
|
|
546
|
+
* there, and it is not joined to its neighbours.
|
|
547
|
+
*/
|
|
548
|
+
function runSweep(ctx, s) {
|
|
549
|
+
const { out, args } = ctx;
|
|
550
|
+
const sweep = checkSweep(s.spec, s.point);
|
|
551
|
+
const rows = sweep.values.map((value) => {
|
|
552
|
+
const at = { ...s.point, [sweep.name]: value };
|
|
553
|
+
const e = s.evaluateAt(at);
|
|
554
|
+
const { regime, horizon, error, reason } = sweepCell(e, s.result);
|
|
555
|
+
const judged = s.tolerance === null ? null : s.judgeRow(e, at, 't' in s.point || sweep.name === 't');
|
|
556
|
+
const pw = judged?.pointWitness;
|
|
557
|
+
return {
|
|
558
|
+
value,
|
|
559
|
+
regime,
|
|
560
|
+
horizon,
|
|
561
|
+
error,
|
|
562
|
+
...(error === null && reason !== null ? { reason } : {}),
|
|
563
|
+
...(judged === null ? {} : { adequacy: judged.verdict }),
|
|
564
|
+
...(judged?.horizon === undefined ? {} : { observableHorizon: judged.horizon, observableError: judged.observableErrorAt ?? null }),
|
|
565
|
+
...(pw === undefined || pw === null ? {} : { pointWitness: 'unavailable' in pw ? { status: 'not-run', reason: pw.unavailable } : { id: pw.id, status: pw.status } }),
|
|
566
|
+
};
|
|
567
|
+
});
|
|
568
|
+
const tally = (k, v) => rows.filter((r) => r[k] === v).length;
|
|
569
|
+
const integrated = s.translation === null
|
|
570
|
+
? 'nothing is integrated and no trajectory is produced'
|
|
571
|
+
: `the only integration is the translation's witness, run at each judged row's point (${s.translation.tr.bridgeId}, ` +
|
|
572
|
+
'RK4, bounded); no trajectory is output';
|
|
573
|
+
const evaluated = s.result.kind === 'bound'
|
|
574
|
+
? `the path's closed-form point bound at each sample (the exact error of the reduced model in the norm '${s.result.norm ?? 'none stated'}'); ` +
|
|
575
|
+
integrated
|
|
576
|
+
: `no error: the path carries no composite claim ('${s.result.reason}'); rows report regime and horizon status only` +
|
|
577
|
+
(s.translation === null ? '' : `; ${integrated}`);
|
|
578
|
+
const fixed = Object.entries(s.point).map(([k, v]) => `${k}=${v}`).join(' ') || 'none';
|
|
579
|
+
if (args.flags.has('json')) {
|
|
580
|
+
emitJson({
|
|
581
|
+
command: 'path',
|
|
582
|
+
epistemics: EPISTEMICS,
|
|
583
|
+
options: { from: s.from, to: s.to, at: s.point, sweep: { parameter: sweep.name, spacing: sweep.spacing, samples: rows.length } },
|
|
584
|
+
result: {
|
|
585
|
+
path: s.bridges.map((b) => b.id),
|
|
586
|
+
kind: s.result.kind,
|
|
587
|
+
...(s.result.kind === 'bound' ? { domainSupremum: s.result.bound, norm: s.result.norm } : { reason: s.result.reason }),
|
|
588
|
+
evaluated,
|
|
589
|
+
...(s.tolerance === null
|
|
590
|
+
? {}
|
|
591
|
+
: s.tolerance.observable === null
|
|
592
|
+
? { tolerance: s.tolerance.value, toleranceScope: s.scope }
|
|
593
|
+
: {
|
|
594
|
+
tolerance: s.tolerance.value,
|
|
595
|
+
toleranceObservable: s.tolerance.observable,
|
|
596
|
+
...(s.translation === null
|
|
597
|
+
? { translation: null }
|
|
598
|
+
: {
|
|
599
|
+
translation: {
|
|
600
|
+
bridgeId: s.translation.tr.bridgeId,
|
|
601
|
+
unit: s.translation.tr.unit,
|
|
602
|
+
errorKind: s.translation.tr.errorKind,
|
|
603
|
+
boundary: s.translation.tr.boundary,
|
|
604
|
+
evidence: s.translation.evidence,
|
|
605
|
+
},
|
|
606
|
+
}),
|
|
607
|
+
}),
|
|
608
|
+
rows,
|
|
609
|
+
tally: {
|
|
610
|
+
inRegime: tally('regime', 'holds'),
|
|
611
|
+
outsideRegime: tally('regime', 'violated'),
|
|
612
|
+
regimeUnknown: tally('regime', 'unknown'),
|
|
613
|
+
pastHorizon: tally('horizon', 'violated'),
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
}, ctx.write);
|
|
617
|
+
return 0;
|
|
618
|
+
}
|
|
619
|
+
if (args.flags.has('csv')) {
|
|
620
|
+
const tol = s.tolerance !== null;
|
|
621
|
+
const pwCol = s.translation !== null;
|
|
622
|
+
ctx.write(`${sweep.name},regime,horizon,error,${tol ? 'adequacy,' : ''}${pwCol ? 'point_witness,' : ''}reason\n`);
|
|
623
|
+
for (const r of rows) {
|
|
624
|
+
ctx.write(`${r.value},${r.regime},${r.horizon},${r.error ?? ''},${tol ? `${r.adequacy},` : ''}${pwCol ? `${r.pointWitness?.status ?? ''},` : ''}` +
|
|
625
|
+
`"${(r.reason ?? '').replace(/"/g, '""')}"\n`);
|
|
626
|
+
}
|
|
627
|
+
return 0;
|
|
628
|
+
}
|
|
629
|
+
out(`\nupt path ${s.from} → ${s.to} — sweep ${sweep.name} over [${sweep.values[0]}, ${sweep.values[sweep.values.length - 1]}], ${rows.length} samples (${sweep.spacing}); fixed: ${fixed}`);
|
|
630
|
+
out(` path: ${s.bridges.map((b) => b.id).join(' → ')}`);
|
|
631
|
+
if (s.result.kind === 'bound')
|
|
632
|
+
out(` domain supremum: K = ${s.result.bound.K} · delta = ${s.result.bound.delta}`);
|
|
633
|
+
out(` evaluated: ${evaluated}`);
|
|
634
|
+
if (s.tolerance !== null && s.tolerance.observable === null)
|
|
635
|
+
out(` tolerance: ${s.tolerance.value}, ${s.scope}`);
|
|
636
|
+
if (s.tolerance !== null && s.tolerance.observable !== null) {
|
|
637
|
+
const carried = s.translation?.evidence.carriages.map((c) => c.bridgeId) ?? [];
|
|
638
|
+
out(s.translation === null
|
|
639
|
+
? ` tolerance: ${showTolerance(s.tolerance)} — no translation into '${s.tolerance.observable}' reaches the end of this path; every row is undetermined`
|
|
640
|
+
: ` tolerance: ${showTolerance(s.tolerance, s.translation.tr.unit)} through ${s.translation.tr.bridgeId}'s declared translation` +
|
|
641
|
+
`${carried.length > 0 ? `, carried by ${carried.join(', ')}` : ''} (${s.translation.tr.boundary}); ` +
|
|
642
|
+
`translation evidence (fixture): ${s.translation.evidence.tags.join(', ')}`);
|
|
643
|
+
}
|
|
644
|
+
const tolCol = s.tolerance === null ? '' : `${'adequacy'.padEnd(13)} `;
|
|
645
|
+
const pwCol = s.translation === null ? '' : `${'point witness'.padEnd(14)} `;
|
|
646
|
+
out(` ${sweep.name.padEnd(12)} ${'regime'.padEnd(10)} ${'horizon'.padEnd(14)} ${tolCol}${pwCol}error`);
|
|
647
|
+
for (const r of rows) {
|
|
648
|
+
const a = r.adequacy === undefined ? '' : `${r.adequacy.padEnd(13)} `;
|
|
649
|
+
const w = s.translation === null ? '' : `${(r.pointWitness?.status ?? '—').padEnd(14)} `;
|
|
650
|
+
out(` ${String(Number(r.value.toPrecision(6))).padEnd(12)} ${String(r.regime).padEnd(10)} ${String(r.horizon).padEnd(14)} ${a}${w}${r.error === null ? `— ${r.reason ?? ''}` : r.error}`);
|
|
651
|
+
}
|
|
652
|
+
out(` in regime: ${tally('regime', 'holds')} · outside: ${tally('regime', 'violated')} · unknown: ${tally('regime', 'unknown')} · ` +
|
|
653
|
+
`past the horizon: ${tally('horizon', 'violated')} of ${rows.length}`);
|
|
654
|
+
out(' (a row with no error is not joined to its neighbours: no bound is claimed there. A sweep exits 0; each row is its own verdict.)');
|
|
655
|
+
return 0;
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Two routes from one source, swept side by side over one parameter. Per row,
|
|
659
|
+
* each route is `claimed` (regime and horizon hold, and a closed-form error
|
|
660
|
+
* exists), `not-claimed` (a regime or horizon is violated, or the route carries
|
|
661
|
+
* no composite claim) or `unsettled` (a coordinate or t was not supplied). A
|
|
662
|
+
* row where every route is not-claimed is NEITHER: no encoded limit applies,
|
|
663
|
+
* and it carries no number. The two errors are in their own norms and are
|
|
664
|
+
* never compared with each other.
|
|
665
|
+
*/
|
|
666
|
+
function runCompare(ctx, from, point, spec, sides) {
|
|
667
|
+
const { out, args } = ctx;
|
|
668
|
+
const sweep = checkSweep(spec, point);
|
|
669
|
+
const rows = sweep.values.map((value) => {
|
|
670
|
+
const at = { ...point, [sweep.name]: value };
|
|
671
|
+
const paths = sides.map((side) => {
|
|
672
|
+
const e = side.evaluateAt(at);
|
|
673
|
+
const cell = sweepCell(e, side.result);
|
|
674
|
+
const state = cell.error !== null && cell.regime === 'holds' && cell.horizon !== 'not-evaluated'
|
|
675
|
+
? 'claimed'
|
|
676
|
+
: cell.error !== null && cell.regime === 'holds' && e.horizons.length === 0
|
|
677
|
+
? 'claimed'
|
|
678
|
+
: cell.regime === 'violated' || cell.horizon === 'violated' || side.result.kind === 'no-claim'
|
|
679
|
+
? 'not-claimed'
|
|
680
|
+
: 'unsettled';
|
|
681
|
+
return {
|
|
682
|
+
to: side.to,
|
|
683
|
+
regime: cell.regime,
|
|
684
|
+
horizon: cell.horizon,
|
|
685
|
+
state,
|
|
686
|
+
error: state === 'claimed' ? cell.error : null,
|
|
687
|
+
...(state !== 'claimed' && cell.reason !== null ? { reason: cell.reason } : {}),
|
|
688
|
+
...(state === 'unsettled' && cell.error !== null ? { reason: 'no t= given, so the horizon was not evaluated' } : {}),
|
|
689
|
+
};
|
|
690
|
+
});
|
|
691
|
+
const claimedBy = paths.filter((p) => p.state === 'claimed').map((p) => p.to);
|
|
692
|
+
const coverage = claimedBy.length > 0 ? 'covered' : paths.every((p) => p.state === 'not-claimed') ? 'neither' : 'unsettled';
|
|
693
|
+
return { value, paths, claimedBy, coverage };
|
|
694
|
+
});
|
|
695
|
+
const count = (c) => rows.filter((r) => r.coverage === c).length;
|
|
696
|
+
const tally = {
|
|
697
|
+
covered: count('covered'),
|
|
698
|
+
neither: count('neither'),
|
|
699
|
+
unsettled: count('unsettled'),
|
|
700
|
+
claimedBy: Object.fromEntries(sides.map((sd) => [sd.to, rows.filter((r) => r.claimedBy.includes(sd.to)).length])),
|
|
701
|
+
claimedByAll: rows.filter((r) => r.claimedBy.length === sides.length).length,
|
|
702
|
+
};
|
|
703
|
+
const evaluated = "each route's closed-form point bound at each sample, in that route's OWN norm; the two errors are different " +
|
|
704
|
+
'quantities and are not compared with each other. Nothing is integrated and no trajectory is produced';
|
|
705
|
+
const neitherNote = `no encoded limit applies: the parent ${from} is the model to use there, and no reduced-model number is given`;
|
|
706
|
+
const fixed = Object.entries(point).map(([k, v]) => `${k}=${v}`).join(' ') || 'none';
|
|
707
|
+
if (args.flags.has('json')) {
|
|
708
|
+
emitJson({
|
|
709
|
+
command: 'path',
|
|
710
|
+
epistemics: EPISTEMICS,
|
|
711
|
+
options: {
|
|
712
|
+
from,
|
|
713
|
+
to: sides.map((sd) => sd.to),
|
|
714
|
+
at: point,
|
|
715
|
+
sweep: { parameter: sweep.name, spacing: sweep.spacing, samples: rows.length },
|
|
716
|
+
},
|
|
717
|
+
result: {
|
|
718
|
+
compare: sides.map((sd) => ({
|
|
719
|
+
to: sd.to,
|
|
720
|
+
path: sd.bridges.map((b) => b.id),
|
|
721
|
+
kind: sd.result.kind,
|
|
722
|
+
...(sd.result.kind === 'bound' ? { domainSupremum: sd.result.bound, norm: sd.result.norm } : { reason: sd.result.reason }),
|
|
723
|
+
})),
|
|
724
|
+
evaluated,
|
|
725
|
+
neither: neitherNote,
|
|
726
|
+
rows,
|
|
727
|
+
tally,
|
|
728
|
+
},
|
|
729
|
+
}, ctx.write);
|
|
730
|
+
return 0;
|
|
731
|
+
}
|
|
732
|
+
if (args.flags.has('csv')) {
|
|
733
|
+
const head = sides.flatMap((sd) => [`${sd.to}_regime`, `${sd.to}_horizon`, `${sd.to}_state`, `${sd.to}_error`]);
|
|
734
|
+
ctx.write(`${sweep.name},${head.join(',')},coverage\n`);
|
|
735
|
+
for (const r of rows) {
|
|
736
|
+
const cells = r.paths.flatMap((p) => [p.regime, p.horizon, p.state, p.error ?? '']);
|
|
737
|
+
ctx.write(`${r.value},${cells.join(',')},${r.coverage === 'covered' ? r.claimedBy.join('+') : r.coverage}\n`);
|
|
738
|
+
}
|
|
739
|
+
return 0;
|
|
740
|
+
}
|
|
741
|
+
out(`\nupt path ${from} → ${sides.map((sd) => sd.to).join(' | ')} — sweep ${sweep.name} over [${sweep.values[0]}, ` +
|
|
742
|
+
`${sweep.values[sweep.values.length - 1]}], ${rows.length} samples (${sweep.spacing}); fixed: ${fixed}`);
|
|
743
|
+
for (const sd of sides) {
|
|
744
|
+
out(` → ${sd.to}: ${sd.bridges.map((b) => b.id).join(' → ')}; ` +
|
|
745
|
+
(sd.result.kind === 'bound' ? `norm: ${sd.result.norm ?? 'none stated'}` : `no composite claim ('${sd.result.reason}')`));
|
|
746
|
+
}
|
|
747
|
+
out(` evaluated: ${evaluated}`);
|
|
748
|
+
const heads = sides.map((sd) => `${sd.to}: regime/horizon error`);
|
|
749
|
+
const w = Math.max(30, ...heads.map((h) => h.length));
|
|
750
|
+
out(` ${sweep.name.padEnd(12)} ${heads.map((h) => h.padEnd(w)).join(' ')} covered by`);
|
|
751
|
+
for (const r of rows) {
|
|
752
|
+
const cells = r.paths.map((p) => `${p.regime}/${p.horizon} ${p.error === null ? '—' : Number(p.error.toPrecision(6))}`.padEnd(w));
|
|
753
|
+
const cov = r.coverage === 'covered' ? r.claimedBy.join(' + ') : r.coverage === 'neither' ? `NEITHER — ${neitherNote}` : 'UNSETTLED — a coordinate or t was not supplied';
|
|
754
|
+
out(` ${String(Number(r.value.toPrecision(6))).padEnd(12)} ${cells.join(' ')} ${cov}`);
|
|
755
|
+
}
|
|
756
|
+
out(` covered: ${tally.covered} (${sides.map((sd) => `${sd.to}: ${tally.claimedBy[sd.to]}`).join(', ')}; by all: ${tally.claimedByAll}) · ` +
|
|
757
|
+
`NEITHER: ${tally.neither} · unsettled: ${tally.unsettled} of ${rows.length}`);
|
|
758
|
+
out(' (errors to 6 significant digits, --json for full precision; a row with no error is not joined to its neighbours. A sweep exits 0.)');
|
|
759
|
+
return 0;
|
|
760
|
+
}
|
|
761
|
+
/** The point evaluation of one route: regimes, horizons and the proven point bound at `at`. */
|
|
762
|
+
function makeEvaluator(api, bridges, result) {
|
|
763
|
+
return (at) => {
|
|
764
|
+
// A horizon is read at the END of the route: a transport applied after a
|
|
765
|
+
// bound restates it on the later model's clock (ADR, time map).
|
|
766
|
+
const carried = result.kind === 'bound' ? (result.transports ?? []) : [];
|
|
767
|
+
const horizons = bridges.flatMap((b, i) => {
|
|
768
|
+
const h = api.horizonOnRoute(bridges, carried, i);
|
|
769
|
+
if (h === null)
|
|
770
|
+
return [];
|
|
771
|
+
// A later step in another family keeps its horizon unevaluated unless a
|
|
772
|
+
// transport on that step restates the clock. The earlier horizon stays
|
|
773
|
+
// in the time of the model where it was stated.
|
|
774
|
+
const blocked = api.familyChangeBlocksHorizon(bridges, carried, i);
|
|
775
|
+
return [
|
|
776
|
+
{
|
|
777
|
+
bridgeId: b.id,
|
|
778
|
+
horizon: h.horizon,
|
|
779
|
+
holds: at['t'] === undefined || blocked ? null : h.holds(at['t'], at),
|
|
780
|
+
...(h.restatedBy.length > 0
|
|
781
|
+
? { restatedBy: h.restatedBy.map((a) => ({ transport: a.transport.id, horizon: a.transport.timeMap.horizon })) }
|
|
782
|
+
: {}),
|
|
783
|
+
...(blocked ? { unevaluated: 'cross-family' } : {}),
|
|
784
|
+
},
|
|
785
|
+
];
|
|
786
|
+
});
|
|
787
|
+
const allHold = horizons.every((h) => h.holds === true);
|
|
788
|
+
// Each step is checked against its own regime. A group name whose π-groups
|
|
789
|
+
// differ is dropped on every step that defines it, so the supplied number
|
|
790
|
+
// is not applied to either definition. intersectRegimes is not called.
|
|
791
|
+
const regimeCollisions = api.collidingRegimeGroups(bridges.map((b) => b.regime));
|
|
792
|
+
const blockedGroups = new Set(regimeCollisions.map((c) => c.group));
|
|
793
|
+
const regimes = bridges.map((b) => {
|
|
794
|
+
const { values } = resolveAtPoint(at, [b.regime]);
|
|
795
|
+
for (const name of blockedGroups)
|
|
796
|
+
delete values[name];
|
|
797
|
+
const check = api.regimeHolds(b.regime, values);
|
|
798
|
+
return {
|
|
799
|
+
bridgeId: b.id,
|
|
800
|
+
ok: check.ok,
|
|
801
|
+
violated: check.violated.map(showInequality),
|
|
802
|
+
unchecked: check.unchecked.map(showInequality),
|
|
803
|
+
...(b.sideConditions.length > 0 ? { premisesNotChecked: [...b.sideConditions] } : {}),
|
|
804
|
+
};
|
|
805
|
+
});
|
|
806
|
+
const allRegimesHold = regimes.some((r) => r.ok === false)
|
|
807
|
+
? false
|
|
808
|
+
: regimes.some((r) => r.ok === 'unknown')
|
|
809
|
+
? 'unknown'
|
|
810
|
+
: true;
|
|
811
|
+
// The bound AT the --at point (persona finding L9). Printed only when it is
|
|
812
|
+
// PROVEN: every regime holds, every step has a closed-form deltaAt (the exact
|
|
813
|
+
// error), and every value is finite. It is composed by the same rule as the
|
|
814
|
+
// domain supremum, by substituting each step's point value for its delta.
|
|
815
|
+
let pointBound = null;
|
|
816
|
+
let pointBoundReason = null;
|
|
817
|
+
if (result.kind === 'bound' && Object.keys(at).length > 0) {
|
|
818
|
+
const steps = bridges.filter((b) => b.bound !== undefined);
|
|
819
|
+
const numerical = steps.find((b) => b.bound.deltaAtBasis !== 'closed-form');
|
|
820
|
+
if (allRegimesHold !== true) {
|
|
821
|
+
pointBoundReason = 'a regime on the path is violated or unchecked';
|
|
822
|
+
}
|
|
823
|
+
else if (steps.length === 0) {
|
|
824
|
+
pointBoundReason = 'no step carries a bound';
|
|
825
|
+
}
|
|
826
|
+
else if (numerical !== undefined) {
|
|
827
|
+
pointBoundReason =
|
|
828
|
+
numerical.bound.deltaAt === undefined
|
|
829
|
+
? `${numerical.id} states no point bound`
|
|
830
|
+
: `${numerical.id}'s point bound is numerically supported, not proven`;
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
// A transport's K is substituted by its closed form at the point, as a
|
|
834
|
+
// bound's delta is (for ab-spring-lc both are the constant 1).
|
|
835
|
+
const atPoint = bridges.map((b) => b.bound === undefined
|
|
836
|
+
? b.normTransports === undefined
|
|
837
|
+
? b
|
|
838
|
+
: { ...b, normTransports: b.normTransports.map((nt) => ({ ...nt, K: nt.KAt(at) })) }
|
|
839
|
+
: { ...b, bound: { ...b.bound, delta: b.bound.deltaAt(at) } });
|
|
840
|
+
const composed = atPoint.every((b) => b.bound === undefined || Number.isFinite(b.bound.delta))
|
|
841
|
+
? api.boundPath(atPoint)
|
|
842
|
+
: null;
|
|
843
|
+
if (composed !== null && composed.kind === 'bound')
|
|
844
|
+
pointBound = composed.bound;
|
|
845
|
+
else
|
|
846
|
+
pointBoundReason = 'a parameter the point bound needs was not supplied';
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return { regimes, allRegimesHold, horizons, allHold, pointBound, pointBoundReason, regimeCollisions };
|
|
850
|
+
};
|
|
851
|
+
}
|
|
23
852
|
async function run(ctx) {
|
|
24
|
-
const { args, api, out } = ctx;
|
|
853
|
+
const { args, api, out, err } = ctx;
|
|
25
854
|
const wantJson = args.flags.has('json');
|
|
26
855
|
const endpoints = args.positionals.filter((p) => !p.includes('='));
|
|
27
856
|
const assignments = [...(args.flags.get('at') ?? []), ...args.positionals.filter((p) => p.includes('='))];
|
|
@@ -30,135 +859,158 @@ async function run(ctx) {
|
|
|
30
859
|
'`upt path model-pendulum model-spring`');
|
|
31
860
|
}
|
|
32
861
|
const [from, to] = endpoints;
|
|
33
|
-
const
|
|
862
|
+
const atNotes = [];
|
|
863
|
+
const point = parseAt(assignments, 'path', atNotes);
|
|
864
|
+
for (const note of atNotes)
|
|
865
|
+
err(note);
|
|
34
866
|
const t = point['t'];
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// asked for. A route stays inside ONE family (findPath's scope); two
|
|
38
|
-
// endpoints in different families are reported as exactly that.
|
|
39
|
-
const familyOf = (id) => api.ATLAS_FAMILIES.find((f) => f.models.some((m) => m.id === id))?.family;
|
|
40
|
-
const fromFamily = familyOf(from);
|
|
41
|
-
const toFamily = familyOf(to);
|
|
42
|
-
if (fromFamily !== undefined && toFamily !== undefined && fromFamily !== toFamily) {
|
|
43
|
-
throw new CliError(`upt path: '${from}' is in family '${fromFamily}' and '${to}' in '${toFamily}'; ` +
|
|
44
|
-
'routes are searched within one family, and cross-family routes are not supported');
|
|
45
|
-
}
|
|
46
|
-
const family = fromFamily ?? toFamily ?? api.ATLAS_FAMILIES[0].family;
|
|
47
|
-
let bridges;
|
|
48
|
-
try {
|
|
49
|
-
bridges = api.findPath(family, from, to);
|
|
50
|
-
}
|
|
51
|
-
catch (e) {
|
|
52
|
-
// RangeError: an unknown endpoint. Reported as a CliError (exit 1) rather
|
|
53
|
-
// than surfaced as a crash — and NOT as `null`, which would be
|
|
54
|
-
// indistinguishable from a genuinely disconnected pair.
|
|
55
|
-
throw new CliError(`upt path: ${e instanceof Error ? e.message : String(e)}`);
|
|
56
|
-
}
|
|
867
|
+
const { bridges, fromFamily, toFamily } = selectRoute(api, from, to, 'path');
|
|
868
|
+
const multi = from === to ? [] : multiPremiseBridges(api, from, to);
|
|
57
869
|
if (bridges === null) {
|
|
58
870
|
if (wantJson) {
|
|
59
|
-
emitJson({
|
|
871
|
+
emitJson({
|
|
872
|
+
command: 'path',
|
|
873
|
+
epistemics: EPISTEMICS,
|
|
874
|
+
options: { from, to, at: point },
|
|
875
|
+
result: { path: null, ...(multi.length === 0 ? {} : { multiPremise: multi }) },
|
|
876
|
+
}, ctx.write);
|
|
60
877
|
return 0;
|
|
61
878
|
}
|
|
62
879
|
out(`\nupt path ${from} → ${to}`);
|
|
63
880
|
out(' no chain of bridges connects these models; there is nothing to compose.');
|
|
881
|
+
printMultiPremise(out, multi);
|
|
64
882
|
return 0;
|
|
65
883
|
}
|
|
884
|
+
const labels = routeFamilyLabels(api, bridges, from);
|
|
66
885
|
if (bridges.length === 0) {
|
|
67
886
|
if (wantJson) {
|
|
68
|
-
emitJson({
|
|
887
|
+
emitJson({
|
|
888
|
+
command: 'path',
|
|
889
|
+
epistemics: EPISTEMICS,
|
|
890
|
+
options: { from, to, at: point },
|
|
891
|
+
result: { path: [], crossFamily: labels.crossFamily, modelFamilies: labels.modelFamilies },
|
|
892
|
+
}, ctx.write);
|
|
69
893
|
return 0;
|
|
70
894
|
}
|
|
71
895
|
out(`\nupt path ${from} → ${to}`);
|
|
72
896
|
out(' the endpoints are the same model: the path is empty and composes nothing.');
|
|
73
897
|
return 0;
|
|
74
898
|
}
|
|
75
|
-
const result = api
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const check = api.regimeHolds(b.regime, resolved);
|
|
90
|
-
return {
|
|
91
|
-
bridgeId: b.id,
|
|
92
|
-
ok: check.ok,
|
|
93
|
-
violated: check.violated.map(showInequality),
|
|
94
|
-
unchecked: check.unchecked.map(showInequality),
|
|
95
|
-
};
|
|
96
|
-
});
|
|
97
|
-
const allRegimesHold = regimes.some((r) => r.ok === false)
|
|
98
|
-
? false
|
|
99
|
-
: regimes.some((r) => r.ok === 'unknown')
|
|
100
|
-
? 'unknown'
|
|
101
|
-
: true;
|
|
102
|
-
// The bound AT the --at point (persona finding L9). Printed only when it is
|
|
103
|
-
// PROVEN: every regime holds, every step has a closed-form deltaAt (the exact
|
|
104
|
-
// error), and every value is finite. It is composed by the same rule as the
|
|
105
|
-
// domain supremum, by substituting each step's point value for its delta.
|
|
106
|
-
let pointBound = null;
|
|
107
|
-
let pointBoundReason = null;
|
|
108
|
-
if (result.kind === 'bound' && Object.keys(point).length > 0) {
|
|
109
|
-
const steps = bridges.filter((b) => b.bound !== undefined);
|
|
110
|
-
const numerical = steps.find((b) => b.bound.deltaAtBasis !== 'closed-form');
|
|
111
|
-
if (allRegimesHold !== true) {
|
|
112
|
-
pointBoundReason = 'a regime on the path is violated or unchecked';
|
|
113
|
-
}
|
|
114
|
-
else if (steps.length === 0) {
|
|
115
|
-
pointBoundReason = 'no step carries a bound';
|
|
116
|
-
}
|
|
117
|
-
else if (numerical !== undefined) {
|
|
118
|
-
pointBoundReason =
|
|
119
|
-
numerical.bound.deltaAt === undefined
|
|
120
|
-
? `${numerical.id} states no point bound`
|
|
121
|
-
: `${numerical.id}'s point bound is numerically supported, not proven`;
|
|
899
|
+
const result = routeClaim(api, bridges);
|
|
900
|
+
const missing = explainsRefusal(result) ? missingForComposite(api, bridges) : [];
|
|
901
|
+
const evaluateAt = makeEvaluator(api, bridges, result);
|
|
902
|
+
const tolValues = args.flags.get('tolerance');
|
|
903
|
+
const tolerance = parseTolerance(tolValues === undefined ? undefined : tolValues[tolValues.length - 1]);
|
|
904
|
+
const scope = toleranceScope(api, bridges);
|
|
905
|
+
const found = tolerance?.observable == null ? null : pathTranslation(api, bridges, tolerance.observable);
|
|
906
|
+
const translation = found?.tr ?? undefined;
|
|
907
|
+
const carriages = found !== null && found.tr !== null ? found.carriages : [];
|
|
908
|
+
const sweepSpec = args.flags.get('sweep');
|
|
909
|
+
const compareTo = args.flags.get('compare');
|
|
910
|
+
if (compareTo !== undefined && compareTo.length > 0) {
|
|
911
|
+
if (sweepSpec === undefined || sweepSpec.length === 0) {
|
|
912
|
+
throw new CliError('upt path: --compare needs --sweep (two routes are compared row by row over a sweep)');
|
|
122
913
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
914
|
+
if (tolerance !== null) {
|
|
915
|
+
throw new CliError('upt path: --compare does not take --tolerance: judge each route on its own, since their errors are in different norms');
|
|
916
|
+
}
|
|
917
|
+
const to2 = compareTo[compareTo.length - 1];
|
|
918
|
+
if (to2 === to)
|
|
919
|
+
throw new CliError(`upt path: --compare=${to2} is the same target as the path; name a different model`);
|
|
920
|
+
const other = selectRoute(api, from, to2, 'path').bridges;
|
|
921
|
+
if (other === null || other.length === 0) {
|
|
922
|
+
throw new CliError(`upt path: --compare=${to2}: ${other === null ? `no chain of bridges connects ${from} to ${to2}` : 'the endpoints are the same model'}; there is nothing to compare`);
|
|
923
|
+
}
|
|
924
|
+
const otherResult = routeClaim(api, other);
|
|
925
|
+
return runCompare(ctx, from, point, sweepSpec[sweepSpec.length - 1], [
|
|
926
|
+
{ to, bridges, result, evaluateAt },
|
|
927
|
+
{ to: to2, bridges: other, result: otherResult, evaluateAt: makeEvaluator(api, other, otherResult) },
|
|
928
|
+
]);
|
|
929
|
+
}
|
|
930
|
+
if (sweepSpec !== undefined && sweepSpec.length > 0) {
|
|
931
|
+
return runSweep(ctx, {
|
|
932
|
+
from,
|
|
933
|
+
to,
|
|
934
|
+
point,
|
|
935
|
+
bridges,
|
|
936
|
+
result,
|
|
937
|
+
evaluateAt,
|
|
938
|
+
spec: sweepSpec[sweepSpec.length - 1],
|
|
939
|
+
tolerance,
|
|
940
|
+
scope,
|
|
941
|
+
judgeRow: (e, at, tGiven) => tolerance === null || tolerance.observable === null
|
|
942
|
+
? judgeTolerance(tolerance?.value ?? 0, e, tGiven)
|
|
943
|
+
: judgeAtPoint(api, { ...tolerance, observable: tolerance.observable }, bridges, e, at, false),
|
|
944
|
+
translation: translation === undefined ? null : { tr: translation, evidence: translationEvidence(api, translation, carriages) },
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
if (args.flags.has('csv'))
|
|
948
|
+
throw new CliError('upt path: --csv needs --sweep (a single point is not a table)');
|
|
949
|
+
const evaluation = evaluateAt(point);
|
|
950
|
+
const { regimes, allRegimesHold, horizons, allHold, pointBound, pointBoundReason, regimeCollisions } = evaluation;
|
|
951
|
+
const adequacy = tolerance === null || tolerance.observable !== null ? null : judgeTolerance(tolerance.value, evaluation, t !== undefined);
|
|
952
|
+
const observed = tolerance === null || tolerance.observable === null
|
|
953
|
+
? null
|
|
954
|
+
: judgeAtPoint(api, { ...tolerance, observable: tolerance.observable }, bridges, evaluation, point, true);
|
|
955
|
+
const evidence = translation === undefined ? null : translationEvidence(api, translation, carriages);
|
|
956
|
+
// A violated regime or horizon is a failed check: exit 3 (persona finding F2),
|
|
957
|
+
// and so is a tolerance the point error exceeds. UNKNOWN, where a coordinate
|
|
958
|
+
// or t was not supplied, is not a failure.
|
|
959
|
+
const horizonViolated = t !== undefined && horizons.some((h) => h.holds === false);
|
|
960
|
+
// The domain supremum is the route's answer only while the point check has
|
|
961
|
+
// not withdrawn it. A violated regime or horizon is not a claim, so neither
|
|
962
|
+
// text nor JSON carries a bound number.
|
|
963
|
+
const claimWithdrawn = allRegimesHold === false || horizonViolated;
|
|
964
|
+
const withdrawnReason = allRegimesHold === false
|
|
965
|
+
? (pointBoundReason ?? 'a regime on the path is violated or unchecked')
|
|
966
|
+
: 'past the horizon, no bound is claimed at this point';
|
|
967
|
+
const exitCode = allRegimesHold === false ||
|
|
968
|
+
horizonViolated ||
|
|
969
|
+
adequacy?.verdict === 'inadequate' ||
|
|
970
|
+
observed?.verdict === 'inadequate'
|
|
971
|
+
? EXIT_CHECK_FAILED
|
|
972
|
+
: 0;
|
|
137
973
|
if (wantJson) {
|
|
138
974
|
emitJson({
|
|
139
975
|
command: 'path',
|
|
140
976
|
epistemics: EPISTEMICS,
|
|
141
977
|
options: { from, to, at: point },
|
|
142
978
|
result: {
|
|
143
|
-
|
|
979
|
+
families: { from: fromFamily, to: toFamily },
|
|
980
|
+
crossFamily: labels.crossFamily,
|
|
981
|
+
modelFamilies: labels.modelFamilies,
|
|
982
|
+
path: labels.steps,
|
|
144
983
|
// A no-claim has no `bound` key at all — the type refuses it, and so
|
|
145
984
|
// does this envelope.
|
|
146
985
|
...(result.kind === 'bound'
|
|
147
986
|
? {
|
|
148
987
|
kind: 'bound',
|
|
149
988
|
relation: result.relation,
|
|
150
|
-
bound: result.bound,
|
|
989
|
+
...(claimWithdrawn ? {} : { bound: result.bound }),
|
|
151
990
|
norm: result.norm,
|
|
152
991
|
terminal: result.terminal,
|
|
992
|
+
...(result.transports === undefined ? {} : { transports: result.transports.map(transportReport) }),
|
|
153
993
|
}
|
|
154
|
-
: {
|
|
994
|
+
: {
|
|
995
|
+
kind: 'no-claim',
|
|
996
|
+
reason: result.reason,
|
|
997
|
+
detail: result.detail,
|
|
998
|
+
phrase: NO_COMPOSITE_PHRASE,
|
|
999
|
+
...(missing.length > 0 ? { missing } : {}),
|
|
1000
|
+
}),
|
|
155
1001
|
regimes,
|
|
156
1002
|
allRegimesHold,
|
|
157
|
-
pointBound,
|
|
158
|
-
...(
|
|
1003
|
+
pointBound: claimWithdrawn ? null : pointBound,
|
|
1004
|
+
...((claimWithdrawn ? withdrawnReason : pointBoundReason) !== null
|
|
1005
|
+
? { pointBoundReason: claimWithdrawn ? withdrawnReason : pointBoundReason }
|
|
1006
|
+
: {}),
|
|
159
1007
|
horizons,
|
|
1008
|
+
...(multi.length === 0 ? {} : { multiPremise: multi }),
|
|
1009
|
+
...(regimeCollisions.length === 0 ? {} : { regimeCollisions }),
|
|
160
1010
|
horizonsEvaluated: t !== undefined,
|
|
161
|
-
allHorizonsHold: t === undefined ? null : allHold,
|
|
1011
|
+
allHorizonsHold: t === undefined || horizons.some((h) => h.holds === null) ? (horizonViolated ? false : null) : allHold,
|
|
1012
|
+
...(adequacy === null ? {} : { tolerance: { value: tolerance.value, ...adequacy, scope } }),
|
|
1013
|
+
...(observed === null ? {} : { tolerance: observableReport(tolerance, observed, bridges, evidence) }),
|
|
162
1014
|
},
|
|
163
1015
|
}, ctx.write);
|
|
164
1016
|
return exitCode;
|
|
@@ -167,25 +1019,50 @@ async function run(ctx) {
|
|
|
167
1019
|
out(` ${bridges.length} bridge(s):`);
|
|
168
1020
|
for (const b of bridges)
|
|
169
1021
|
out(` ${b.premises[0]} --[${b.relation}]--> ${b.conclusion} (${b.id})`);
|
|
1022
|
+
printMultiPremise(out, multi);
|
|
1023
|
+
if (labels.crossFamily) {
|
|
1024
|
+
out(` crosses families: ${labels.modelFamilies.join(' → ')}`);
|
|
1025
|
+
}
|
|
170
1026
|
out('');
|
|
171
1027
|
if (result.kind === 'bound') {
|
|
172
1028
|
out(` composite relation: ${result.relation}`);
|
|
173
|
-
|
|
1029
|
+
if (claimWithdrawn) {
|
|
1030
|
+
out(' composed bound: none — no bound is claimed at this point');
|
|
1031
|
+
}
|
|
1032
|
+
else {
|
|
1033
|
+
out(` composed bound: K = ${result.bound.K} · delta = ${result.bound.delta}`);
|
|
1034
|
+
}
|
|
174
1035
|
out(` norm: ${result.norm ?? '(none stated — the claim is the vacuous identity)'}`);
|
|
175
1036
|
if (result.terminal)
|
|
176
1037
|
out(' terminal: the last step states no Lipschitz constant; the claim ends there');
|
|
177
|
-
|
|
1038
|
+
for (const a of result.transports ?? []) {
|
|
1039
|
+
const nt = a.transport;
|
|
1040
|
+
out(` why the bound crosses '${a.bridgeId}' (exact): it declares the norm transport '${nt.id}'`);
|
|
1041
|
+
out(` ${nt.fromModel} → ${nt.toModel}: '${nt.from}' → '${nt.to}', K = ${nt.K} (${nt.domain})`);
|
|
1042
|
+
out(` because: ${nt.derivation}`);
|
|
1043
|
+
out(` time map: ${nt.timeMap.map} (uniform)`);
|
|
1044
|
+
out(` horizon: ${nt.timeMap.horizon}`);
|
|
1045
|
+
out(` witness: ${nt.witness.id} (${nt.witness.kind}; ${nt.basis} when it checks, never formally proved) — ` +
|
|
1046
|
+
`\`upt map --route=${from},${to} --run\` runs it`);
|
|
1047
|
+
out(' no other norm or direction through this map is declared, and each stays refused');
|
|
1048
|
+
}
|
|
1049
|
+
if (!claimWithdrawn && pointBound !== null) {
|
|
178
1050
|
out(` bound at this point: K = ${pointBound.K} · delta = ${pointBound.delta} (closed-form: the exact error; ` +
|
|
179
1051
|
"the composed bound above is the supremum over the bridge's domain)");
|
|
180
1052
|
}
|
|
181
|
-
else if (pointBoundReason !== null) {
|
|
182
|
-
out(` bound at this point: none — ${pointBoundReason}`);
|
|
1053
|
+
else if ((claimWithdrawn ? withdrawnReason : pointBoundReason) !== null) {
|
|
1054
|
+
out(` bound at this point: none — ${claimWithdrawn ? withdrawnReason : pointBoundReason}`);
|
|
183
1055
|
}
|
|
184
1056
|
}
|
|
185
1057
|
else {
|
|
186
1058
|
out(` composite relation: ${NO_COMPOSITE_PHRASE}`);
|
|
187
1059
|
out(` bound: ${NO_COMPOSITE_PHRASE} — reason '${result.reason}'`);
|
|
188
1060
|
out(` ${result.detail}`);
|
|
1061
|
+
if (missing.length > 0) {
|
|
1062
|
+
out(' to compose, this path would need:');
|
|
1063
|
+
for (const m of missing)
|
|
1064
|
+
out(` - ${m}`);
|
|
1065
|
+
}
|
|
189
1066
|
}
|
|
190
1067
|
out('');
|
|
191
1068
|
if (allRegimesHold === false) {
|
|
@@ -206,20 +1083,53 @@ async function run(ctx) {
|
|
|
206
1083
|
else if (r.ok === 'unknown')
|
|
207
1084
|
out(` ${r.bridgeId}: unknown — unchecked: ${r.unchecked.join('; ')}`);
|
|
208
1085
|
}
|
|
1086
|
+
if (regimeCollisions.length > 0) {
|
|
1087
|
+
out(' regime group names collide (unchecked on each step that defines them):');
|
|
1088
|
+
for (const c of regimeCollisions)
|
|
1089
|
+
out(` ${c.group}: ${c.families.join(', ')}`);
|
|
1090
|
+
}
|
|
1091
|
+
if (regimes.some((r) => r.premisesNotChecked !== undefined)) {
|
|
1092
|
+
out(' premises not machine-checked (your judgment or measurement):');
|
|
1093
|
+
for (const r of regimes) {
|
|
1094
|
+
if (r.premisesNotChecked !== undefined)
|
|
1095
|
+
out(` ${r.bridgeId}: ${r.premisesNotChecked.join('; ')}`);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
209
1098
|
if (horizons.length === 0) {
|
|
210
1099
|
out(' horizons: none on this path (no step carries a bound)');
|
|
211
1100
|
}
|
|
212
1101
|
else if (t === undefined) {
|
|
213
1102
|
out(' horizons: NOT EVALUATED (no t= supplied via --at); an unevaluated horizon is not a passing one');
|
|
214
|
-
for (const h of horizons)
|
|
1103
|
+
for (const h of horizons) {
|
|
215
1104
|
out(` ${h.bridgeId}: ${h.horizon}`);
|
|
1105
|
+
for (const r of h.restatedBy ?? [])
|
|
1106
|
+
out(` restated by '${r.transport}': ${r.horizon}`);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
else if (horizons.some((h) => h.unevaluated === 'cross-family') && !horizonViolated) {
|
|
1110
|
+
out(` horizons at t=${t}: NOT EVALUATED — a family change does not restate a horizon onto the next clock`);
|
|
1111
|
+
for (const h of horizons) {
|
|
1112
|
+
const state = h.holds === null ? 'unevaluated' : h.holds ? 'holds' : 'VIOLATED';
|
|
1113
|
+
out(` ${h.bridgeId}: ${state} — ${h.horizon}`);
|
|
1114
|
+
for (const r of h.restatedBy ?? [])
|
|
1115
|
+
out(` restated by '${r.transport}': ${r.horizon}`);
|
|
1116
|
+
}
|
|
216
1117
|
}
|
|
217
1118
|
else {
|
|
218
1119
|
out(` horizons at t=${t}: ${allHold ? 'all hold' : 'NOT all hold'}`);
|
|
219
1120
|
for (const h of horizons) {
|
|
220
|
-
|
|
1121
|
+
const state = h.holds === null ? 'unevaluated' : h.holds ? 'holds' : 'VIOLATED';
|
|
1122
|
+
out(` ${h.bridgeId}: ${state} — ${h.horizon}`);
|
|
1123
|
+
for (const r of h.restatedBy ?? [])
|
|
1124
|
+
out(` restated by '${r.transport}': ${r.horizon}`);
|
|
221
1125
|
}
|
|
222
1126
|
}
|
|
1127
|
+
if (adequacy !== null) {
|
|
1128
|
+
out(` tolerance ${tolerance.value}: ${adequacy.verdict.toUpperCase()} — ${adequacy.reason}`);
|
|
1129
|
+
out(` (${scope})`);
|
|
1130
|
+
}
|
|
1131
|
+
if (observed !== null)
|
|
1132
|
+
printObservable(out, tolerance, observed, bridges, evidence, result.kind);
|
|
223
1133
|
out(` (${EPISTEMICS})`);
|
|
224
1134
|
return exitCode;
|
|
225
1135
|
}
|