Improving all side of app
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
package synthetic
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// evalDef compiles a SignalDef and evaluates it against per-source values keyed
|
||||
// by source node id.
|
||||
func evalDef(t *testing.T, def SignalDef, srcVals map[string]float64) float64 {
|
||||
t.Helper()
|
||||
rg, err := compileGraph(def)
|
||||
if err != nil {
|
||||
t.Fatalf("compileGraph: %v", err)
|
||||
}
|
||||
out, err := rg.eval(srcVals)
|
||||
if err != nil {
|
||||
t.Fatalf("eval: %v", err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// TestGraphMultiInputDAG verifies that an intermediate op can take two
|
||||
// independently-wired sources — the capability the old linear pipeline lacked.
|
||||
func TestGraphMultiInputDAG(t *testing.T) {
|
||||
def := SignalDef{
|
||||
Name: "diff",
|
||||
Graph: &Graph{
|
||||
Output: "out",
|
||||
Nodes: []GraphNode{
|
||||
{ID: "a", Kind: "source", DS: "x", Signal: "left"},
|
||||
{ID: "b", Kind: "source", DS: "x", Signal: "right"},
|
||||
{ID: "sub", Kind: "op", Op: "subtract", Inputs: []string{"a", "b"}},
|
||||
{ID: "out", Kind: "output", Inputs: []string{"sub"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
got := evalDef(t, def, map[string]float64{"a": 10, "b": 3})
|
||||
if got != 7 {
|
||||
t.Errorf("subtract DAG: want 7, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGraphExprNamedInputs verifies expr nodes bind arbitrary named inputs in
|
||||
// wired order.
|
||||
func TestGraphExprNamedInputs(t *testing.T) {
|
||||
def := SignalDef{
|
||||
Name: "formula",
|
||||
Graph: &Graph{
|
||||
Output: "out",
|
||||
Nodes: []GraphNode{
|
||||
{ID: "a", Kind: "source", DS: "x", Signal: "p"},
|
||||
{ID: "b", Kind: "source", DS: "x", Signal: "q"},
|
||||
{ID: "e", Kind: "op", Op: "expr", Inputs: []string{"a", "b"},
|
||||
Params: map[string]any{"expr": "price * qty", "vars": []any{"price", "qty"}}},
|
||||
{ID: "out", Kind: "output", Inputs: []string{"e"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
got := evalDef(t, def, map[string]float64{"a": 4, "b": 2.5})
|
||||
if math.Abs(got-10) > 1e-9 {
|
||||
t.Errorf("expr named inputs: want 10, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGraphFanInToExpr exercises a non-trivial DAG: two ops feeding one expr.
|
||||
func TestGraphFanInToExpr(t *testing.T) {
|
||||
def := SignalDef{
|
||||
Name: "combo",
|
||||
Graph: &Graph{
|
||||
Output: "out",
|
||||
Nodes: []GraphNode{
|
||||
{ID: "a", Kind: "source", DS: "x", Signal: "p"},
|
||||
{ID: "b", Kind: "source", DS: "x", Signal: "q"},
|
||||
{ID: "g", Kind: "op", Op: "gain", Inputs: []string{"a"}, Params: map[string]any{"gain": 2.0}},
|
||||
{ID: "o", Kind: "op", Op: "offset", Inputs: []string{"b"}, Params: map[string]any{"offset": 1.0}},
|
||||
{ID: "e", Kind: "op", Op: "expr", Inputs: []string{"g", "o"}, Params: map[string]any{"expr": "a + b"}},
|
||||
{ID: "out", Kind: "output", Inputs: []string{"e"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
// g = 5*2 = 10 ; o = 4+1 = 5 ; a+b = 15
|
||||
got := evalDef(t, def, map[string]float64{"a": 5, "b": 4})
|
||||
if math.Abs(got-15) > 1e-9 {
|
||||
t.Errorf("fan-in DAG: want 15, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGraphLegacyConversion verifies the linear Inputs+Pipeline form still
|
||||
// evaluates correctly via the graph runtime.
|
||||
func TestGraphLegacyConversion(t *testing.T) {
|
||||
def := SignalDef{
|
||||
Name: "legacy",
|
||||
DS: "x",
|
||||
Signal: "p",
|
||||
Pipeline: []NodeDef{{Type: "gain", Params: map[string]any{"gain": 3.0}}},
|
||||
}
|
||||
rg, err := compileGraph(def)
|
||||
if err != nil {
|
||||
t.Fatalf("compileGraph: %v", err)
|
||||
}
|
||||
if len(rg.sources) != 1 {
|
||||
t.Fatalf("want 1 source, got %d", len(rg.sources))
|
||||
}
|
||||
got, err := rg.eval(map[string]float64{rg.sources[0].id: 4})
|
||||
if err != nil {
|
||||
t.Fatalf("eval: %v", err)
|
||||
}
|
||||
if got != 12 {
|
||||
t.Errorf("legacy gain: want 12, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGraphCycleRejected ensures a cyclic graph is refused at compile time.
|
||||
func TestGraphCycleRejected(t *testing.T) {
|
||||
def := SignalDef{
|
||||
Name: "cyclic",
|
||||
Graph: &Graph{
|
||||
Output: "out",
|
||||
Nodes: []GraphNode{
|
||||
{ID: "a", Kind: "op", Op: "gain", Inputs: []string{"b"}, Params: map[string]any{"gain": 1.0}},
|
||||
{ID: "b", Kind: "op", Op: "gain", Inputs: []string{"a"}, Params: map[string]any{"gain": 1.0}},
|
||||
{ID: "out", Kind: "output", Inputs: []string{"a"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := compileGraph(def); err == nil {
|
||||
t.Error("expected cycle to be rejected")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user