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 package specexpr
64
65 import (
66 "cmp"
67 "container/heap"
68 "fmt"
69 "io"
70 "iter"
71 "log"
72 "maps"
73 "slices"
74 "strings"
75 )
76
77
78
79
80
81
82
83
84
85
86
87 type Solver struct {
88 vars map[Variable][]any
89 asserts []Expr
90 tracer *tracer
91 }
92
93
94 func (s *Solver) SetTrace(w io.Writer) {
95 if w == nil {
96 s.tracer = nil
97 } else {
98 s.tracer = &tracer{w: w}
99 }
100 }
101
102
103
104
105 func (s *Solver) Declare(v Variable, domain []any) {
106 if s.vars == nil {
107 s.vars = make(map[Variable][]any)
108 }
109 if _, ok := s.vars[v]; ok {
110 panic(v + " redeclared")
111 }
112 for i, d := range domain {
113 if d, ok := d.(int); ok {
114 domain[i] = Int(d)
115 }
116 }
117 s.vars[v] = domain
118 }
119
120
121 func (s *Solver) Assign(v Variable, val Expr) Variable {
122 s.Assert(&BinExpr{Op: OpEqual, X: v, Y: val})
123 return v
124 }
125
126
127 func (s *Solver) Assert(cond Expr) {
128 s.asserts = append(s.asserts, cond)
129 }
130
131 func (s *Solver) Fprint(w io.Writer) {
132 for _, v := range slices.Sorted(maps.Keys(s.vars)) {
133 fmt.Fprintf(w, "%s in %v\n", v, s.vars[v])
134 }
135 for _, expr := range s.asserts {
136 fmt.Fprintf(w, "%s\n", expr)
137 }
138 }
139
140
141 type Bindings struct {
142 varNames map[Variable]int
143 vals []any
144 }
145
146
147 func (b *Bindings) Get(v Variable) any {
148 vid, ok := b.varNames[v]
149 if !ok || vid >= len(b.vals) {
150 return nil
151 }
152 return b.vals[vid]
153 }
154
155
156 func (b *Bindings) All() iter.Seq2[Variable, any] {
157 return func(yield func(Variable, any) bool) {
158 for _, varName := range slices.Sorted(maps.Keys(b.varNames)) {
159 vid := b.varNames[varName]
160 if vid < len(b.vals) && !yield(varName, b.vals[vid]) {
161 return
162 }
163 }
164 }
165 }
166
167 func (b *Bindings) String() string {
168 var buf strings.Builder
169 buf.WriteByte('{')
170 for v, val := range b.All() {
171 if buf.Len() > 1 {
172 buf.WriteByte(' ')
173 }
174 fmt.Fprintf(&buf, "%s=%v", v, val)
175 }
176 buf.WriteByte('}')
177 return buf.String()
178 }
179
180
181 func (s *Solver) Solve() iter.Seq2[*Bindings, error] {
182 steps, err := s.topoSort()
183 if err != nil {
184 return func(yield func(*Bindings, error) bool) {
185 yield(nil, err)
186 }
187 }
188
189
190 varIDs := make(map[Variable]int)
191 for _, step := range steps {
192 if step.kind == solverStepCheck {
193 continue
194 }
195 if _, ok := varIDs[step.bind]; ok {
196 panic(fmt.Sprintf("variable %s resolved multiple times by solver sequence", step.bind))
197 }
198 varIDs[step.bind] = len(varIDs)
199 }
200
201
202
203 errors := make(map[string]bool)
204 addErr := func(err error) {
205 if errors != nil {
206 errors[err.Error()] = true
207 }
208 }
209
210
211 b := Bindings{
212 varNames: varIDs,
213 vals: make([]any, 0, len(varIDs)),
214 }
215 pop := func() {
216 b.vals = b.vals[:len(b.vals)-1]
217 }
218 var visit func(steps []*solverStep, yield func(*Bindings, error) bool) bool
219 visit = func(steps []*solverStep, yield func(*Bindings, error) bool) bool {
220 if len(steps) == 0 {
221 errors = nil
222
223 s.tracer.sat()
224 return yield(&Bindings{varNames: b.varNames, vals: slices.Clone(b.vals)}, nil)
225 }
226 step := steps[0]
227 steps = steps[1:]
228 switch step.kind {
229 case solverStepAssign:
230 val, err := step.expr.(*BinExpr).Y.eval(&b)
231 if err == nil {
232 if domain, ok := s.vars[step.bind]; ok && !slices.Contains(domain, val) {
233 err = fmt.Errorf("cannot assign %s=%v: not in domain", step.bind, val)
234 }
235 }
236 s.tracer.assign(step.expr, step.bind, val, err)
237 if err != nil {
238 addErr(err)
239 return true
240 }
241 b.vals = append(b.vals, val)
242 defer pop()
243 return visit(steps, yield)
244
245 case solverStepCheck:
246 val, err := step.expr.eval(&b)
247 s.tracer.check(step.expr, val, err)
248 if err != nil {
249 addErr(err)
250 return true
251 }
252 vBool, ok := val.(bool)
253 if !ok {
254 panic(fmt.Errorf("%s has type %T, expected bool", step.expr, val))
255 }
256 if vBool {
257 return visit(steps, yield)
258 }
259 return true
260
261 case solverStepIndep:
262 i := len(b.vals)
263 b.vals = append(b.vals, nil)
264 defer pop()
265 for _, val := range s.vars[step.bind] {
266 b.vals[i] = val
267 s.tracer.enter(step.bind, val)
268 if !visit(steps, yield) {
269 return false
270 }
271 s.tracer.exit()
272 }
273 return true
274 }
275 panic("bad step kind")
276 }
277 return func(yield func(*Bindings, error) bool) {
278 if visit(steps, yield) {
279 if len(errors) > 0 {
280 err := fmt.Errorf("%s", strings.Join(slices.Sorted(maps.Keys(errors)), "\n"))
281 yield(nil, err)
282 }
283 }
284 }
285 }
286
287 type solverStep struct {
288 kind solverStepKind
289 id int
290 expr Expr
291 bind Variable
292 hid int
293 }
294
295 type solverStepKind int
296
297 const (
298
299
300 solverStepIndep solverStepKind = iota
301
302
303
304
305
306 solverStepAssign
307
308
309 solverStepCheck
310 )
311
312 func (s *solverStep) Compare(t *solverStep) int {
313
314
315 if s.kind != t.kind {
316 return cmp.Compare(s.kind, t.kind)
317 }
318 switch s.kind {
319 case solverStepCheck, solverStepAssign:
320 return cmp.Compare(s.id, t.id)
321 case solverStepIndep:
322 return cmp.Compare(s.bind, t.bind)
323 }
324 panic("bad solverStep kind")
325 }
326
327 type solverHeap []*solverStep
328
329 func (sh solverHeap) Len() int { return len(sh) }
330
331 func (sh solverHeap) Less(i, j int) bool {
332 return sh[i].Compare(sh[j]) < 0
333 }
334
335 func (sh solverHeap) Swap(i, j int) {
336 sh[i], sh[j] = sh[j], sh[i]
337 sh[i].hid, sh[j].hid = i, j
338 }
339
340 func (sh *solverHeap) Push(x any) {
341 item := x.(*solverStep)
342 item.hid = len(*sh)
343 *sh = append(*sh, item)
344 }
345
346 func (sh *solverHeap) Pop() any {
347 old := *sh
348 n := len(old)
349 item := old[n-1]
350 old[n-1] = nil
351 item.hid = -1
352 *sh = old[0 : n-1]
353 return item
354 }
355
356 func (s *Solver) topoSort() (order []*solverStep, err error) {
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379 var queue solverHeap
380 defs := make(map[Variable][]*solverStep)
381 uses := make(map[Variable]map[*solverStep]bool)
382 remaining := make(map[*solverStep]int)
383
384 isVarAssign := func(e Expr) (Variable, Expr, bool) {
385 switch e := e.(type) {
386 case *BinExpr:
387 if e.Op == OpEqual {
388 switch x := e.X.(type) {
389 case Variable:
390 return x, e.Y, true
391 }
392 }
393 }
394 return "", nil, false
395 }
396
397 for i, assert := range s.asserts {
398 var rhs Expr
399
400 var step *solverStep
401 if def, val, ok := isVarAssign(assert); ok {
402 if def == val {
403
404
405 continue
406 }
407
408 step = &solverStep{kind: solverStepAssign, id: i, expr: assert, hid: -1, bind: def}
409
410 defs[def] = append(defs[def], step)
411 rhs = val
412 } else {
413
414 step = &solverStep{kind: solverStepCheck, id: i, expr: assert, hid: -1}
415 rhs = assert
416 }
417
418
419 deps := 0
420 for use := range exprVars(rhs) {
421 if uses[use] == nil {
422 uses[use] = make(map[*solverStep]bool)
423 }
424 if !uses[use][step] {
425 uses[use][step] = true
426 deps++
427 }
428 }
429 if deps == 0 {
430
431 step.hid = len(queue)
432 queue = append(queue, step)
433 } else {
434 remaining[step] = deps
435 }
436 }
437
438
439 for v := range uses {
440 if defs[v] == nil {
441 if _, ok := s.vars[v]; !ok {
442 return nil, fmt.Errorf("no domain for independent variable %q", v)
443 }
444 queue = append(queue, &solverStep{kind: solverStepIndep, bind: v, hid: -1})
445 }
446 }
447
448 for v := range s.vars {
449 if uses[v] == nil && defs[v] == nil {
450 queue = append(queue, &solverStep{kind: solverStepIndep, bind: v, hid: -1})
451 }
452 }
453
454
455
456 heap.Init(&queue)
457 for len(queue) > 0 {
458 step := queue[0]
459 heap.Pop(&queue)
460
461 order = append(order, step)
462
463 if step.kind == solverStepCheck {
464 continue
465 }
466
467
468 v := step.bind
469
470
471 for _, def := range defs[v] {
472 if def != step {
473 def.kind = solverStepCheck
474
475 if def.hid != -1 {
476 heap.Fix(&queue, def.hid)
477 }
478 }
479 }
480 delete(defs, v)
481
482
483 for use := range uses[v] {
484 remaining[use]--
485 if remaining[use] == 0 {
486
487
488 heap.Push(&queue, use)
489 delete(remaining, use)
490 }
491 }
492 }
493
494 if len(remaining) > 0 {
495 return nil, reportCycle(defs, remaining)
496 }
497 return order, nil
498 }
499
500 func reportCycle(defs map[Variable][]*solverStep, remaining map[*solverStep]int) error {
501
502
503 var step *solverStep
504 for rem := range remaining {
505 if rem.kind == solverStepAssign && (step == nil || rem.Compare(step) < 0) {
506 step = rem
507 }
508 }
509
510 var cycle []Expr
511 have := make(map[*solverStep]int)
512 var visit func(step *solverStep) error
513 visit = func(step *solverStep) error {
514 if step.kind != solverStepAssign || remaining[step] == 0 {
515 return nil
516 }
517 if i, ok := have[step]; ok {
518
519 return fmt.Errorf("cyclic requirements: %v", cycle[i:])
520 }
521 have[step] = len(cycle)
522 cycle = append(cycle, step.expr)
523 for v := range exprVars(step.expr.(*BinExpr).Y) {
524 for _, def := range defs[v] {
525 if err := visit(def); err != nil {
526 return err
527 }
528 }
529 }
530 delete(have, step)
531 cycle = cycle[:len(cycle)-1]
532 return nil
533 }
534 err := visit(step)
535 if err == nil {
536 log.Printf("remaining:")
537 for rem, count := range remaining {
538 log.Printf(" %v (%d)", rem, count)
539 }
540 log.Fatal("unresolved assertions, but failed to find a cycle")
541 }
542 return err
543 }
544
View as plain text