@@ -3,40 +3,16 @@ package solver
33import (
44 "fmt"
55 "strings"
6- )
7-
8- // constrainer is a reusable accumulator of constraint clause terms.
9- type constrainer struct {
10- pos []Identifier
11- neg []Identifier
12- }
13-
14- func (x * constrainer ) Add (id Identifier ) {
15- x .pos = append (x .pos , id )
16- }
17-
18- func (x * constrainer ) AddNot (id Identifier ) {
19- x .neg = append (x .neg , id )
20- }
216
22- // Reset clears the receiver's internal state so that it can be
23- // reused.
24- func (x * constrainer ) Reset () {
25- x .pos = x .pos [:0 ]
26- x .neg = x .neg [:0 ]
27- }
28-
29- // Empty returns true if and only if the receiver has accumulated no
30- // positive or negative terms.
31- func (x * constrainer ) Empty () bool {
32- return len (x .pos ) == 0 && len (x .neg ) == 0
33- }
7+ "github.com/irifrance/gini/logic"
8+ "github.com/irifrance/gini/z"
9+ )
3410
3511// Constraint implementations limit the circumstances under which a
3612// particular Installable can appear in a solution.
3713type Constraint interface {
3814 String (subject Identifier ) string
39- apply (x * constrainer , subject Identifier )
15+ apply (c * logic. C , lm * litMapping , subject Identifier ) z. Lit
4016 order () []Identifier
4117}
4218
@@ -49,7 +25,8 @@ func (zeroConstraint) String(subject Identifier) string {
4925 return ""
5026}
5127
52- func (zeroConstraint ) apply (x * constrainer , subject Identifier ) {
28+ func (zeroConstraint ) apply (c * logic.C , lm * litMapping , subject Identifier ) z.Lit {
29+ return z .LitNull
5330}
5431
5532func (zeroConstraint ) order () []Identifier {
@@ -71,15 +48,15 @@ func (a AppliedConstraint) String() string {
7148
7249type mandatory struct {}
7350
74- func (c mandatory ) String (subject Identifier ) string {
51+ func (constraint mandatory ) String (subject Identifier ) string {
7552 return fmt .Sprintf ("%s is mandatory" , subject )
7653}
7754
78- func (c mandatory ) apply (x * constrainer , subject Identifier ) {
79- x . Add (subject )
55+ func (constraint mandatory ) apply (_ * logic. C , lm * litMapping , subject Identifier ) z. Lit {
56+ return lm . LitOf (subject )
8057}
8158
82- func (c mandatory ) order () []Identifier {
59+ func (constraint mandatory ) order () []Identifier {
8360 return nil
8461}
8562
@@ -91,15 +68,15 @@ func Mandatory() Constraint {
9168
9269type prohibited struct {}
9370
94- func (c prohibited ) String (subject Identifier ) string {
71+ func (constraint prohibited ) String (subject Identifier ) string {
9572 return fmt .Sprintf ("%s is prohibited" , subject )
9673}
9774
98- func (c prohibited ) apply (x * constrainer , subject Identifier ) {
99- x . AddNot (subject )
75+ func (constraint prohibited ) apply (c * logic. C , lm * litMapping , subject Identifier ) z. Lit {
76+ return lm . LitOf (subject ). Not ( )
10077}
10178
102- func (c prohibited ) order () []Identifier {
79+ func (constraint prohibited ) order () []Identifier {
10380 return nil
10481}
10582
@@ -113,26 +90,24 @@ func Prohibited() Constraint {
11390
11491type dependency []Identifier
11592
116- func (c dependency ) String (subject Identifier ) string {
117- s := make ([]string , len (c ))
118- for i , each := range c {
93+ func (constraint dependency ) String (subject Identifier ) string {
94+ s := make ([]string , len (constraint ))
95+ for i , each := range constraint {
11996 s [i ] = string (each )
12097 }
12198 return fmt .Sprintf ("%s requires at least one of %s" , subject , strings .Join (s , ", " ))
12299}
123100
124- func (c dependency ) apply (x * constrainer , subject Identifier ) {
125- if len (c ) == 0 {
126- return
127- }
128- x .AddNot (subject )
129- for _ , each := range c {
130- x .Add (each )
101+ func (constraint dependency ) apply (c * logic.C , lm * litMapping , subject Identifier ) z.Lit {
102+ m := lm .LitOf (subject ).Not ()
103+ for _ , each := range constraint {
104+ m = c .Or (m , lm .LitOf (each ))
131105 }
106+ return m
132107}
133108
134- func (c dependency ) order () []Identifier {
135- return [] Identifier ( c )
109+ func (constraint dependency ) order () []Identifier {
110+ return constraint
136111}
137112
138113// Dependency returns a Constraint that will only permit solutions
@@ -146,16 +121,15 @@ func Dependency(ids ...Identifier) Constraint {
146121
147122type conflict Identifier
148123
149- func (c conflict ) String (subject Identifier ) string {
150- return fmt .Sprintf ("%s conflicts with %s" , subject , c )
124+ func (constraint conflict ) String (subject Identifier ) string {
125+ return fmt .Sprintf ("%s conflicts with %s" , subject , constraint )
151126}
152127
153- func (c conflict ) apply (x * constrainer , subject Identifier ) {
154- x .AddNot (subject )
155- x .AddNot (Identifier (c ))
128+ func (constraint conflict ) apply (c * logic.C , lm * litMapping , subject Identifier ) z.Lit {
129+ return c .Or (lm .LitOf (subject ).Not (), lm .LitOf (Identifier (constraint )).Not ())
156130}
157131
158- func (c conflict ) order () []Identifier {
132+ func (constraint conflict ) order () []Identifier {
159133 return nil
160134}
161135
@@ -165,3 +139,38 @@ func (c conflict) order() []Identifier {
165139func Conflict (id Identifier ) Constraint {
166140 return conflict (id )
167141}
142+
143+ type leq struct {
144+ ids []Identifier
145+ n int
146+ }
147+
148+ func (constraint leq ) String (subject Identifier ) string {
149+ s := make ([]string , len (constraint .ids ))
150+ for i , each := range constraint .ids {
151+ s [i ] = string (each )
152+ }
153+ return fmt .Sprintf ("%s permits at most %d of %s" , subject , constraint .n , strings .Join (s , ", " ))
154+ }
155+
156+ func (constraint leq ) apply (c * logic.C , lm * litMapping , subject Identifier ) z.Lit {
157+ ms := make ([]z.Lit , len (constraint .ids ))
158+ for i , each := range constraint .ids {
159+ ms [i ] = lm .LitOf (each )
160+ }
161+ return c .CardSort (ms ).Leq (constraint .n )
162+ }
163+
164+ func (constraint leq ) order () []Identifier {
165+ return nil
166+ }
167+
168+ // AtMost returns a Constraint that forbids solutions that contain
169+ // more than n of the Installables identified by the given
170+ // Identifiers.
171+ func AtMost (n int , ids ... Identifier ) Constraint {
172+ return leq {
173+ ids : ids ,
174+ n : n ,
175+ }
176+ }
0 commit comments