Repository navigation
Expand file tree
/
Copy pathserialize_test.go
More file actions
129 lines (117 loc) · 3.22 KB
/
Copy pathserialize_test.go
File metadata and controls
129 lines (117 loc) · 3.22 KB
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package randomforest
import (
"encoding/json"
"math"
"math/rand"
"testing"
)
func assertEqualFloat64(f1, f2, precision float64) bool {
return math.Abs(f1-f2) < precision
}
func dfsBranchVisit(branch *Branch) []int {
valuesPath := make([]int, 0, 5)
valuesPath = append(valuesPath, int(branch.Value))
if branch.Branch0 != nil {
valuesPath = append(valuesPath, dfsBranchVisit(branch.Branch0)...)
}
if branch.Branch1 != nil {
valuesPath = append(valuesPath, dfsBranchVisit(branch.Branch1)...)
}
return valuesPath
}
// TestStructuralConsistency tests whether serialization's flattening
// of Forest trees (a list of nodes along with IDs of their children)
// preserves structure.
func TestStructuralConsistency(t *testing.T) {
fr := &Forest{Trees: make([]Tree, 1)}
fr.Trees[0] = Tree{
Root: Branch{
Value: 1,
Branch0: &Branch{
Value: 2,
Branch0: &Branch{
Value: 3,
Branch0: &Branch{
Value: 4,
Branch0: &Branch{
Value: 5,
},
},
},
Branch1: &Branch{
Value: 6,
},
},
Branch1: &Branch{
Value: 7,
Branch0: &Branch{
Value: 8,
Branch0: &Branch{
Value: 9,
},
Branch1: &Branch{
Value: 10,
},
},
Branch1: &Branch{
Value: 11,
},
},
},
}
pathExpected := dfsBranchVisit(&fr.Trees[0].Root)
jsonData, err := json.Marshal(fr)
if err != nil {
t.Error("failed to serialize a Forest instance: %w", err)
}
var fr2 Forest
if err := json.Unmarshal(jsonData, &fr2); err != nil {
t.Error("failed to deserialize a Forest instance: %w", err)
}
pathTest := dfsBranchVisit(&fr2.Trees[0].Root)
if len(pathExpected) != len(pathTest) {
t.Error("different number of nodes in the original and deserialized Forest trees")
}
for i := 0; i < len(pathExpected); i++ {
if pathExpected[i] != pathTest[i] {
t.Error("different tree structure between the original and deserialized Forest trees")
}
}
}
// TestJSONSerialization ensures that the original Forest and its serialized
// and deserialized form produce exact results.
func TestJSONSerialization(t *testing.T) {
xData := [][]float64{}
yData := []int{}
for i := 0; i < 1000; i++ {
x := []float64{rand.Float64(), rand.Float64(), rand.Float64(), rand.Float64()}
y := int(x[0] + x[1] + x[2] + x[3])
xData = append(xData, x)
yData = append(yData, y)
}
forest := Forest{}
forestData := ForestData{X: xData, Class: yData}
forest.Data = forestData
forest.Train(500)
testInput := []float64{0.1, 0.1, 0.1, 0.1}
voteExpected := forest.Vote(testInput)
data, err := json.Marshal(forest)
if err != nil {
t.Error("failed to serialize the forest")
}
var forestFromJSON Forest
if err := json.Unmarshal(data, &forestFromJSON); err != nil {
t.Error("failed to read a forest from JSON data")
}
forestFromJSON.Data = forestData
voteTest := forestFromJSON.Vote(testInput)
if len(voteExpected) != len(voteTest) {
t.Error("vote slice has not the expected size")
}
for i := 0; i < len(voteExpected); i++ {
// note: the precision below must match the JSONNumbersPrecisionDecPlaces package variable
if !assertEqualFloat64(voteExpected[i], voteTest[i], 0.00001) {
t.Errorf("vote element %d mismatch (expected %.5f, got %.5f)", i, voteExpected[i], voteTest[i])
}
}
}