universal-physics-tensor 11.0.0 → 12.0.0
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/README.md +36 -34
- package/data/applied-cases.json +1892 -0
- package/data/applied-cases.schema.json +194 -0
- package/data/atlas/atlas.json +21 -21
- package/data/atlas/atlas.jsonld +1 -1
- package/data/atlas/diffusion.json +5 -5
- package/data/atlas/oscillators.json +7 -7
- package/data/atlas/waves.json +11 -11
- package/data/bridge-catalog.json +20 -4
- package/data/units.json +6 -25
- package/dist/atlas/benchmark/stats.d.ts.map +1 -1
- package/dist/atlas/benchmark/stats.js +6 -20
- package/dist/atlas/benchmark/stats.js.map +1 -1
- package/dist/atlas/physjs-entries.generated.d.ts +13 -4
- package/dist/atlas/physjs-entries.generated.d.ts.map +1 -1
- package/dist/atlas/physjs-entries.generated.js +15 -4
- package/dist/atlas/physjs-entries.generated.js.map +1 -1
- package/dist/atlas/physjs-reviewed.js +2 -2
- package/dist/atlas/physjs-reviewed.js.map +1 -1
- package/dist/cases/catalog-checks.d.ts +10 -0
- package/dist/cases/catalog-checks.d.ts.map +1 -0
- package/dist/cases/catalog-checks.js +241 -0
- package/dist/cases/catalog-checks.js.map +1 -0
- package/dist/cases/catalog.d.ts +83 -0
- package/dist/cases/catalog.d.ts.map +1 -0
- package/dist/cases/catalog.js +118 -0
- package/dist/cases/catalog.js.map +1 -0
- package/dist/cases/engine.d.ts +13 -0
- package/dist/cases/engine.d.ts.map +1 -0
- package/dist/cases/engine.js +179 -0
- package/dist/cases/engine.js.map +1 -0
- package/dist/cases/index.d.ts.map +1 -1
- package/dist/cases/index.js +5 -7
- package/dist/cases/index.js.map +1 -1
- package/dist/cases/methods.d.ts +215 -0
- package/dist/cases/methods.d.ts.map +1 -0
- package/dist/cases/methods.js +743 -0
- package/dist/cases/methods.js.map +1 -0
- package/dist/cases/types.d.ts +12 -0
- package/dist/cases/types.d.ts.map +1 -1
- package/dist/cases/types.js.map +1 -1
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/command.d.ts +3 -0
- package/dist/cli/command.d.ts.map +1 -1
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/commands/_discovery-opts.d.ts +1 -0
- package/dist/cli/commands/_discovery-opts.d.ts.map +1 -1
- package/dist/cli/commands/_discovery-opts.js +1 -0
- package/dist/cli/commands/_discovery-opts.js.map +1 -1
- package/dist/cli/commands/discover.d.ts.map +1 -1
- package/dist/cli/commands/discover.js +116 -71
- package/dist/cli/commands/discover.js.map +1 -1
- package/dist/cli/commands/evaluate.js +2 -2
- 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 +22 -2
- package/dist/cli/commands/explain.js.map +1 -1
- package/dist/cli/commands/ground.d.ts.map +1 -1
- package/dist/cli/commands/ground.js +6 -1
- package/dist/cli/commands/ground.js.map +1 -1
- package/dist/cli/commands/map.d.ts.map +1 -1
- package/dist/cli/commands/map.js +9 -6
- package/dist/cli/commands/map.js.map +1 -1
- package/dist/cli/determination.d.ts +1 -0
- package/dist/cli/determination.d.ts.map +1 -1
- package/dist/cli/determination.js.map +1 -1
- package/dist/cli/flag-help.d.ts +1 -0
- package/dist/cli/flag-help.d.ts.map +1 -1
- package/dist/cli/flag-help.js +1 -0
- package/dist/cli/flag-help.js.map +1 -1
- package/dist/cli/graphs.d.ts +2 -0
- package/dist/cli/graphs.d.ts.map +1 -1
- package/dist/cli/graphs.js +1 -0
- package/dist/cli/graphs.js.map +1 -1
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +1 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/output.d.ts +8 -0
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +8 -0
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/statuses.d.ts.map +1 -1
- package/dist/cli/statuses.js +12 -2
- package/dist/cli/statuses.js.map +1 -1
- package/dist/cli/version.d.ts +1 -0
- package/dist/cli/version.d.ts.map +1 -1
- package/dist/cli/version.js +1 -0
- package/dist/cli/version.js.map +1 -1
- package/dist/cli-api.d.ts +2 -0
- package/dist/cli-api.d.ts.map +1 -1
- package/dist/cli-api.js +2 -0
- package/dist/cli-api.js.map +1 -1
- package/dist/composition/canonical-graph.d.ts +2 -2
- package/dist/composition/canonical-graph.js +2 -2
- package/dist/composition/canonical-graph.js.map +1 -1
- package/dist/composition/consequence.d.ts +15 -5
- package/dist/composition/consequence.d.ts.map +1 -1
- package/dist/composition/consequence.js +6 -4
- package/dist/composition/consequence.js.map +1 -1
- package/dist/composition/discovery.d.ts +78 -14
- package/dist/composition/discovery.d.ts.map +1 -1
- package/dist/composition/discovery.js +73 -23
- package/dist/composition/discovery.js.map +1 -1
- package/dist/composition/expr-eval.d.ts +1 -1
- package/dist/composition/expr-eval.d.ts.map +1 -1
- package/dist/composition/expr-eval.js +4 -4
- package/dist/composition/expr-eval.js.map +1 -1
- package/dist/composition/expr-simplify.d.ts +10 -14
- package/dist/composition/expr-simplify.d.ts.map +1 -1
- package/dist/composition/expr-simplify.js +49 -52
- package/dist/composition/expr-simplify.js.map +1 -1
- package/dist/composition/grounding.d.ts.map +1 -1
- package/dist/composition/grounding.js +19 -7
- package/dist/composition/grounding.js.map +1 -1
- package/dist/composition/mathts-quiet.d.ts +4 -6
- package/dist/composition/mathts-quiet.d.ts.map +1 -1
- package/dist/composition/mathts-quiet.js +4 -14
- package/dist/composition/mathts-quiet.js.map +1 -1
- package/dist/composition/own-equation-magnitude.d.ts +95 -0
- package/dist/composition/own-equation-magnitude.d.ts.map +1 -0
- package/dist/composition/own-equation-magnitude.js +270 -0
- package/dist/composition/own-equation-magnitude.js.map +1 -0
- package/dist/composition/probe/backend-protocol.d.ts +3 -0
- package/dist/composition/probe/backend-protocol.d.ts.map +1 -1
- package/dist/composition/probe/backend-protocol.js.map +1 -1
- package/dist/composition/probe/candidate-store.d.ts +1 -0
- package/dist/composition/probe/candidate-store.d.ts.map +1 -1
- package/dist/composition/probe/candidate-store.js +1 -0
- package/dist/composition/probe/candidate-store.js.map +1 -1
- package/dist/composition/probe/corpus.d.ts +4 -2
- package/dist/composition/probe/corpus.d.ts.map +1 -1
- package/dist/composition/probe/corpus.js +3 -3
- package/dist/composition/probe/corpus.js.map +1 -1
- package/dist/composition/probe/dataset.d.ts +1 -0
- package/dist/composition/probe/dataset.d.ts.map +1 -1
- package/dist/composition/probe/dataset.js.map +1 -1
- package/dist/composition/probe/experiment-design.d.ts +2 -0
- package/dist/composition/probe/experiment-design.d.ts.map +1 -1
- package/dist/composition/probe/experiment-design.js.map +1 -1
- package/dist/composition/probe/falsify.d.ts +2 -0
- package/dist/composition/probe/falsify.d.ts.map +1 -1
- package/dist/composition/probe/falsify.js.map +1 -1
- package/dist/composition/probe/fit.d.ts +1 -0
- package/dist/composition/probe/fit.d.ts.map +1 -1
- package/dist/composition/probe/fit.js.map +1 -1
- package/dist/composition/probe/generator.d.ts +3 -0
- package/dist/composition/probe/generator.d.ts.map +1 -1
- package/dist/composition/probe/generator.js +5 -6
- package/dist/composition/probe/generator.js.map +1 -1
- package/dist/composition/probe/limits.d.ts +1 -0
- package/dist/composition/probe/limits.d.ts.map +1 -1
- package/dist/composition/probe/limits.js.map +1 -1
- package/dist/composition/probe/pipeline.d.ts +5 -0
- package/dist/composition/probe/pipeline.d.ts.map +1 -1
- package/dist/composition/probe/pipeline.js +64 -21
- package/dist/composition/probe/pipeline.js.map +1 -1
- package/dist/composition/probe/power-law.d.ts.map +1 -1
- package/dist/composition/probe/power-law.js +3 -7
- package/dist/composition/probe/power-law.js.map +1 -1
- package/dist/composition/probe/problem.d.ts +1 -0
- package/dist/composition/probe/problem.d.ts.map +1 -1
- package/dist/composition/probe/problem.js.map +1 -1
- package/dist/composition/probe/residual.d.ts +1 -0
- package/dist/composition/probe/residual.d.ts.map +1 -1
- package/dist/composition/probe/residual.js +1 -0
- package/dist/composition/probe/residual.js.map +1 -1
- package/dist/composition/probe/run-manifest.d.ts +1 -0
- package/dist/composition/probe/run-manifest.d.ts.map +1 -1
- package/dist/composition/probe/run-manifest.js.map +1 -1
- package/dist/composition/probe/scalar-search.d.ts +50 -0
- package/dist/composition/probe/scalar-search.d.ts.map +1 -0
- package/dist/composition/probe/scalar-search.js +169 -0
- package/dist/composition/probe/scalar-search.js.map +1 -0
- package/dist/composition/probe/scoring.d.ts +1 -0
- package/dist/composition/probe/scoring.d.ts.map +1 -1
- package/dist/composition/probe/scoring.js.map +1 -1
- package/dist/composition/probe/study.d.ts +2 -2
- package/dist/composition/probe/study.d.ts.map +1 -1
- package/dist/composition/probe/study.js +6 -10
- package/dist/composition/probe/study.js.map +1 -1
- package/dist/composition/probe/t-tail.d.ts +3 -4
- package/dist/composition/probe/t-tail.d.ts.map +1 -1
- package/dist/composition/probe/t-tail.js +7 -10
- package/dist/composition/probe/t-tail.js.map +1 -1
- package/dist/composition/proposed-bridges.d.ts +11 -2
- package/dist/composition/proposed-bridges.d.ts.map +1 -1
- package/dist/composition/proposed-bridges.js +7 -5
- package/dist/composition/proposed-bridges.js.map +1 -1
- package/dist/composition/rational-exponent.d.ts +2 -2
- package/dist/composition/rational-exponent.d.ts.map +1 -1
- package/dist/composition/rational-exponent.js +4 -4
- package/dist/composition/rational-exponent.js.map +1 -1
- package/dist/composition/representative-values.d.ts.map +1 -1
- package/dist/composition/representative-values.js +6 -0
- package/dist/composition/representative-values.js.map +1 -1
- package/dist/composition/retrodiction.d.ts +15 -0
- package/dist/composition/retrodiction.d.ts.map +1 -1
- package/dist/composition/retrodiction.js +10 -3
- package/dist/composition/retrodiction.js.map +1 -1
- package/dist/composition/user-equation.d.ts +1 -0
- package/dist/composition/user-equation.d.ts.map +1 -1
- package/dist/composition/user-equation.js +1 -0
- package/dist/composition/user-equation.js.map +1 -1
- package/dist/core/constants.d.ts +12 -11
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +24 -21
- package/dist/core/constants.js.map +1 -1
- package/dist/diff/bridge-ast-gradient.d.ts +27 -23
- package/dist/diff/bridge-ast-gradient.d.ts.map +1 -1
- package/dist/diff/bridge-ast-gradient.js +75 -173
- package/dist/diff/bridge-ast-gradient.js.map +1 -1
- package/dist/dimensional/ast-types.d.ts +15 -0
- package/dist/dimensional/ast-types.d.ts.map +1 -1
- package/dist/dimensional/ast-types.js.map +1 -1
- package/dist/dimensional/curvature-composite.d.ts +1 -1
- package/dist/dimensional/curvature-composite.js.map +1 -1
- package/dist/dimensional/exact-scale.d.ts +41 -11
- package/dist/dimensional/exact-scale.d.ts.map +1 -1
- package/dist/dimensional/exact-scale.js +115 -123
- package/dist/dimensional/exact-scale.js.map +1 -1
- package/dist/dimensional/mathts-unit-delegation.d.ts +29 -0
- package/dist/dimensional/mathts-unit-delegation.d.ts.map +1 -0
- package/dist/dimensional/mathts-unit-delegation.js +187 -0
- package/dist/dimensional/mathts-unit-delegation.js.map +1 -0
- package/dist/dimensional/mathts-unit-wrapper.d.ts +33 -0
- package/dist/dimensional/mathts-unit-wrapper.d.ts.map +1 -0
- package/dist/dimensional/mathts-unit-wrapper.js +190 -0
- package/dist/dimensional/mathts-unit-wrapper.js.map +1 -0
- package/dist/dimensional/scalar-lowering.d.ts +21 -0
- package/dist/dimensional/scalar-lowering.d.ts.map +1 -0
- package/dist/dimensional/scalar-lowering.js +45 -0
- package/dist/dimensional/scalar-lowering.js.map +1 -0
- package/dist/dimensional/unit-data.d.ts +5 -1
- package/dist/dimensional/unit-data.d.ts.map +1 -1
- package/dist/dimensional/unit-data.js +28 -4
- package/dist/dimensional/unit-data.js.map +1 -1
- package/dist/dimensional/units.d.ts +2 -0
- package/dist/dimensional/units.d.ts.map +1 -1
- package/dist/dimensional/units.js +59 -3
- package/dist/dimensional/units.js.map +1 -1
- package/dist/dimensional/validator.d.ts +2 -0
- package/dist/dimensional/validator.d.ts.map +1 -1
- package/dist/dimensional/validator.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/numerical/connection-lowering-helpers.d.ts +3 -1
- package/dist/numerical/connection-lowering-helpers.d.ts.map +1 -1
- package/dist/numerical/connection-lowering-helpers.js +11 -15
- package/dist/numerical/connection-lowering-helpers.js.map +1 -1
- package/dist/numerical/pderiv.d.ts.map +1 -1
- package/dist/numerical/pderiv.js +2 -6
- package/dist/numerical/pderiv.js.map +1 -1
- package/dist/numerical/quadrature.js +3 -3
- package/dist/numerical/quadrature.js.map +1 -1
- package/dist/numerical/statistics.js +1 -1
- package/dist/numerical/statistics.js.map +1 -1
- package/dist/numerical/strides.d.ts +3 -2
- package/dist/numerical/strides.d.ts.map +1 -1
- package/dist/numerical/strides.js +3 -10
- package/dist/numerical/strides.js.map +1 -1
- package/package.json +9 -12
- package/dist/cases/brownian-sphere.d.ts +0 -68
- package/dist/cases/brownian-sphere.d.ts.map +0 -1
- package/dist/cases/brownian-sphere.js +0 -355
- package/dist/cases/brownian-sphere.js.map +0 -1
- package/dist/cases/damped-resonator.d.ts +0 -23
- package/dist/cases/damped-resonator.d.ts.map +0 -1
- package/dist/cases/damped-resonator.js +0 -221
- package/dist/cases/damped-resonator.js.map +0 -1
- package/dist/cases/kepler-rv.d.ts +0 -13
- package/dist/cases/kepler-rv.d.ts.map +0 -1
- package/dist/cases/kepler-rv.js +0 -173
- package/dist/cases/kepler-rv.js.map +0 -1
- package/dist/cases/lumped-cooling.d.ts +0 -51
- package/dist/cases/lumped-cooling.d.ts.map +0 -1
- package/dist/cases/lumped-cooling.js +0 -259
- package/dist/cases/lumped-cooling.js.map +0 -1
- package/dist/cases/resistor-noise.d.ts +0 -14
- package/dist/cases/resistor-noise.d.ts.map +0 -1
- package/dist/cases/resistor-noise.js +0 -215
- package/dist/cases/resistor-noise.js.map +0 -1
- package/dist/cases/skin-depth.d.ts +0 -17
- package/dist/cases/skin-depth.d.ts.map +0 -1
- package/dist/cases/skin-depth.js +0 -170
- package/dist/cases/skin-depth.js.map +0 -1
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Exact bridge-gradients
|
|
2
|
+
* Exact bridge-gradients over the symbolic RHS AST.
|
|
3
3
|
*
|
|
4
4
|
* The catalog's plain-JS evaluators cannot be differentiated by AD (they run
|
|
5
5
|
* raw `Math.*` arithmetic and return a number, which carries no tape; see
|
|
6
6
|
* `bridge-gradient.ts`). But each bridge also carries a faithful symbolic
|
|
7
7
|
* encoding of its RHS (`*_RHS: ExprNode`). This module lowers that scalar AST
|
|
8
|
-
*
|
|
9
|
-
* chosen variable
|
|
10
|
-
*
|
|
11
|
-
* the plain-JS evaluators
|
|
8
|
+
* with the MathTS scalar builder and differentiates it with MathTS
|
|
9
|
+
* `compileScalarGradient`: the chosen variable is the one parameter, and every
|
|
10
|
+
* other symbol is a constant. The result is the EXACT derivative (machine
|
|
11
|
+
* precision); the plain-JS evaluators stay untouched (P8 Decision #1).
|
|
12
12
|
*
|
|
13
|
-
* Scope: the
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* an exponent).
|
|
13
|
+
* Scope: the scalar grammar is `symbol` + `op(+ − * / ^)` + `transcendental` +
|
|
14
|
+
* `abs`. A bridge encoded with a typed stub differentiates with respect to the
|
|
15
|
+
* stub, not the physics inside it; fully-expanded encodings (e.g. BE-42
|
|
16
|
+
* `ℏc³/(8πGM·k_B)`) differentiate exactly. A `^` exponent must be constant: a
|
|
17
|
+
* UPT pre-check refuses the differentiation variable in an exponent before
|
|
18
|
+
* MathTS sees the tree.
|
|
20
19
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* A point where the value overflows gives `NaN` for the value and the
|
|
21
|
+
* gradient (MathTS marks the row invalid), not `±Infinity`.
|
|
23
22
|
*
|
|
24
23
|
* @module diff/bridge-ast-gradient
|
|
25
24
|
*/
|
|
@@ -35,31 +34,36 @@ export interface ASTGradientResult {
|
|
|
35
34
|
readonly gradient: number;
|
|
36
35
|
}
|
|
37
36
|
/**
|
|
38
|
-
* Differentiate a scalar bridge RHS AST with respect to one symbol
|
|
39
|
-
*
|
|
40
|
-
* (caller `bindings`, then {@link NAMED_CONSTANTS}, then numeric
|
|
41
|
-
* `bindings` must contain `varName` (its value sets the point of
|
|
37
|
+
* Differentiate a scalar bridge RHS AST with respect to one symbol through
|
|
38
|
+
* MathTS `compileScalarGradient`. Every symbol other than `varName` is resolved
|
|
39
|
+
* to a constant (caller `bindings`, then {@link NAMED_CONSTANTS}, then numeric
|
|
40
|
+
* literal); the `bindings` must contain `varName` (its value sets the point of
|
|
41
|
+
* evaluation).
|
|
42
42
|
*
|
|
43
|
+
* @throws TypeError when `varName` is not bound, a symbol cannot be resolved,
|
|
44
|
+
* `varName` appears in an exponent, or a node kind is outside the scalar grammar.
|
|
43
45
|
* @public
|
|
44
46
|
*/
|
|
45
|
-
export declare function bridgeGradientAST(rhs: ExprNode, varName: string, bindings: Record<string, number>):
|
|
47
|
+
export declare function bridgeGradientAST(rhs: ExprNode, varName: string, bindings: Record<string, number>): ASTGradientResult;
|
|
46
48
|
/**
|
|
47
49
|
* Convenience wrapper around {@link bridgeGradientAST} that looks the RHS AST up
|
|
48
50
|
* by catalog bridge id. `bridgeId` accepts a number, `'42'`, or `'BE-42'`.
|
|
49
51
|
*
|
|
50
52
|
* Throws if the id has no encoded RHS in {@link BRIDGE_RHS_BY_ID} (e.g. BE-51/52,
|
|
51
53
|
* which are closed-form evaluators without an AST). If the bridge's RHS is not in
|
|
52
|
-
* the differentiable scalar grammar (a tensor
|
|
54
|
+
* the differentiable scalar grammar (a tensor, integral or curvature encoding), the
|
|
53
55
|
* delegated `bridgeGradientAST` throws the "unsupported node kind" error — use
|
|
54
56
|
* {@link astDifferentiableBridgeIds} to discover which ids are AD-eligible.
|
|
55
57
|
*
|
|
56
58
|
* @public
|
|
57
59
|
*/
|
|
58
|
-
export declare function bridgeGradientASTById(bridgeId: number | string, varName: string, bindings: Record<string, number>):
|
|
60
|
+
export declare function bridgeGradientASTById(bridgeId: number | string, varName: string, bindings: Record<string, number>): ASTGradientResult;
|
|
59
61
|
/**
|
|
60
62
|
* The catalog bridge ids whose encoded RHS lies entirely in the differentiable
|
|
61
|
-
* scalar grammar
|
|
62
|
-
*
|
|
63
|
+
* scalar grammar. `bridgeGradientASTById` differentiates each of them exactly
|
|
64
|
+
* with respect to any variable that is not in an exponent; a variable in an
|
|
65
|
+
* exponent is refused (`checkExponents`).
|
|
66
|
+
* Bridges encoded with tensor, integral or curvature nodes (or whose physics is
|
|
63
67
|
* hidden behind a typed-stub symbol) are excluded from EXACT differentiation
|
|
64
68
|
* (a stub still differentiates w.r.t. the stub symbol, but not the physics
|
|
65
69
|
* inside it). Returned sorted ascending.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-ast-gradient.d.ts","sourceRoot":"","sources":["../../src/diff/bridge-ast-gradient.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bridge-ast-gradient.d.ts","sourceRoot":"","sources":["../../src/diff/bridge-ast-gradient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAM5D;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAgFD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,QAAQ,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,iBAAiB,CAkCnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,iBAAiB,CAUnB;AAaD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,EAAE,CAMrD"}
|
|
@@ -1,69 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Exact bridge-gradients
|
|
2
|
+
* Exact bridge-gradients over the symbolic RHS AST.
|
|
3
3
|
*
|
|
4
4
|
* The catalog's plain-JS evaluators cannot be differentiated by AD (they run
|
|
5
5
|
* raw `Math.*` arithmetic and return a number, which carries no tape; see
|
|
6
6
|
* `bridge-gradient.ts`). But each bridge also carries a faithful symbolic
|
|
7
7
|
* encoding of its RHS (`*_RHS: ExprNode`). This module lowers that scalar AST
|
|
8
|
-
*
|
|
9
|
-
* chosen variable
|
|
10
|
-
*
|
|
11
|
-
* the plain-JS evaluators
|
|
8
|
+
* with the MathTS scalar builder and differentiates it with MathTS
|
|
9
|
+
* `compileScalarGradient`: the chosen variable is the one parameter, and every
|
|
10
|
+
* other symbol is a constant. The result is the EXACT derivative (machine
|
|
11
|
+
* precision); the plain-JS evaluators stay untouched (P8 Decision #1).
|
|
12
12
|
*
|
|
13
|
-
* Scope: the
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* an exponent).
|
|
13
|
+
* Scope: the scalar grammar is `symbol` + `op(+ − * / ^)` + `transcendental` +
|
|
14
|
+
* `abs`. A bridge encoded with a typed stub differentiates with respect to the
|
|
15
|
+
* stub, not the physics inside it; fully-expanded encodings (e.g. BE-42
|
|
16
|
+
* `ℏc³/(8πGM·k_B)`) differentiate exactly. A `^` exponent must be constant: a
|
|
17
|
+
* UPT pre-check refuses the differentiation variable in an exponent before
|
|
18
|
+
* MathTS sees the tree.
|
|
20
19
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* A point where the value overflows gives `NaN` for the value and the
|
|
21
|
+
* gradient (MathTS marks the row invalid), not `±Infinity`.
|
|
23
22
|
*
|
|
24
23
|
* @module diff/bridge-ast-gradient
|
|
25
24
|
*/
|
|
25
|
+
import { ScalarBuildError } from '@danielsimonjr/mathts-expression';
|
|
26
|
+
import { compileScalarGradient } from '@danielsimonjr/mathts-functions';
|
|
27
|
+
import { forEachScalarLeaf, isDecimalLiteral } from '../dimensional/ast-leaves.js';
|
|
26
28
|
import { constantScope } from '../dimensional/symbolic-constants.js';
|
|
27
|
-
import {
|
|
29
|
+
import { toScalarNode } from '../dimensional/scalar-lowering.js';
|
|
28
30
|
import { BRIDGE_RHS_BY_ID, parseBridgeId } from '../bridges/rhs-registry.js';
|
|
29
|
-
import { GAUSS_LEGENDRE_16 } from '../numerical/quadrature.js';
|
|
30
|
-
/** Map a transcendental fn name to the TapedTensor method that traces it. */
|
|
31
|
-
function applyTranscendental(fn, t) {
|
|
32
|
-
switch (fn) {
|
|
33
|
-
case 'exp':
|
|
34
|
-
return t.exp();
|
|
35
|
-
case 'ln':
|
|
36
|
-
return t.log();
|
|
37
|
-
case 'log2':
|
|
38
|
-
return t.log2();
|
|
39
|
-
case 'log10':
|
|
40
|
-
return t.log10();
|
|
41
|
-
case 'sin':
|
|
42
|
-
return t.sin();
|
|
43
|
-
case 'cos':
|
|
44
|
-
return t.cos();
|
|
45
|
-
case 'tan':
|
|
46
|
-
return t.tan();
|
|
47
|
-
case 'sinh':
|
|
48
|
-
return t.sinh();
|
|
49
|
-
case 'cosh':
|
|
50
|
-
return t.cosh();
|
|
51
|
-
case 'tanh':
|
|
52
|
-
return t.tanh();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
31
|
/**
|
|
56
32
|
* Named physical constants the bridge encodings reference as bare symbols:
|
|
57
33
|
* every registered spelling, from the constant registry, plus π and its
|
|
58
|
-
* registered multiples, so
|
|
34
|
+
* registered multiples, so the AST evaluates to the SAME number as the
|
|
59
35
|
* numeric evaluator. Callers can override or extend via the `bindings` argument.
|
|
60
36
|
*/
|
|
61
37
|
const NAMED_CONSTANTS = constantScope();
|
|
62
38
|
/** Resolve a symbol's numeric value: caller bindings → named constants → numeric literal. */
|
|
63
39
|
function resolveConstant(name, bindings) {
|
|
64
|
-
if (Object.
|
|
40
|
+
if (Object.hasOwn(bindings, name))
|
|
65
41
|
return bindings[name];
|
|
66
|
-
if (Object.
|
|
42
|
+
if (Object.hasOwn(NAMED_CONSTANTS, name))
|
|
67
43
|
return NAMED_CONSTANTS[name];
|
|
68
44
|
const asNumber = Number(name);
|
|
69
45
|
if (name.trim() !== '' && Number.isFinite(asNumber))
|
|
@@ -75,9 +51,8 @@ function resolveConstant(name, bindings) {
|
|
|
75
51
|
*
|
|
76
52
|
* The exponent may contain scalar arithmetic over constants/bindings (for
|
|
77
53
|
* example `-1/z`) as long as it is independent of the differentiation
|
|
78
|
-
* variable.
|
|
79
|
-
*
|
|
80
|
-
* explicitly rather than being silently detached from AD.
|
|
54
|
+
* variable. UPT keeps the constant-power contract, so the differentiation
|
|
55
|
+
* variable in an exponent is refused before MathTS reads the tree.
|
|
81
56
|
*/
|
|
82
57
|
function resolveExponent(node, varName, bindings) {
|
|
83
58
|
if (node.kind === 'symbol') {
|
|
@@ -103,125 +78,60 @@ function resolveExponent(node, varName, bindings) {
|
|
|
103
78
|
throw new TypeError(`bridgeGradientAST: '^' exponent must be a constant scalar expression, got node kind '${node.kind}'.`);
|
|
104
79
|
}
|
|
105
80
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
|
|
81
|
+
* Refuse the differentiation variable in any `^` exponent, and check that every
|
|
82
|
+
* exponent is a constant scalar expression. MathTS would differentiate a
|
|
83
|
+
* variable exponent; UPT keeps the constant-power contract.
|
|
84
|
+
*/
|
|
85
|
+
function checkExponents(node, varName, bindings) {
|
|
86
|
+
if (node.kind === 'op') {
|
|
87
|
+
if (node.op === '^' && node.args.length === 2)
|
|
88
|
+
resolveExponent(node.args[1], varName, bindings);
|
|
89
|
+
for (const arg of node.args)
|
|
90
|
+
checkExponents(arg, varName, bindings);
|
|
91
|
+
}
|
|
92
|
+
else if (node.kind === 'transcendental' || node.kind === 'abs') {
|
|
93
|
+
checkExponents(node.arg, varName, bindings);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Differentiate a scalar bridge RHS AST with respect to one symbol through
|
|
98
|
+
* MathTS `compileScalarGradient`. Every symbol other than `varName` is resolved
|
|
99
|
+
* to a constant (caller `bindings`, then {@link NAMED_CONSTANTS}, then numeric
|
|
100
|
+
* literal); the `bindings` must contain `varName` (its value sets the point of
|
|
101
|
+
* evaluation).
|
|
110
102
|
*
|
|
103
|
+
* @throws TypeError when `varName` is not bound, a symbol cannot be resolved,
|
|
104
|
+
* `varName` appears in an exponent, or a node kind is outside the scalar grammar.
|
|
111
105
|
* @public
|
|
112
106
|
*/
|
|
113
|
-
export
|
|
114
|
-
if (!Object.
|
|
107
|
+
export function bridgeGradientAST(rhs, varName, bindings) {
|
|
108
|
+
if (!Object.hasOwn(bindings, varName)) {
|
|
115
109
|
throw new TypeError(`bridgeGradientAST: bindings must contain the differentiation variable '${varName}'.`);
|
|
116
110
|
}
|
|
117
|
-
|
|
118
|
-
let
|
|
111
|
+
checkExponents(rhs, varName, bindings);
|
|
112
|
+
let lowered;
|
|
119
113
|
try {
|
|
120
|
-
|
|
121
|
-
// this lowering calls: reverseGrad, TapedTensor, Tensor.fromNested …).
|
|
122
|
-
// The casts state that those members exist on the imported modules, which
|
|
123
|
-
// their own type declarations guarantee; the full MathTS types are not
|
|
124
|
-
// imported so this file compiles without the autograd types at hand.
|
|
125
|
-
autograd =
|
|
126
|
-
(await import('@danielsimonjr/mathts-autograd'));
|
|
127
|
-
tensorMod =
|
|
128
|
-
(await import('@danielsimonjr/mathts-tensor'));
|
|
114
|
+
lowered = toScalarNode(rhs);
|
|
129
115
|
}
|
|
130
|
-
catch {
|
|
131
|
-
|
|
116
|
+
catch (err) {
|
|
117
|
+
if (!(err instanceof ScalarBuildError))
|
|
118
|
+
throw err;
|
|
119
|
+
throw new TypeError(`bridgeGradientAST: unsupported node kind — ${err.message}. The differentiable grammar is ` +
|
|
120
|
+
`symbol + op(+ − * / ^) + transcendental + abs. Other encodings (tensor/curvature, integrals, ` +
|
|
121
|
+
`or physics hidden in a typed-stub symbol) are not exactly differentiable.`);
|
|
132
122
|
}
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const bound = boundVars.get(node.name);
|
|
146
|
-
if (bound !== undefined)
|
|
147
|
-
return bound;
|
|
148
|
-
return node.name === varName
|
|
149
|
-
? x
|
|
150
|
-
: constLeaf(resolveConstant(node.name, bindings));
|
|
151
|
-
}
|
|
152
|
-
if (node.kind === 'op') {
|
|
153
|
-
switch (node.op) {
|
|
154
|
-
case '+':
|
|
155
|
-
return node.args.map((a) => walk(a, boundVars)).reduce((a, b) => a.add(b));
|
|
156
|
-
case '-': {
|
|
157
|
-
const terms = node.args.map((a) => walk(a, boundVars));
|
|
158
|
-
// Unary minus (0 − t); n-ary subtract folds left.
|
|
159
|
-
return terms.length === 1
|
|
160
|
-
? constLeaf(0).sub(terms[0])
|
|
161
|
-
: terms.reduce((a, b) => a.sub(b));
|
|
162
|
-
}
|
|
163
|
-
case '*':
|
|
164
|
-
return node.args.map((a) => walk(a, boundVars)).reduce((a, b) => a.mul(b));
|
|
165
|
-
case '/':
|
|
166
|
-
return node.args.map((a) => walk(a, boundVars)).reduce((a, b) => a.divide(b));
|
|
167
|
-
case '^':
|
|
168
|
-
return walk(node.args[0], boundVars).pow(resolveExponent(node.args[1], varName, bindings));
|
|
169
|
-
default:
|
|
170
|
-
throw new TypeError(`bridgeGradientAST: unsupported operator '${node.op}'.`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
if (node.kind === 'transcendental') {
|
|
174
|
-
return applyTranscendental(node.fn, walk(node.arg, boundVars));
|
|
175
|
-
}
|
|
176
|
-
if (node.kind === 'abs') {
|
|
177
|
-
return walk(node.arg, boundVars).abs();
|
|
178
|
-
}
|
|
179
|
-
if (node.kind === 'integral') {
|
|
180
|
-
// Definite integral via 16-point Gauss–Legendre quadrature, built from
|
|
181
|
-
// traced ops so reverse-mode AD yields the gradient w.r.t. integrand
|
|
182
|
-
// parameters (Leibniz: ∫ ∂f/∂θ) and w.r.t. bounds (∂Q/∂b ≈ f(b)).
|
|
183
|
-
// NOTE: the gradient is EXACT for the quadrature, which APPROXIMATES the
|
|
184
|
-
// true integral for non-polynomial integrands (exact for constant /
|
|
185
|
-
// polynomial-degree ≤ 31 integrands).
|
|
186
|
-
if (!node.lower || !node.upper) {
|
|
187
|
-
throw new TypeError(`bridgeGradientAST: an abstract (bound-less) integral is not differentiable; ` +
|
|
188
|
-
`supply lower/upper bounds for a definite integral.`);
|
|
189
|
-
}
|
|
190
|
-
if (node.over.kind !== 'symbol') {
|
|
191
|
-
throw new TypeError(`bridgeGradientAST: integral 'over' must be a symbol.`);
|
|
192
|
-
}
|
|
193
|
-
const overName = node.over.name;
|
|
194
|
-
if (overName === varName) {
|
|
195
|
-
throw new TypeError(`bridgeGradientAST: cannot differentiate w.r.t. the integration variable '${overName}'.`);
|
|
196
|
-
}
|
|
197
|
-
const lo = walk(node.lower, boundVars);
|
|
198
|
-
const hi = walk(node.upper, boundVars);
|
|
199
|
-
const half = hi.sub(lo).scale(0.5); // (b − a)/2
|
|
200
|
-
const mid = lo.add(hi).scale(0.5); // (a + b)/2
|
|
201
|
-
let sum = null;
|
|
202
|
-
for (const gl of GAUSS_LEGENDRE_16) {
|
|
203
|
-
const xPoint = mid.add(half.scale(gl.node)); // (b−a)/2·ξ + (a+b)/2
|
|
204
|
-
const env = new Map(boundVars);
|
|
205
|
-
env.set(overName, xPoint);
|
|
206
|
-
const term = walk(node.integrand, env).scale(gl.weight);
|
|
207
|
-
sum = sum === null ? term : sum.add(term);
|
|
208
|
-
}
|
|
209
|
-
// GAUSS_LEGENDRE_16 is non-empty, so `sum` is set.
|
|
210
|
-
return half.mul(sum);
|
|
211
|
-
}
|
|
212
|
-
throw new TypeError(`bridgeGradientAST: unsupported node kind '${node.kind}' — the differentiable ` +
|
|
213
|
-
`grammar is symbol + op(+ − * / ^) + transcendental + abs + definite integral. ` +
|
|
214
|
-
`Other encodings (tensor/curvature, bound-less integrals, or physics hidden in ` +
|
|
215
|
-
`a typed-stub symbol) are not exactly differentiable.`);
|
|
216
|
-
};
|
|
217
|
-
return walk(rhs, new Map());
|
|
218
|
-
};
|
|
219
|
-
const xLeaf = Tensor.fromNested(bindings[varName], []);
|
|
220
|
-
const { value, gradient } = reverseGrad(fn, xLeaf);
|
|
221
|
-
return {
|
|
222
|
-
value: value.toNested(),
|
|
223
|
-
gradient: gradient.toNested(),
|
|
224
|
-
};
|
|
123
|
+
const constants = {};
|
|
124
|
+
forEachScalarLeaf(rhs, (leaf) => {
|
|
125
|
+
if (leaf.name === varName)
|
|
126
|
+
return;
|
|
127
|
+
// A literal spelling stays MathTS's literal unless the caller bound that name.
|
|
128
|
+
if (isDecimalLiteral(leaf.name) && !Object.hasOwn(bindings, leaf.name))
|
|
129
|
+
return;
|
|
130
|
+
constants[leaf.name] = resolveConstant(leaf.name, bindings);
|
|
131
|
+
}, { transcendental: true, abs: true });
|
|
132
|
+
const compiled = compileScalarGradient(lowered, { variables: [], parameters: [varName], constants });
|
|
133
|
+
const { values, grad } = compiled.evaluate([], [bindings[varName]]);
|
|
134
|
+
return { value: values[0], gradient: grad[0] };
|
|
225
135
|
}
|
|
226
136
|
/**
|
|
227
137
|
* Convenience wrapper around {@link bridgeGradientAST} that looks the RHS AST up
|
|
@@ -229,7 +139,7 @@ export async function bridgeGradientAST(rhs, varName, bindings) {
|
|
|
229
139
|
*
|
|
230
140
|
* Throws if the id has no encoded RHS in {@link BRIDGE_RHS_BY_ID} (e.g. BE-51/52,
|
|
231
141
|
* which are closed-form evaluators without an AST). If the bridge's RHS is not in
|
|
232
|
-
* the differentiable scalar grammar (a tensor
|
|
142
|
+
* the differentiable scalar grammar (a tensor, integral or curvature encoding), the
|
|
233
143
|
* delegated `bridgeGradientAST` throws the "unsupported node kind" error — use
|
|
234
144
|
* {@link astDifferentiableBridgeIds} to discover which ids are AD-eligible.
|
|
235
145
|
*
|
|
@@ -244,7 +154,7 @@ export function bridgeGradientASTById(bridgeId, varName, bindings) {
|
|
|
244
154
|
}
|
|
245
155
|
return bridgeGradientAST(rhs, varName, bindings);
|
|
246
156
|
}
|
|
247
|
-
/** Whether an AST consists solely of the differentiable scalar grammar (symbol + op(+ − * / ^)). */
|
|
157
|
+
/** Whether an AST consists solely of the differentiable scalar grammar (symbol + op(+ − * / ^) + transcendental + abs). */
|
|
248
158
|
function isDifferentiableScalarAST(node) {
|
|
249
159
|
if (node.kind === 'symbol')
|
|
250
160
|
return true;
|
|
@@ -253,24 +163,16 @@ function isDifferentiableScalarAST(node) {
|
|
|
253
163
|
return false;
|
|
254
164
|
return node.args.every(isDifferentiableScalarAST);
|
|
255
165
|
}
|
|
256
|
-
if (node.kind === 'transcendental')
|
|
166
|
+
if (node.kind === 'transcendental' || node.kind === 'abs')
|
|
257
167
|
return isDifferentiableScalarAST(node.arg);
|
|
258
|
-
if (node.kind === 'abs')
|
|
259
|
-
return isDifferentiableScalarAST(node.arg);
|
|
260
|
-
if (node.kind === 'integral') {
|
|
261
|
-
return (!!node.lower &&
|
|
262
|
-
!!node.upper &&
|
|
263
|
-
node.over.kind === 'symbol' &&
|
|
264
|
-
isDifferentiableScalarAST(node.integrand) &&
|
|
265
|
-
isDifferentiableScalarAST(node.lower) &&
|
|
266
|
-
isDifferentiableScalarAST(node.upper));
|
|
267
|
-
}
|
|
268
168
|
return false;
|
|
269
169
|
}
|
|
270
170
|
/**
|
|
271
171
|
* The catalog bridge ids whose encoded RHS lies entirely in the differentiable
|
|
272
|
-
* scalar grammar
|
|
273
|
-
*
|
|
172
|
+
* scalar grammar. `bridgeGradientASTById` differentiates each of them exactly
|
|
173
|
+
* with respect to any variable that is not in an exponent; a variable in an
|
|
174
|
+
* exponent is refused (`checkExponents`).
|
|
175
|
+
* Bridges encoded with tensor, integral or curvature nodes (or whose physics is
|
|
274
176
|
* hidden behind a typed-stub symbol) are excluded from EXACT differentiation
|
|
275
177
|
* (a stub still differentiates w.r.t. the stub symbol, but not the physics
|
|
276
178
|
* inside it). Returned sorted ascending.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-ast-gradient.js","sourceRoot":"","sources":["../../src/diff/bridge-ast-gradient.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Exact bridge-gradients via reverse-mode AD over the symbolic RHS AST.\n *\n * The catalog's plain-JS evaluators cannot be differentiated by AD (they run\n * raw `Math.*` arithmetic and return a number, which carries no tape; see\n * `bridge-gradient.ts`). But each bridge also carries a faithful symbolic\n * encoding of its RHS (`*_RHS: ExprNode`). This module lowers that scalar AST\n * through `@danielsimonjr/mathts-autograd`'s `TapedTensor` ops — binding the\n * chosen variable to a traced input and every other symbol to a constant tape\n * leaf — so `reverseGrad` returns the EXACT derivative (machine precision), with\n * the plain-JS evaluators left untouched (P8 Decision #1).\n *\n * Scope: the dimensional scalar grammar is `symbol` + `op(+ − * / ^)` (the\n * transcendentals of a bridge are absorbed into typed-stub *symbols*, so they\n * appear as opaque constants here). A bridge encoded with a typed stub therefore\n * differentiates with respect to the stub, not the physics inside it — faithful,\n * fully-expanded encodings (e.g. BE-42 `ℏc³/(8πGM·k_B)`) differentiate exactly.\n * `^` exponents must be constant (the differentiation variable may not appear in\n * an exponent).\n *\n * Loads `@danielsimonjr/mathts-autograd` at the call and throws\n * `EngineCapabilityError` when that import fails.\n *\n * @module diff/bridge-ast-gradient\n */\n\nimport type { ExprNode, TranscendentalFn } from '../dimensional/validator.js';\nimport { constantScope } from '../dimensional/symbolic-constants.js';\nimport { EngineCapabilityError } from '../numerical/errors.js';\nimport { BRIDGE_RHS_BY_ID, parseBridgeId } from '../bridges/rhs-registry.js';\nimport { GAUSS_LEGENDRE_16 } from '../numerical/quadrature.js';\n\n/**\n * Result of {@link bridgeGradientAST}: the bridge's scalar `value` at the\n * supplied point and the exact `gradient` d(value)/d(varName).\n *\n * @public\n */\nexport interface ASTGradientResult {\n readonly value: number;\n readonly gradient: number;\n}\n\n// --- Structural views of the autograd/tensor packages (required dependencies; the\n// dynamic import keeps the AD path off the module's load, and its result is narrowed\n// to the call-site shape). ---\n\ntype TapeHandle = unknown;\n\ninterface TapedScalar {\n readonly tape: TapeHandle;\n add(o: TapedScalar): TapedScalar;\n sub(o: TapedScalar): TapedScalar;\n mul(o: TapedScalar): TapedScalar;\n divide(o: TapedScalar): TapedScalar;\n scale(k: number): TapedScalar;\n pow(k: number): TapedScalar;\n exp(): TapedScalar;\n log(): TapedScalar;\n log2(): TapedScalar;\n log10(): TapedScalar;\n sin(): TapedScalar;\n cos(): TapedScalar;\n tan(): TapedScalar;\n sinh(): TapedScalar;\n cosh(): TapedScalar;\n tanh(): TapedScalar;\n abs(): TapedScalar;\n}\n\n/** Map a transcendental fn name to the TapedTensor method that traces it. */\nfunction applyTranscendental(fn: TranscendentalFn, t: TapedScalar): TapedScalar {\n switch (fn) {\n case 'exp':\n return t.exp();\n case 'ln':\n return t.log();\n case 'log2':\n return t.log2();\n case 'log10':\n return t.log10();\n case 'sin':\n return t.sin();\n case 'cos':\n return t.cos();\n case 'tan':\n return t.tan();\n case 'sinh':\n return t.sinh();\n case 'cosh':\n return t.cosh();\n case 'tanh':\n return t.tanh();\n }\n}\n\ninterface MathTSTensorLike {\n toNested(): unknown;\n}\n\ninterface AutogradModuleLike {\n reverseGrad(\n fn: (x: TapedScalar) => TapedScalar,\n x: MathTSTensorLike,\n cotangent?: MathTSTensorLike,\n ): { value: MathTSTensorLike; gradient: MathTSTensorLike };\n TapedTensor: {\n fromTensorAsInput(t: MathTSTensorLike, tape: TapeHandle): TapedScalar;\n };\n}\n\ninterface TensorModuleLike {\n Tensor: { fromNested(data: number, shape: number[]): MathTSTensorLike };\n}\n\n/**\n * Named physical constants the bridge encodings reference as bare symbols:\n * every registered spelling, from the constant registry, plus π and its\n * registered multiples, so a traced AST evaluates to the SAME number as the\n * numeric evaluator. Callers can override or extend via the `bindings` argument.\n */\nconst NAMED_CONSTANTS: Readonly<Record<string, number>> = constantScope();\n\n/** Resolve a symbol's numeric value: caller bindings → named constants → numeric literal. */\nfunction resolveConstant(\n name: string,\n bindings: Record<string, number>,\n): number {\n if (Object.prototype.hasOwnProperty.call(bindings, name))\n return bindings[name];\n if (Object.prototype.hasOwnProperty.call(NAMED_CONSTANTS, name))\n return NAMED_CONSTANTS[name];\n const asNumber = Number(name);\n if (name.trim() !== '' && Number.isFinite(asNumber)) return asNumber;\n throw new TypeError(\n `bridgeGradientAST: unknown symbol '${name}' — not a binding, a named constant ` +\n `(${Object.keys(NAMED_CONSTANTS).join(', ')}), or a numeric literal. Supply it in bindings.`,\n );\n}\n\n/** Resolve a `^` exponent to a numeric constant expression.\n *\n * The exponent may contain scalar arithmetic over constants/bindings (for\n * example `-1/z`) as long as it is independent of the differentiation\n * variable. Variable exponents require a traced `pow(base, exponent)` op,\n * which the current MathTS tape surface does not expose, so they are rejected\n * explicitly rather than being silently detached from AD.\n */\nfunction resolveExponent(\n node: ExprNode,\n varName: string,\n bindings: Record<string, number>,\n): number {\n if (node.kind === 'symbol') {\n if (node.name === varName) {\n throw new TypeError(\n `bridgeGradientAST: differentiation variable '${varName}' appears as an exponent — ` +\n `variable exponents are not supported (only constant powers).`,\n );\n }\n return resolveConstant(node.name, bindings);\n }\n if (node.kind === 'op') {\n const values = node.args.map((arg) => resolveExponent(arg, varName, bindings));\n if (values.length === 0) {\n throw new TypeError(`bridgeGradientAST: '${node.op}' exponent expression has no operands.`);\n }\n switch (node.op) {\n case '+': return values.reduce((a, b) => a + b);\n case '-': return values.length === 1 ? -values[0] : values.slice(1).reduce((a, b) => a - b, values[0]);\n case '*': return values.reduce((a, b) => a * b);\n case '/': return values.slice(1).reduce((a, b) => a / b, values[0]);\n case '^': return values.slice(1).reduce((a, b) => a ** b, values[0]);\n }\n }\n throw new TypeError(\n `bridgeGradientAST: '^' exponent must be a constant scalar expression, got node kind '${node.kind}'.`,\n );\n}\n\n/**\n * Differentiate a scalar bridge RHS AST with respect to one symbol via\n * reverse-mode AD. Every symbol other than `varName` is resolved to a constant\n * (caller `bindings`, then {@link NAMED_CONSTANTS}, then numeric literal); the\n * `bindings` must contain `varName` (its value sets the point of evaluation).\n *\n * @public\n */\nexport async function bridgeGradientAST(\n rhs: ExprNode,\n varName: string,\n bindings: Record<string, number>,\n): Promise<ASTGradientResult> {\n if (!Object.prototype.hasOwnProperty.call(bindings, varName)) {\n throw new TypeError(\n `bridgeGradientAST: bindings must contain the differentiation variable '${varName}'.`,\n );\n }\n\n let autograd: AutogradModuleLike;\n let tensorMod: TensorModuleLike;\n try {\n // The two modules are typed by the structural views above (the members\n // this lowering calls: reverseGrad, TapedTensor, Tensor.fromNested …).\n // The casts state that those members exist on the imported modules, which\n // their own type declarations guarantee; the full MathTS types are not\n // imported so this file compiles without the autograd types at hand.\n autograd =\n (await import('@danielsimonjr/mathts-autograd')) as unknown as AutogradModuleLike;\n tensorMod =\n (await import('@danielsimonjr/mathts-tensor')) as unknown as TensorModuleLike;\n } catch {\n throw new EngineCapabilityError('mathts-autograd', 'reverseGrad');\n }\n const { reverseGrad, TapedTensor } = autograd;\n const { Tensor } = tensorMod;\n\n // Build the (traced var) → scalar function reverseGrad expects. `x` arrives as\n // a TapedTensor; constants become extra tape leaves (their gradients are\n // computed and ignored — only `x`'s gradient is returned).\n const fn = (x: TapedScalar): TapedScalar => {\n const constLeaf = (v: number): TapedScalar =>\n TapedTensor.fromTensorAsInput(Tensor.fromNested(v, []), x.tape);\n\n // `boundVars` maps an integration variable name to its current (traced)\n // quadrature point; it is checked BEFORE the diff-var / constants so an\n // integration variable correctly shadows an outer symbol of the same name.\n const walk = (node: ExprNode, boundVars: ReadonlyMap<string, TapedScalar>): TapedScalar => {\n if (node.kind === 'symbol') {\n const bound = boundVars.get(node.name);\n if (bound !== undefined) return bound;\n return node.name === varName\n ? x\n : constLeaf(resolveConstant(node.name, bindings));\n }\n if (node.kind === 'op') {\n switch (node.op) {\n case '+':\n return node.args.map((a) => walk(a, boundVars)).reduce((a, b) => a.add(b));\n case '-': {\n const terms = node.args.map((a) => walk(a, boundVars));\n // Unary minus (0 − t); n-ary subtract folds left.\n return terms.length === 1\n ? constLeaf(0).sub(terms[0])\n : terms.reduce((a, b) => a.sub(b));\n }\n case '*':\n return node.args.map((a) => walk(a, boundVars)).reduce((a, b) => a.mul(b));\n case '/':\n return node.args.map((a) => walk(a, boundVars)).reduce((a, b) => a.divide(b));\n case '^':\n return walk(node.args[0], boundVars).pow(\n resolveExponent(node.args[1], varName, bindings),\n );\n default:\n throw new TypeError(\n `bridgeGradientAST: unsupported operator '${node.op}'.`,\n );\n }\n }\n if (node.kind === 'transcendental') {\n return applyTranscendental(node.fn, walk(node.arg, boundVars));\n }\n if (node.kind === 'abs') {\n return walk(node.arg, boundVars).abs();\n }\n if (node.kind === 'integral') {\n // Definite integral via 16-point Gauss–Legendre quadrature, built from\n // traced ops so reverse-mode AD yields the gradient w.r.t. integrand\n // parameters (Leibniz: ∫ ∂f/∂θ) and w.r.t. bounds (∂Q/∂b ≈ f(b)).\n // NOTE: the gradient is EXACT for the quadrature, which APPROXIMATES the\n // true integral for non-polynomial integrands (exact for constant /\n // polynomial-degree ≤ 31 integrands).\n if (!node.lower || !node.upper) {\n throw new TypeError(\n `bridgeGradientAST: an abstract (bound-less) integral is not differentiable; ` +\n `supply lower/upper bounds for a definite integral.`,\n );\n }\n if (node.over.kind !== 'symbol') {\n throw new TypeError(`bridgeGradientAST: integral 'over' must be a symbol.`);\n }\n const overName = node.over.name;\n if (overName === varName) {\n throw new TypeError(\n `bridgeGradientAST: cannot differentiate w.r.t. the integration variable '${overName}'.`,\n );\n }\n const lo = walk(node.lower, boundVars);\n const hi = walk(node.upper, boundVars);\n const half = hi.sub(lo).scale(0.5); // (b − a)/2\n const mid = lo.add(hi).scale(0.5); // (a + b)/2\n let sum: TapedScalar | null = null;\n for (const gl of GAUSS_LEGENDRE_16) {\n const xPoint = mid.add(half.scale(gl.node)); // (b−a)/2·ξ + (a+b)/2\n const env = new Map(boundVars);\n env.set(overName, xPoint);\n const term = walk(node.integrand, env).scale(gl.weight);\n sum = sum === null ? term : sum.add(term);\n }\n // GAUSS_LEGENDRE_16 is non-empty, so `sum` is set.\n return half.mul(sum as TapedScalar);\n }\n throw new TypeError(\n `bridgeGradientAST: unsupported node kind '${node.kind}' — the differentiable ` +\n `grammar is symbol + op(+ − * / ^) + transcendental + abs + definite integral. ` +\n `Other encodings (tensor/curvature, bound-less integrals, or physics hidden in ` +\n `a typed-stub symbol) are not exactly differentiable.`,\n );\n };\n\n return walk(rhs, new Map());\n };\n\n const xLeaf = Tensor.fromNested(bindings[varName], []);\n const { value, gradient } = reverseGrad(fn, xLeaf);\n return {\n value: value.toNested() as number,\n gradient: gradient.toNested() as number,\n };\n}\n\n/**\n * Convenience wrapper around {@link bridgeGradientAST} that looks the RHS AST up\n * by catalog bridge id. `bridgeId` accepts a number, `'42'`, or `'BE-42'`.\n *\n * Throws if the id has no encoded RHS in {@link BRIDGE_RHS_BY_ID} (e.g. BE-51/52,\n * which are closed-form evaluators without an AST). If the bridge's RHS is not in\n * the differentiable scalar grammar (a tensor/integral/curvature encoding), the\n * delegated `bridgeGradientAST` throws the \"unsupported node kind\" error — use\n * {@link astDifferentiableBridgeIds} to discover which ids are AD-eligible.\n *\n * @public\n */\nexport function bridgeGradientASTById(\n bridgeId: number | string,\n varName: string,\n bindings: Record<string, number>\n): Promise<ASTGradientResult> {\n const id = parseBridgeId(bridgeId);\n const rhs = BRIDGE_RHS_BY_ID.get(id);\n if (rhs === undefined) {\n throw new TypeError(\n `bridgeGradientASTById: BE-${id} has no encoded RHS AST in the registry ` +\n `(BE-51/52 are closed-form; ${BRIDGE_RHS_BY_ID.size} bridges have an encoded AST).`\n );\n }\n return bridgeGradientAST(rhs, varName, bindings);\n}\n\n/** Whether an AST consists solely of the differentiable scalar grammar (symbol + op(+ − * / ^)). */\nfunction isDifferentiableScalarAST(node: ExprNode): boolean {\n if (node.kind === 'symbol') return true;\n if (node.kind === 'op') {\n if (!['+', '-', '*', '/', '^'].includes(node.op)) return false;\n return node.args.every(isDifferentiableScalarAST);\n }\n if (node.kind === 'transcendental') return isDifferentiableScalarAST(node.arg);\n if (node.kind === 'abs') return isDifferentiableScalarAST(node.arg);\n if (node.kind === 'integral') {\n return (\n !!node.lower &&\n !!node.upper &&\n node.over.kind === 'symbol' &&\n isDifferentiableScalarAST(node.integrand) &&\n isDifferentiableScalarAST(node.lower) &&\n isDifferentiableScalarAST(node.upper)\n );\n }\n return false;\n}\n\n/**\n * The catalog bridge ids whose encoded RHS lies entirely in the differentiable\n * scalar grammar — i.e. those `bridgeGradientASTById` can differentiate exactly.\n * Bridges encoded with tensor/integral/curvature nodes (or whose physics is\n * hidden behind a typed-stub symbol) are excluded from EXACT differentiation\n * (a stub still differentiates w.r.t. the stub symbol, but not the physics\n * inside it). Returned sorted ascending.\n *\n * @public\n */\nexport function astDifferentiableBridgeIds(): number[] {\n const ids: number[] = [];\n for (const [id, rhs] of BRIDGE_RHS_BY_ID) {\n if (isDifferentiableScalarAST(rhs)) ids.push(id);\n }\n return ids.sort((a, b) => a - b);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bridge-ast-gradient.js","sourceRoot":"","sources":["../../src/diff/bridge-ast-gradient.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Exact bridge-gradients over the symbolic RHS AST.\n *\n * The catalog's plain-JS evaluators cannot be differentiated by AD (they run\n * raw `Math.*` arithmetic and return a number, which carries no tape; see\n * `bridge-gradient.ts`). But each bridge also carries a faithful symbolic\n * encoding of its RHS (`*_RHS: ExprNode`). This module lowers that scalar AST\n * with the MathTS scalar builder and differentiates it with MathTS\n * `compileScalarGradient`: the chosen variable is the one parameter, and every\n * other symbol is a constant. The result is the EXACT derivative (machine\n * precision); the plain-JS evaluators stay untouched (P8 Decision #1).\n *\n * Scope: the scalar grammar is `symbol` + `op(+ − * / ^)` + `transcendental` +\n * `abs`. A bridge encoded with a typed stub differentiates with respect to the\n * stub, not the physics inside it; fully-expanded encodings (e.g. BE-42\n * `ℏc³/(8πGM·k_B)`) differentiate exactly. A `^` exponent must be constant: a\n * UPT pre-check refuses the differentiation variable in an exponent before\n * MathTS sees the tree.\n *\n * A point where the value overflows gives `NaN` for the value and the\n * gradient (MathTS marks the row invalid), not `±Infinity`.\n *\n * @module diff/bridge-ast-gradient\n */\n\nimport { ScalarBuildError } from '@danielsimonjr/mathts-expression';\nimport { compileScalarGradient } from '@danielsimonjr/mathts-functions';\nimport type { ExprNode } from '../dimensional/validator.js';\nimport { forEachScalarLeaf, isDecimalLiteral } from '../dimensional/ast-leaves.js';\nimport { constantScope } from '../dimensional/symbolic-constants.js';\nimport { toScalarNode } from '../dimensional/scalar-lowering.js';\nimport { BRIDGE_RHS_BY_ID, parseBridgeId } from '../bridges/rhs-registry.js';\n\n/**\n * Result of {@link bridgeGradientAST}: the bridge's scalar `value` at the\n * supplied point and the exact `gradient` d(value)/d(varName).\n *\n * @public\n */\nexport interface ASTGradientResult {\n readonly value: number;\n readonly gradient: number;\n}\n\n/**\n * Named physical constants the bridge encodings reference as bare symbols:\n * every registered spelling, from the constant registry, plus π and its\n * registered multiples, so the AST evaluates to the SAME number as the\n * numeric evaluator. Callers can override or extend via the `bindings` argument.\n */\nconst NAMED_CONSTANTS: Readonly<Record<string, number>> = constantScope();\n\n/** Resolve a symbol's numeric value: caller bindings → named constants → numeric literal. */\nfunction resolveConstant(\n name: string,\n bindings: Record<string, number>,\n): number {\n if (Object.hasOwn(bindings, name))\n return bindings[name];\n if (Object.hasOwn(NAMED_CONSTANTS, name))\n return NAMED_CONSTANTS[name];\n const asNumber = Number(name);\n if (name.trim() !== '' && Number.isFinite(asNumber)) return asNumber;\n throw new TypeError(\n `bridgeGradientAST: unknown symbol '${name}' — not a binding, a named constant ` +\n `(${Object.keys(NAMED_CONSTANTS).join(', ')}), or a numeric literal. Supply it in bindings.`,\n );\n}\n\n/** Resolve a `^` exponent to a numeric constant expression.\n *\n * The exponent may contain scalar arithmetic over constants/bindings (for\n * example `-1/z`) as long as it is independent of the differentiation\n * variable. UPT keeps the constant-power contract, so the differentiation\n * variable in an exponent is refused before MathTS reads the tree.\n */\nfunction resolveExponent(\n node: ExprNode,\n varName: string,\n bindings: Record<string, number>,\n): number {\n if (node.kind === 'symbol') {\n if (node.name === varName) {\n throw new TypeError(\n `bridgeGradientAST: differentiation variable '${varName}' appears as an exponent — ` +\n `variable exponents are not supported (only constant powers).`,\n );\n }\n return resolveConstant(node.name, bindings);\n }\n if (node.kind === 'op') {\n const values = node.args.map((arg) => resolveExponent(arg, varName, bindings));\n if (values.length === 0) {\n throw new TypeError(`bridgeGradientAST: '${node.op}' exponent expression has no operands.`);\n }\n switch (node.op) {\n case '+': return values.reduce((a, b) => a + b);\n case '-': return values.length === 1 ? -values[0] : values.slice(1).reduce((a, b) => a - b, values[0]);\n case '*': return values.reduce((a, b) => a * b);\n case '/': return values.slice(1).reduce((a, b) => a / b, values[0]);\n case '^': return values.slice(1).reduce((a, b) => a ** b, values[0]);\n }\n }\n throw new TypeError(\n `bridgeGradientAST: '^' exponent must be a constant scalar expression, got node kind '${node.kind}'.`,\n );\n}\n\n/**\n * Refuse the differentiation variable in any `^` exponent, and check that every\n * exponent is a constant scalar expression. MathTS would differentiate a\n * variable exponent; UPT keeps the constant-power contract.\n */\nfunction checkExponents(node: ExprNode, varName: string, bindings: Record<string, number>): void {\n if (node.kind === 'op') {\n if (node.op === '^' && node.args.length === 2) resolveExponent(node.args[1], varName, bindings);\n for (const arg of node.args) checkExponents(arg, varName, bindings);\n } else if (node.kind === 'transcendental' || node.kind === 'abs') {\n checkExponents(node.arg, varName, bindings);\n }\n}\n\n/**\n * Differentiate a scalar bridge RHS AST with respect to one symbol through\n * MathTS `compileScalarGradient`. Every symbol other than `varName` is resolved\n * to a constant (caller `bindings`, then {@link NAMED_CONSTANTS}, then numeric\n * literal); the `bindings` must contain `varName` (its value sets the point of\n * evaluation).\n *\n * @throws TypeError when `varName` is not bound, a symbol cannot be resolved,\n * `varName` appears in an exponent, or a node kind is outside the scalar grammar.\n * @public\n */\nexport function bridgeGradientAST(\n rhs: ExprNode,\n varName: string,\n bindings: Record<string, number>,\n): ASTGradientResult {\n if (!Object.hasOwn(bindings, varName)) {\n throw new TypeError(\n `bridgeGradientAST: bindings must contain the differentiation variable '${varName}'.`,\n );\n }\n checkExponents(rhs, varName, bindings);\n\n let lowered: ReturnType<typeof toScalarNode>;\n try {\n lowered = toScalarNode(rhs);\n } catch (err) {\n if (!(err instanceof ScalarBuildError)) throw err;\n throw new TypeError(\n `bridgeGradientAST: unsupported node kind — ${err.message}. The differentiable grammar is ` +\n `symbol + op(+ − * / ^) + transcendental + abs. Other encodings (tensor/curvature, integrals, ` +\n `or physics hidden in a typed-stub symbol) are not exactly differentiable.`,\n ); }\n\n const constants: Record<string, number> = {};\n forEachScalarLeaf(\n rhs,\n (leaf) => {\n if (leaf.name === varName) return;\n // A literal spelling stays MathTS's literal unless the caller bound that name.\n if (isDecimalLiteral(leaf.name) && !Object.hasOwn(bindings, leaf.name)) return;\n constants[leaf.name] = resolveConstant(leaf.name, bindings);\n },\n { transcendental: true, abs: true },\n );\n\n const compiled = compileScalarGradient(lowered, { variables: [], parameters: [varName], constants });\n const { values, grad } = compiled.evaluate([], [bindings[varName]]);\n return { value: values[0]!, gradient: grad[0]! };\n}\n\n/**\n * Convenience wrapper around {@link bridgeGradientAST} that looks the RHS AST up\n * by catalog bridge id. `bridgeId` accepts a number, `'42'`, or `'BE-42'`.\n *\n * Throws if the id has no encoded RHS in {@link BRIDGE_RHS_BY_ID} (e.g. BE-51/52,\n * which are closed-form evaluators without an AST). If the bridge's RHS is not in\n * the differentiable scalar grammar (a tensor, integral or curvature encoding), the\n * delegated `bridgeGradientAST` throws the \"unsupported node kind\" error — use\n * {@link astDifferentiableBridgeIds} to discover which ids are AD-eligible.\n *\n * @public\n */\nexport function bridgeGradientASTById(\n bridgeId: number | string,\n varName: string,\n bindings: Record<string, number>\n): ASTGradientResult {\n const id = parseBridgeId(bridgeId);\n const rhs = BRIDGE_RHS_BY_ID.get(id);\n if (rhs === undefined) {\n throw new TypeError(\n `bridgeGradientASTById: BE-${id} has no encoded RHS AST in the registry ` +\n `(BE-51/52 are closed-form; ${BRIDGE_RHS_BY_ID.size} bridges have an encoded AST).`\n );\n }\n return bridgeGradientAST(rhs, varName, bindings);\n}\n\n/** Whether an AST consists solely of the differentiable scalar grammar (symbol + op(+ − * / ^) + transcendental + abs). */\nfunction isDifferentiableScalarAST(node: ExprNode): boolean {\n if (node.kind === 'symbol') return true;\n if (node.kind === 'op') {\n if (!['+', '-', '*', '/', '^'].includes(node.op)) return false;\n return node.args.every(isDifferentiableScalarAST);\n }\n if (node.kind === 'transcendental' || node.kind === 'abs') return isDifferentiableScalarAST(node.arg);\n return false;\n}\n\n/**\n * The catalog bridge ids whose encoded RHS lies entirely in the differentiable\n * scalar grammar. `bridgeGradientASTById` differentiates each of them exactly\n * with respect to any variable that is not in an exponent; a variable in an\n * exponent is refused (`checkExponents`).\n * Bridges encoded with tensor, integral or curvature nodes (or whose physics is\n * hidden behind a typed-stub symbol) are excluded from EXACT differentiation\n * (a stub still differentiates w.r.t. the stub symbol, but not the physics\n * inside it). Returned sorted ascending.\n *\n * @public\n */\nexport function astDifferentiableBridgeIds(): number[] {\n const ids: number[] = [];\n for (const [id, rhs] of BRIDGE_RHS_BY_ID) {\n if (isDifferentiableScalarAST(rhs)) ids.push(id);\n }\n return ids.sort((a, b) => a - b);\n}\n"]}
|
|
@@ -18,8 +18,11 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import type { Dimension } from './types.js';
|
|
20
20
|
import type { CurvatureCompositeNode } from './curvature-composite.js';
|
|
21
|
+
/** The position of a tensor index: upper (contravariant) or lower (covariant). */
|
|
21
22
|
export type Variance = 'upper' | 'lower';
|
|
23
|
+
/** The semantic class of a tensor symbol: coordinate, field or constant. */
|
|
22
24
|
export type Role = 'coordinate' | 'field' | 'constant';
|
|
25
|
+
/** One index of a tensor: its label and whether it is upper or lower. */
|
|
23
26
|
export interface TensorIndex {
|
|
24
27
|
readonly label: string;
|
|
25
28
|
readonly variance: Variance;
|
|
@@ -40,6 +43,7 @@ export interface UpperIndex {
|
|
|
40
43
|
* are excluded — they produce fractional dimensions.)
|
|
41
44
|
*/
|
|
42
45
|
export type TranscendentalFn = 'exp' | 'ln' | 'log2' | 'log10' | 'sin' | 'cos' | 'tan' | 'sinh' | 'cosh' | 'tanh';
|
|
46
|
+
/** A named tensor, with its indices, dimension and optional role. */
|
|
43
47
|
export interface TensorSymbolNode {
|
|
44
48
|
readonly kind: 'tensor-symbol';
|
|
45
49
|
readonly name: string;
|
|
@@ -51,10 +55,12 @@ export interface TensorSymbolNode {
|
|
|
51
55
|
* operand (default 'symbolic'). */
|
|
52
56
|
readonly numericalForm?: 'symbolic' | 'numerical-fn' | 'grid';
|
|
53
57
|
}
|
|
58
|
+
/** An Einstein-summation product of tensor and scalar operands. */
|
|
54
59
|
export interface TensorProductNode {
|
|
55
60
|
readonly kind: 'tensor-product';
|
|
56
61
|
readonly args: ReadonlyArray<ExprNode>;
|
|
57
62
|
}
|
|
63
|
+
/** A metric tensor, with its name, indices, signature and dimension. */
|
|
58
64
|
export interface MetricTensorNode {
|
|
59
65
|
readonly kind: 'metric-tensor';
|
|
60
66
|
readonly name: string;
|
|
@@ -64,11 +70,13 @@ export interface MetricTensorNode {
|
|
|
64
70
|
/** v0.4.0 numerical-lowering hint for ∂g (default 'computed'). */
|
|
65
71
|
readonly derivativeStrategy?: 'computed' | 'zero' | 'supplied';
|
|
66
72
|
}
|
|
73
|
+
/** The Kronecker delta, with its tensor indices and dimension. */
|
|
67
74
|
export interface KroneckerDeltaNode {
|
|
68
75
|
readonly kind: 'kronecker-delta';
|
|
69
76
|
readonly indices: ReadonlyArray<TensorIndex>;
|
|
70
77
|
readonly dim: Dimension;
|
|
71
78
|
}
|
|
79
|
+
/** The partial derivative of an expression, taken on a covariant index. */
|
|
72
80
|
export interface TensorPartialDerivativeNode {
|
|
73
81
|
readonly kind: 'tensor-partial-derivative';
|
|
74
82
|
readonly of: ExprNode;
|
|
@@ -88,6 +96,7 @@ export interface CovariantDerivativeNode {
|
|
|
88
96
|
readonly gLower: MetricTensorNode;
|
|
89
97
|
readonly gInverse: MetricTensorNode;
|
|
90
98
|
}
|
|
99
|
+
/** The Riemann curvature tensor, with one upper and three lower indices. */
|
|
91
100
|
export type RiemannTensorNode = CurvatureCompositeNode<'riemann-tensor', {
|
|
92
101
|
readonly upperIndex: UpperIndex;
|
|
93
102
|
readonly lowerIndices: readonly [CovariantIndex, CovariantIndex, CovariantIndex];
|
|
@@ -126,6 +135,7 @@ export type BianchiResidualNode = CurvatureCompositeNode<'bianchi-residual', {
|
|
|
126
135
|
/** The Riemann tensor whose cyclic-derivative identity is checked. */
|
|
127
136
|
readonly riemann: RiemannTensorNode;
|
|
128
137
|
}>;
|
|
138
|
+
/** The Weyl curvature tensor, the trace-free part of the Riemann tensor. */
|
|
129
139
|
export type WeylTensorNode = CurvatureCompositeNode<'weyl-tensor', {
|
|
130
140
|
/** Metric g_{μν} (both-lower). Present for numerical lowering consumers. */
|
|
131
141
|
readonly metric: MetricTensorNode;
|
|
@@ -147,11 +157,13 @@ export type KretschmannScalarNode = CurvatureCompositeNode<'kretschmann-scalar',
|
|
|
147
157
|
/** Metric (both-lower preferred). */
|
|
148
158
|
readonly metric: MetricTensorNode;
|
|
149
159
|
}>;
|
|
160
|
+
/** A Killing vector field, with its vector and the metric it preserves. */
|
|
150
161
|
export interface KillingVectorNode {
|
|
151
162
|
readonly kind: 'killing-vector';
|
|
152
163
|
readonly vector: TensorSymbolNode;
|
|
153
164
|
readonly metric: MetricTensorNode;
|
|
154
165
|
}
|
|
166
|
+
/** A conserved charge: a Killing vector contracted with a momentum. */
|
|
155
167
|
export interface ConservedChargeNode {
|
|
156
168
|
readonly kind: 'conserved-charge';
|
|
157
169
|
/** The Killing vector ξ^μ (rank-1, upper variance). */
|
|
@@ -160,6 +172,7 @@ export interface ConservedChargeNode {
|
|
|
160
172
|
* vector's index label so ξ^μ p_μ is well-formed. */
|
|
161
173
|
readonly momentum: TensorSymbolNode;
|
|
162
174
|
}
|
|
175
|
+
/** The symmetric stress-energy tensor T, with its indices and component dimension. */
|
|
163
176
|
export interface StressEnergyTensorNode {
|
|
164
177
|
readonly kind: 'stress-energy';
|
|
165
178
|
readonly symbol: 'T';
|
|
@@ -167,6 +180,7 @@ export interface StressEnergyTensorNode {
|
|
|
167
180
|
readonly symmetry: 'symmetric';
|
|
168
181
|
readonly componentDim: Dimension;
|
|
169
182
|
}
|
|
183
|
+
/** The cosmological constant Λ, with its dimension and optional numeric value. */
|
|
170
184
|
export interface CosmologicalConstantNode {
|
|
171
185
|
readonly kind: 'cosmological-constant';
|
|
172
186
|
readonly symbol: 'Λ';
|
|
@@ -186,6 +200,7 @@ export interface EinsteinFieldEquationNode {
|
|
|
186
200
|
readonly rhs: StressEnergyTensorNode;
|
|
187
201
|
readonly coupling: 'einstein';
|
|
188
202
|
}
|
|
203
|
+
/** Any node of a dimensional expression: scalar, calculus, tensor, curvature or field-equation. */
|
|
189
204
|
export type ExprNode = {
|
|
190
205
|
kind: 'symbol';
|
|
191
206
|
name: string;
|