diff --git a/pipeline.go b/pipeline.go index 8f8500e..04e6a6d 100644 --- a/pipeline.go +++ b/pipeline.go @@ -45,3 +45,31 @@ func Imprint(node Node, ctx *Context) reversal.GrammarImprint { tokens := tok.Tokenise(text) return reversal.NewImprint(tokens) } + +// CompareVariants runs the imprint pipeline on each responsive variant independently +// and returns pairwise similarity scores. Key format: "name1:name2". +func CompareVariants(r *Responsive, ctx *Context) map[string]float64 { + if ctx == nil { + ctx = NewContext() + } + + type named struct { + name string + imp reversal.GrammarImprint + } + + var imprints []named + for _, v := range r.variants { + imp := Imprint(v.layout, ctx) + imprints = append(imprints, named{name: v.name, imp: imp}) + } + + scores := make(map[string]float64) + for i := 0; i < len(imprints); i++ { + for j := i + 1; j < len(imprints); j++ { + key := imprints[i].name + ":" + imprints[j].name + scores[key] = imprints[i].imp.Similar(imprints[j].imp) + } + } + return scores +} diff --git a/pipeline_test.go b/pipeline_test.go index 09d68c7..b679bd8 100644 --- a/pipeline_test.go +++ b/pipeline_test.go @@ -99,3 +99,30 @@ func TestImprint_SimilarPages(t *testing.T) { t.Errorf("similar pages should score higher (%f) than different (%f)", sim, diffSim) } } + +func TestCompareVariants(t *testing.T) { + svc, _ := i18n.New() + i18n.SetDefault(svc) + ctx := NewContext() + + r := NewResponsive(). + Variant("desktop", NewLayout("HLCRF"). + H(El("h1", Text("Building project"))). + C(El("p", Text("Files deleted successfully"))). + F(El("small", Text("Completed")))). + Variant("mobile", NewLayout("HCF"). + H(El("h1", Text("Building project"))). + C(El("p", Text("Files deleted successfully"))). + F(El("small", Text("Completed")))) + + scores := CompareVariants(r, ctx) + + key := "desktop:mobile" + sim, ok := scores[key] + if !ok { + t.Fatalf("CompareVariants missing key %q, got keys: %v", key, scores) + } + if sim < 0.8 { + t.Errorf("same content in different variants should score >= 0.8, got %f", sim) + } +}