--- /dev/null
+// Copyright (C) The Lightning Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+package lightning
+
+import (
+ "golang.org/x/exp/rand"
+ "gonum.org/v1/gonum/stat/distuv"
+)
+
+var chisquared = distuv.ChiSquared{K: 1, Src: rand.NewSource(rand.Uint64())}
+
+func pvalue(a, b []bool) float64 {
+ // !b b
+ // !a tab[0] tab[1]
+ // a tab[2] tab[3]
+ tab := make([]int, 4)
+ for ai, aval := range []bool{false, true} {
+ for bi, bval := range []bool{false, true} {
+ obs := 0
+ for i := range a {
+ if a[i] == aval && b[i] == bval {
+ obs++
+ }
+ }
+ tab[ai*2+bi] = obs
+ }
+ }
+ var sum float64
+ for ai := 0; ai < 2; ai++ {
+ for bi := 0; bi < 2; bi++ {
+ rowtotal := tab[ai*2] + tab[ai*2+1]
+ coltotal := tab[bi] + tab[2+bi]
+ exp := float64(rowtotal) * float64(coltotal) / float64(len(a))
+ obs := tab[ai*2+bi]
+ d := float64(obs) - exp
+ sum += (d * d) / exp
+ }
+ }
+ return 1 - chisquared.CDF(sum)
+}
--- /dev/null
+// Copyright (C) The Lightning Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+package lightning
+
+import (
+ "fmt"
+
+ "gopkg.in/check.v1"
+)
+
+type pvalueSuite struct{}
+
+var _ = check.Suite(&pvalueSuite{})
+
+func (s *pvalueSuite) TestPvalue(c *check.C) {
+ a := make([]bool, 54)
+ b := make([]bool, 54)
+ for i := 0; i < 25; i++ {
+ a[i] = true
+ b[i] = true
+ }
+ for i := 25; i < 31; i++ {
+ a[i] = true
+ }
+ for i := 31; i < 39; i++ {
+ b[i] = true
+ }
+ c.Check(fmt.Sprintf("%.7f", pvalue(a, b)), check.Equals, "0.0006297")
+ for i := range a {
+ a[i] = !a[i]
+ }
+ c.Check(fmt.Sprintf("%.7f", pvalue(a, b)), check.Equals, "0.0006297")
+}
github.com/sirupsen/logrus v1.6.0
github.com/spaolacci/murmur3 v1.1.0 // indirect
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
+ golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 // indirect
gonum.org/v1/gonum v0.8.1