github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/solver/lit_mapping.go (about) 1 package solver 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/go-air/gini/inter" 8 "github.com/go-air/gini/logic" 9 "github.com/go-air/gini/z" 10 ) 11 12 type DuplicateIdentifier Identifier 13 14 func (e DuplicateIdentifier) Error() string { 15 return fmt.Sprintf("duplicate identifier %q in input", Identifier(e)) 16 } 17 18 type inconsistentLitMapping []error 19 20 func (inconsistentLitMapping) Error() string { 21 return "internal solver failure" 22 } 23 24 // litMapping performs translation between the input and output types of 25 // Solve (Constraints, Variables, etc.) and the variables that 26 // appear in the SAT formula. 27 type litMapping struct { 28 inorder []Variable 29 variables map[z.Lit]Variable 30 lits map[Identifier]z.Lit 31 constraints map[z.Lit]AppliedConstraint 32 c *logic.C 33 errs inconsistentLitMapping 34 } 35 36 // newLitMapping returns a new litMapping with its state initialized based on 37 // the provided slice of Variables. This includes construction of 38 // the translation tables between Variables/Constraints and the 39 // inputs to the underlying solver. 40 func newLitMapping(variables []Variable) (*litMapping, error) { 41 d := litMapping{ 42 inorder: variables, 43 variables: make(map[z.Lit]Variable, len(variables)), 44 lits: make(map[Identifier]z.Lit, len(variables)), 45 constraints: make(map[z.Lit]AppliedConstraint), 46 c: logic.NewCCap(len(variables)), 47 } 48 49 // First pass to assign lits: 50 for _, variable := range variables { 51 im := d.c.Lit() 52 if _, ok := d.lits[variable.Identifier()]; ok { 53 return nil, DuplicateIdentifier(variable.Identifier()) 54 } 55 d.lits[variable.Identifier()] = im 56 d.variables[im] = variable 57 } 58 59 for _, variable := range variables { 60 for _, constraint := range variable.Constraints() { 61 m := constraint.apply(d.c, &d, variable.Identifier()) 62 if m == z.LitNull { 63 // This constraint doesn't have a 64 // useful representation in the SAT 65 // inputs. 66 continue 67 } 68 69 d.constraints[m] = AppliedConstraint{ 70 Variable: variable, 71 Constraint: constraint, 72 } 73 } 74 } 75 76 return &d, nil 77 } 78 79 // LitOf returns the positive literal corresponding to the Variable 80 // with the given Identifier. 81 func (d *litMapping) LitOf(id Identifier) z.Lit { 82 m, ok := d.lits[id] 83 if ok { 84 return m 85 } 86 d.errs = append(d.errs, fmt.Errorf("variable %q referenced but not provided", id)) 87 return z.LitNull 88 } 89 90 // VariableOf returns the Variable corresponding to the provided 91 // literal, or a zeroVariable if no such Variable exists. 92 func (d *litMapping) VariableOf(m z.Lit) Variable { 93 i, ok := d.variables[m] 94 if ok { 95 return i 96 } 97 d.errs = append(d.errs, fmt.Errorf("no variable corresponding to %s", m)) 98 return zeroVariable{} 99 } 100 101 // ConstraintOf returns the constraint application corresponding to 102 // the provided literal, or a zeroConstraint if no such constraint 103 // exists. 104 func (d *litMapping) ConstraintOf(m z.Lit) AppliedConstraint { 105 if a, ok := d.constraints[m]; ok { 106 return a 107 } 108 d.errs = append(d.errs, fmt.Errorf("no constraint corresponding to %s", m)) 109 return AppliedConstraint{ 110 Variable: zeroVariable{}, 111 Constraint: zeroConstraint{}, 112 } 113 } 114 115 // Error returns a single error value that is an aggregation of all 116 // errors encountered during a litMapping's lifetime, or nil if there have 117 // been no errors. A non-nil return value likely indicates a problem 118 // with the solver or constraint implementations. 119 func (d *litMapping) Error() error { 120 if len(d.errs) == 0 { 121 return nil 122 } 123 s := make([]string, len(d.errs)) 124 for i, err := range d.errs { 125 s[i] = err.Error() 126 } 127 return fmt.Errorf("%d errors encountered: %s", len(s), strings.Join(s, ", ")) 128 } 129 130 // AddConstraints adds the current constraints encoded in the embedded circuit to the 131 // solver g 132 func (d *litMapping) AddConstraints(g inter.S) { 133 d.c.ToCnf(g) 134 } 135 136 func (d *litMapping) AssumeConstraints(s inter.S) { 137 for m := range d.constraints { 138 s.Assume(m) 139 } 140 } 141 142 // CardinalityConstrainer constructs a sorting network to provide 143 // cardinality constraints over the provided slice of literals. Any 144 // new clauses and variables are translated to CNF and taught to the 145 // given inter.Adder, so this function will panic if it is in a test 146 // context. 147 func (d *litMapping) CardinalityConstrainer(g inter.Adder, ms []z.Lit) *logic.CardSort { 148 clen := d.c.Len() 149 cs := d.c.CardSort(ms) 150 marks := make([]int8, clen, d.c.Len()) 151 for i := range marks { 152 marks[i] = 1 153 } 154 for w := 0; w <= cs.N(); w++ { 155 marks, _ = d.c.CnfSince(g, marks, cs.Leq(w)) 156 } 157 return cs 158 } 159 160 // AnchorIdentifiers returns a slice containing the Identifiers of 161 // every Variable with at least one "anchor" constraint, in the 162 // order they appear in the input. 163 func (d *litMapping) AnchorIdentifiers() []Identifier { 164 var ids []Identifier 165 for _, variable := range d.inorder { 166 for _, constraint := range variable.Constraints() { 167 if constraint.anchor() { 168 ids = append(ids, variable.Identifier()) 169 break 170 } 171 } 172 } 173 return ids 174 } 175 176 func (d *litMapping) Variables(g inter.S) []Variable { 177 var result []Variable 178 for _, i := range d.inorder { 179 if g.Value(d.LitOf(i.Identifier())) { 180 result = append(result, i) 181 } 182 } 183 return result 184 } 185 186 func (d *litMapping) Lits(dst []z.Lit) []z.Lit { 187 if cap(dst) < len(d.inorder) { 188 dst = make([]z.Lit, 0, len(d.inorder)) 189 } 190 dst = dst[:0] 191 for _, i := range d.inorder { 192 m := d.LitOf(i.Identifier()) 193 dst = append(dst, m) 194 } 195 return dst 196 } 197 198 func (d *litMapping) Conflicts(g inter.Assumable) []AppliedConstraint { 199 whys := g.Why(nil) 200 as := make([]AppliedConstraint, 0, len(whys)) 201 for _, why := range whys { 202 if a, ok := d.constraints[why]; ok { 203 as = append(as, a) 204 } 205 } 206 return as 207 }