Skip to content

Commit da11c05

Browse files
Add derivative golden fixture export
1 parent f1fef5f commit da11c05

7 files changed

Lines changed: 132 additions & 6 deletions

File tree

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
.PHONY: check fmt test validate eval gradient clean
1+
.PHONY: check fmt test validate eval gradient export-golden clean
22

33
INPUTS=--input action_features=2.0 --input user_features=3.0 --const 1.0
44

5-
check: fmt test validate eval gradient
5+
check: fmt test validate eval gradient export-golden
66

77
fmt:
88
cargo fmt --check
@@ -19,5 +19,8 @@ eval:
1919
gradient:
2020
cargo run -- check-gradient examples/risk-models.valid.json $(INPUTS) --epsilon 0.000001 --tolerance 0.00001 --out target/gatl-ad-lab/ad-check.json
2121

22+
export-golden:
23+
cargo run -- export-golden examples/risk-models.valid.json $(INPUTS) --epsilon 0.000001 --tolerance 0.00001 --out target/gatl-ad-lab/derivative-golden.json
24+
2225
clean:
2326
rm -rf target

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ v0.1 supports:
2323
- scalar primitives `const`, `add`, `sub`, `mul`, `div`, `exp`, `log`,
2424
`sigmoid`, `dot`, and `matmul`;
2525
- reverse pullbacks from `derivativeProgram.instructions`;
26-
- finite-difference gradient comparison.
26+
- finite-difference gradient comparison;
27+
- derivative golden fixture export for external formal AD proof backends.
2728

2829
`const` has no literal in current `gatl-core`, so this lab treats it as an
2930
external numeric assumption. The CLI default is `--const 1.0`, and reports
@@ -55,6 +56,13 @@ cargo run -- check-gradient /home/jisheng-yang/projects/gatl-core/target/gatl/ri
5556
--epsilon 0.000001 \
5657
--tolerance 0.00001 \
5758
--out target/gatl-ad-lab/ad-check.json
59+
cargo run -- export-golden /home/jisheng-yang/projects/gatl-core/target/gatl/risk-models.json \
60+
--input action_features=2.0 \
61+
--input user_features=3.0 \
62+
--const 1.0 \
63+
--epsilon 0.000001 \
64+
--tolerance 0.00001 \
65+
--out target/gatl-ad-lab/derivative-golden.json
5866
```
5967

6068
Local example:
@@ -76,3 +84,7 @@ This is a local numeric lab, not a production AD engine:
7684

7785
Future proof-oriented work should consume the generated AD check report or add
7886
a separate proof fixture format, not move numeric execution into `gatl-core`.
87+
`export-golden` emits that first proof-backend handoff fixture: it records the
88+
typed expression, derivative program, numeric inputs, expected primal value,
89+
expected reverse gradients, and finite-difference comparison metadata. It does
90+
not run Lean, Coq, Agda, F*, or any external proof engine.

docs/ad-check-report.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,20 @@ abs(reverse - finiteDifference) <= tolerance
3535
This report is not a formal proof. It is a local executable check that the
3636
current exported derivative instruction skeleton agrees with a numerical
3737
finite-difference baseline under declared assumptions.
38+
39+
## Derivative Golden Fixture
40+
41+
`gatl-ad-lab export-golden` emits:
42+
43+
```text
44+
format = gatl-ad-lab/v0.1-derivative-golden-fixture
45+
```
46+
47+
The fixture carries the selected typed numeric expression, derivative program,
48+
numeric input cases, expected primal value, expected reverse gradients, and the
49+
finite-difference comparison source. It is intended for an external formal AD
50+
proof backend to import as a deterministic fixture.
51+
52+
The command does not execute a proof assistant or certify correctness. Its
53+
`proofBackendBoundary` explicitly records that production proof checking is an
54+
external requirement.

docs/architecture.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ gatl-core risk-models.json
1414
-> reverse derivative instruction interpretation
1515
-> finite-difference comparison
1616
-> AD check report
17+
-> optional derivative golden fixture for formal proof backends
1718
```
1819

1920
## Trusted Boundary
@@ -24,10 +25,14 @@ The v0.1 trusted boundary is:
2425
- `gatl-core/v0.1-risk-model-analysis` validation;
2526
- scalar RPN node evaluation;
2627
- local pullback rules for smooth scalar primitives;
27-
- central finite-difference comparison.
28+
- central finite-difference comparison;
29+
- deterministic derivative golden fixture export.
2830

2931
The lab does not prove AD correctness. It provides an external executable
3032
sanity check and a report that future proof tooling can consume.
33+
`export-golden` turns the same check into a proof-backend fixture by preserving
34+
typedExpression, derivativeProgram, numeric assumptions, expected values, and
35+
comparison metadata. The formal proof backend remains external.
3136

3237
## Primitive Semantics
3338

@@ -51,6 +56,7 @@ Non-smooth or nondeterministic primitives remain outside this lab.
5156
- No production AD engine.
5257
- No TensorFlow, PyTorch, JAX, ONNX, or autograd integration.
5358
- No proof assistant integration.
59+
- No production formal proof backend.
5460
- No network access.
5561
- No secret handling.
5662
- No background worker.

docs/compatibility.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ risk-model artifacts.
1515
| --- | --- |
1616
| Evaluation report | `gatl-ad-lab/v0.1-evaluation` |
1717
| AD check report | `gatl-ad-lab/v0.1-ad-check-report` |
18+
| Derivative golden fixture | `gatl-ad-lab/v0.1-derivative-golden-fixture` |
1819

1920
## Release Gate
2021

2122
`make check` is the v0.1 release gate. It validates the risk-model fixture,
2223
evaluates the typed scalar expression, runs the exported reverse derivative
23-
instruction skeleton, and compares the result with finite differences.
24+
instruction skeleton, compares the result with finite differences, and exports
25+
a derivative golden fixture for external formal proof backends.
2426

2527
## Boundary
2628

src/lib.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use serde_json::{json, Value};
44

55
pub const LAB_VERSION: &str = "gatl-ad-lab/v0.1";
66
pub const REPORT_FORMAT: &str = "gatl-ad-lab/v0.1-ad-check-report";
7+
pub const DERIVATIVE_GOLDEN_FORMAT: &str = "gatl-ad-lab/v0.1-derivative-golden-fixture";
78

89
#[derive(Clone, Debug, PartialEq)]
910
pub struct LabError {
@@ -194,6 +195,46 @@ pub fn gradient_check_report(
194195
}))
195196
}
196197

198+
pub fn derivative_golden_fixture(
199+
root: &Value,
200+
options: &EvaluationOptions,
201+
) -> Result<Value, Vec<LabError>> {
202+
let model = select_model(root, options)?;
203+
let result = gradient_check_model(&model, options)?;
204+
let input_cases = options
205+
.inputs
206+
.iter()
207+
.map(|(name, value)| {
208+
json!({
209+
"name": name,
210+
"value": value
211+
})
212+
})
213+
.collect::<Vec<_>>();
214+
Ok(json!({
215+
"apiVersion": "gatl.dev/v0.1",
216+
"kind": "GATLDerivativeGoldenFixture",
217+
"version": LAB_VERSION,
218+
"format": DERIVATIVE_GOLDEN_FORMAT,
219+
"modelId": result.model_id,
220+
"assumptions": assumptions_json(options),
221+
"inputCases": input_cases,
222+
"expectedValue": result.value,
223+
"expectedReverseGradients": result.reverse_gradients,
224+
"comparisonSource": {
225+
"finiteDifferenceEpsilon": options.epsilon,
226+
"tolerance": options.tolerance,
227+
"maxAbsError": result.max_abs_error,
228+
"passed": result.passed
229+
},
230+
"proofBackendBoundary": {
231+
"status": "external-proof-backend-required",
232+
"consumes": "typedExpression + derivativeProgram + expectedReverseGradients",
233+
"executesProofBackend": false
234+
}
235+
}))
236+
}
237+
197238
fn gradient_check_model(
198239
model: &RiskModel,
199240
options: &EvaluationOptions,
@@ -885,6 +926,19 @@ mod tests {
885926
assert!((result.reverse_gradients["y"] - 2.0).abs() < 1e-9);
886927
}
887928

929+
#[test]
930+
fn exports_derivative_golden_fixture() {
931+
let fixture = derivative_golden_fixture(&report(), &options()).expect("golden");
932+
assert_eq!(
933+
fixture.pointer("/format"),
934+
Some(&json!(DERIVATIVE_GOLDEN_FORMAT))
935+
);
936+
assert_eq!(
937+
fixture.pointer("/expectedReverseGradients/x"),
938+
Some(&json!(3.0))
939+
);
940+
}
941+
888942
#[test]
889943
fn rejects_missing_input() {
890944
let mut options = options();

src/main.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use std::fs;
44
use std::path::PathBuf;
55

66
use gatl_ad_lab::{
7-
evaluate_report, gradient_check_report, validate_risk_models, EvaluationOptions, LabError,
7+
derivative_golden_fixture, evaluate_report, gradient_check_report, validate_risk_models,
8+
EvaluationOptions, LabError,
89
};
910
use serde_json::Value;
1011

@@ -21,13 +22,43 @@ fn run(args: Vec<String>) -> i32 {
2122
"validate" => validate_command(&args[1..]),
2223
"eval" => eval_command(&args[1..]),
2324
"check-gradient" => check_gradient_command(&args[1..]),
25+
"export-golden" => export_golden_command(&args[1..]),
2426
_ => {
2527
usage();
2628
2
2729
}
2830
}
2931
}
3032

33+
fn export_golden_command(args: &[String]) -> i32 {
34+
let (path, out, options) = match parse_report_options(args, true) {
35+
Ok(parsed) => parsed,
36+
Err(ParseOutcome::Usage) => {
37+
usage();
38+
return 2;
39+
}
40+
Err(ParseOutcome::Message(message)) => {
41+
eprintln!("error: {message}");
42+
return 2;
43+
}
44+
};
45+
let report = match read_json(&path) {
46+
Ok(value) => value,
47+
Err(error) => {
48+
eprintln!("error: {error}");
49+
return 1;
50+
}
51+
};
52+
let output = match derivative_golden_fixture(&report, &options) {
53+
Ok(value) => value,
54+
Err(errors) => {
55+
print_errors(&errors);
56+
return 1;
57+
}
58+
};
59+
write_or_print("derivative-golden", output, out)
60+
}
61+
3162
fn validate_command(args: &[String]) -> i32 {
3263
let [path] = args else {
3364
usage();
@@ -267,6 +298,7 @@ fn usage() {
267298
eprintln!(" gatl-ad-lab validate <risk-models.json>");
268299
eprintln!(" gatl-ad-lab eval <risk-models.json> [--model <id>] --input name=value [--input name=value ...] [--const <value>] [--out <path>]");
269300
eprintln!(" gatl-ad-lab check-gradient <risk-models.json> [--model <id>] --input name=value [--input name=value ...] [--const <value>] [--epsilon <value>] [--tolerance <value>] [--out <path>]");
301+
eprintln!(" gatl-ad-lab export-golden <risk-models.json> [--model <id>] --input name=value [--input name=value ...] [--const <value>] [--epsilon <value>] [--tolerance <value>] [--out <path>]");
270302
}
271303

272304
enum ParseOutcome {

0 commit comments

Comments
 (0)