1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
use std::fmt::Debug;
/// Application-owned full-recompute oracle for a Trellis graph wrapper.
pub trait FullRecomputeOracle<G> {
/// Canonical application inputs used by full recompute.
type CanonicalInputs;
/// Comparable state observed from full recompute and incremental graph state.
type ExpectedState: Clone + Debug + PartialEq;
/// Computes expected state from canonical application truth.
fn recompute(inputs: &Self::CanonicalInputs) -> Self::ExpectedState;
/// Observes the equivalent state from the incremental graph or wrapper.
fn observe_incremental(graph: &G, inputs: &Self::CanonicalInputs) -> Self::ExpectedState;
}
/// Successful oracle comparison.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OracleCheck<S> {
/// State produced by full recompute.
pub expected: S,
/// State observed from the incremental graph.
pub actual: S,
}
/// Full-recompute oracle mismatch.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OracleMismatch<S> {
/// State produced by full recompute.
pub expected: S,
/// State observed from the incremental graph.
pub actual: S,
}
/// Asserts that incremental observation equals application full recompute.
pub fn assert_incremental_equals_full<G, O>(
graph: &G,
inputs: &O::CanonicalInputs,
) -> Result<OracleCheck<O::ExpectedState>, OracleMismatch<O::ExpectedState>>
where
O: FullRecomputeOracle<G>,
{
let expected = O::recompute(inputs);
let actual = O::observe_incremental(graph, inputs);
if expected == actual {
Ok(OracleCheck { expected, actual })
} else {
Err(OracleMismatch { expected, actual })
}
}