github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/solver/search.go (about) 1 package solver 2 3 import ( 4 "context" 5 6 "github.com/go-air/gini/inter" 7 "github.com/go-air/gini/z" 8 ) 9 10 type choice struct { 11 prev, next *choice 12 index int // index of next unguessed literal 13 candidates []z.Lit 14 } 15 16 type guess struct { 17 m z.Lit // if z.LitNull, this choice was satisfied by a previous assumption 18 index int // index of guessed literal in candidates 19 children int // number of choices introduced by making this guess 20 candidates []z.Lit 21 } 22 23 type search struct { 24 s inter.S 25 lits *litMapping 26 assumptions map[z.Lit]struct{} // set of assumed lits - duplicates guess stack - for fast lookup 27 guesses []guess // stack of assumed guesses 28 headChoice, tailChoice *choice // deque of unmade choices 29 tracer Tracer 30 result int 31 buffer []z.Lit 32 } 33 34 func (h *search) PushGuess() { 35 c := h.PopChoiceFront() 36 g := guess{ 37 m: z.LitNull, 38 index: c.index, 39 candidates: c.candidates, 40 } 41 if g.index < len(g.candidates) { 42 g.m = g.candidates[g.index] 43 } 44 45 // Check whether or not this choice can be satisfied by an 46 // existing assumption. 47 for _, m := range g.candidates { 48 if _, ok := h.assumptions[m]; ok { 49 g.m = z.LitNull 50 break 51 } 52 } 53 54 h.guesses = append(h.guesses, g) 55 if g.m == z.LitNull { 56 return 57 } 58 59 variable := h.lits.VariableOf(g.m) 60 for _, constraint := range variable.Constraints() { 61 var ms []z.Lit 62 for _, dependency := range constraint.order() { 63 ms = append(ms, h.lits.LitOf(dependency)) 64 } 65 if len(ms) > 0 { 66 h.guesses[len(h.guesses)-1].children++ 67 h.PushChoiceBack(choice{candidates: ms}) 68 } 69 } 70 71 if h.assumptions == nil { 72 h.assumptions = make(map[z.Lit]struct{}) 73 } 74 h.assumptions[g.m] = struct{}{} 75 h.s.Assume(g.m) 76 h.result, h.buffer = h.s.Test(h.buffer) 77 } 78 79 func (h *search) PopGuess() { 80 g := h.guesses[len(h.guesses)-1] 81 h.guesses = h.guesses[:len(h.guesses)-1] 82 if g.m != z.LitNull { 83 delete(h.assumptions, g.m) 84 h.result = h.s.Untest() 85 } 86 for g.children > 0 { 87 g.children-- 88 h.PopChoiceBack() 89 } 90 c := choice{ 91 index: g.index, 92 candidates: g.candidates, 93 } 94 if g.m != z.LitNull { 95 c.index++ 96 } 97 h.PushChoiceFront(c) 98 } 99 100 func (h *search) PushChoiceFront(c choice) { 101 if h.headChoice == nil { 102 h.headChoice = &c 103 h.tailChoice = &c 104 return 105 } 106 h.headChoice.prev = &c 107 c.next = h.headChoice 108 h.headChoice = &c 109 } 110 111 func (h *search) PopChoiceFront() choice { 112 c := h.headChoice 113 if c.next != nil { 114 c.next.prev = nil 115 } else { 116 h.tailChoice = nil 117 } 118 h.headChoice = c.next 119 return *c 120 } 121 122 func (h *search) PushChoiceBack(c choice) { 123 if h.tailChoice == nil { 124 h.headChoice = &c 125 h.tailChoice = &c 126 return 127 } 128 h.tailChoice.next = &c 129 c.prev = h.tailChoice 130 h.tailChoice = &c 131 } 132 133 func (h *search) PopChoiceBack() choice { 134 c := h.tailChoice 135 if c.prev != nil { 136 c.prev.next = nil 137 } else { 138 h.headChoice = nil 139 } 140 h.tailChoice = c.prev 141 return *c 142 } 143 144 func (h *search) Result() int { 145 return h.result 146 } 147 148 func (h *search) Lits() []z.Lit { 149 result := make([]z.Lit, 0, len(h.guesses)) 150 for _, g := range h.guesses { 151 if g.m != z.LitNull { 152 result = append(result, g.m) 153 } 154 } 155 return result 156 } 157 158 func (h *search) Do(ctx context.Context, anchors []z.Lit) (int, []z.Lit, map[z.Lit]struct{}) { 159 for _, m := range anchors { 160 h.PushChoiceBack(choice{candidates: []z.Lit{m}}) 161 } 162 163 for { 164 // Need to have a definitive result once all choices 165 // have been made to decide whether to end or 166 // backtrack. 167 if h.headChoice == nil && h.result == unknown { 168 h.result = h.s.Solve() 169 } 170 171 // Backtrack if possible, otherwise end. 172 if h.result == unsatisfiable { 173 h.tracer.Trace(h) 174 if len(h.guesses) == 0 { 175 break 176 } 177 h.PopGuess() 178 continue 179 } 180 181 // Satisfiable and no decisions left! 182 if h.headChoice == nil { 183 break 184 } 185 186 // Possibly SAT, keep guessing. 187 h.PushGuess() 188 } 189 190 lits := h.Lits() 191 set := make(map[z.Lit]struct{}, len(lits)) 192 for _, m := range lits { 193 set[m] = struct{}{} 194 } 195 result := h.Result() 196 197 // Go back to the initial test scope. 198 for len(h.guesses) > 0 { 199 h.PopGuess() 200 } 201 202 return result, lits, set 203 } 204 205 func (h *search) Variables() []Variable { 206 result := make([]Variable, 0, len(h.guesses)) 207 for _, g := range h.guesses { 208 if g.m != z.LitNull { 209 result = append(result, h.lits.VariableOf(g.candidates[g.index])) 210 } 211 } 212 return result 213 } 214 215 func (h *search) Conflicts() []AppliedConstraint { 216 return h.lits.Conflicts(h.s) 217 }