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
|
package query
import (
"slices"
)
type Optimizer struct{}
func StatementCmp(a Statement, b Statement) int {
catDiff := int(a.Category - b.Category)
opDiff := int(a.Operator - b.Operator)
negatedDiff := 0
if a.Negated && !b.Negated {
negatedDiff = 1
} else if !a.Negated && b.Negated {
negatedDiff = -1
}
return catDiff*100_000 + opDiff*100 + negatedDiff*10 + a.Value.Compare(b.Value)
}
func StatementEq(a Statement, b Statement) bool {
a.Simplify()
b.Simplify()
return a.Category == b.Category && a.Operator == b.Operator && a.Negated == b.Negated && a.Value.Compare(b.Value) == 0
}
// Merge child clauses with their parents when applicable
func (o Optimizer) Flatten(root *Clause) {
stack := make([]*Clause, 0, len(root.Clauses))
stack = append(stack, root)
for len(stack) != 0 {
top := len(stack) - 1
node := stack[top]
stack = stack[:top]
hasMerged := false
// merge if only child clause
if len(node.Statements) == 0 && len(node.Clauses) == 1 {
child := node.Clauses[0]
node.Operator = child.Operator
node.Statements = child.Statements
node.Clauses = child.Clauses
}
// cannot be "modernized", node.Clauses is modified in loop
for i := 0; i < len(node.Clauses); i++ {
child := node.Clauses[i]
// merge because of commutativity
if node.Operator == child.Operator {
hasMerged = true
node.Statements = append(node.Statements, child.Statements...)
node.Clauses = append(node.Clauses, child.Clauses...)
} else {
stack = append(stack, child)
}
}
if hasMerged {
numChildren := len(stack) - top
if numChildren > 0 {
node.Clauses = slices.Grow(node.Clauses, numChildren)
node.Clauses = node.Clauses[:numChildren]
copy(node.Clauses, stack[top:top+numChildren])
} else {
node.Clauses = nil
}
}
}
}
func (o Optimizer) Compact(c *Clause) {
for clause := range c.DFS() {
clause.Statements = slices.CompactFunc(c.Statements, StatementEq)
}
}
// if any claus is a strict equality/inequality noop all fuzzy operations
func strictEquality(clause Clause) error {
isStrict := slices.ContainsFunc(clause.Statements, func(stmt Statement) bool {
if stmt.Operator == OP_EQ || stmt.Operator == OP_NE {
return true
}
return false
})
if isStrict {
for i := range clause.Statements {
stmt := clause.Statements[i]
if stmt.Operator != OP_EQ && stmt.Operator != OP_NE {
clause.Statements[i] = Statement{}
}
}
}
return nil
}
|