Skip to content

Commit

Permalink
Ensure solver output is deterministic
Browse files Browse the repository at this point in the history
Signed-off-by: Mikalai Radchuk <mradchuk@redhat.com>
  • Loading branch information
m1kola committed Nov 16, 2023
1 parent d7f4845 commit 11c5175
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 55 deletions.
16 changes: 9 additions & 7 deletions internal/solver/lit_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ func (inconsistentLitMapping) Error() string {
// Solve (Constraints, Variables, etc.) and the variables that
// appear in the SAT formula.
type litMapping struct {
inorder []deppy.Variable
variables map[z.Lit]deppy.Variable
lits map[deppy.Identifier]z.Lit
constraints map[z.Lit]deppy.AppliedConstraint
c *logic.C
errs inconsistentLitMapping
inorder []deppy.Variable
variables map[z.Lit]deppy.Variable
lits map[deppy.Identifier]z.Lit
constraints map[z.Lit]deppy.AppliedConstraint
constraintsInOrder []z.Lit
c *logic.C
errs inconsistentLitMapping
}

// newLitMapping returns a new litMapping with its state initialized based on
Expand Down Expand Up @@ -72,6 +73,7 @@ func newLitMapping(variables []deppy.Variable) (*litMapping, error) {
Variable: variable,
Constraint: constraint,
}
d.constraintsInOrder = append(d.constraintsInOrder, m)
}
}

Expand Down Expand Up @@ -142,7 +144,7 @@ func (d *litMapping) AddConstraints(g inter.S) {
}

func (d *litMapping) AssumeConstraints(s inter.S) {
for m := range d.constraints {
for _, m := range d.constraintsInOrder {
s.Assume(m)
}
}
Expand Down
58 changes: 10 additions & 48 deletions internal/solver/solve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ package solver
import (
"bytes"
"context"
"errors"
"fmt"
"reflect"
"sort"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -117,11 +114,11 @@ func TestSolve(t *testing.T) {
Error: deppy.NotSatisfiable{
{
Variable: variable("a", constraint.Mandatory(), constraint.Prohibited()),
Constraint: constraint.Mandatory(),
Constraint: constraint.Prohibited(),
},
{
Variable: variable("a", constraint.Mandatory(), constraint.Prohibited()),
Constraint: constraint.Prohibited(),
Constraint: constraint.Mandatory(),
},
},
},
Expand Down Expand Up @@ -186,16 +183,16 @@ func TestSolve(t *testing.T) {
},
Error: deppy.NotSatisfiable{
{
Variable: variable("a", constraint.Mandatory()),
Constraint: constraint.Mandatory(),
Variable: variable("b", constraint.Mandatory(), constraint.Conflict("a")),
Constraint: constraint.Conflict("a"),
},
{
Variable: variable("b", constraint.Mandatory(), constraint.Conflict("a")),
Constraint: constraint.Mandatory(),
},
{
Variable: variable("b", constraint.Mandatory(), constraint.Conflict("a")),
Constraint: constraint.Conflict("a"),
Variable: variable("a", constraint.Mandatory()),
Constraint: constraint.Mandatory(),
},
},
},
Expand All @@ -218,16 +215,16 @@ func TestSolve(t *testing.T) {
},
Error: deppy.NotSatisfiable{
{
Variable: variable("a", constraint.Mandatory(), constraint.Dependency("x", "y"), constraint.AtMost(1, "x", "y")),
Constraint: constraint.AtMost(1, "x", "y"),
Variable: variable("y", constraint.Mandatory()),
Constraint: constraint.Mandatory(),
},
{
Variable: variable("x", constraint.Mandatory()),
Constraint: constraint.Mandatory(),
},
{
Variable: variable("y", constraint.Mandatory()),
Constraint: constraint.Mandatory(),
Variable: variable("a", constraint.Mandatory(), constraint.Dependency("x", "y"), constraint.AtMost(1, "x", "y")),
Constraint: constraint.AtMost(1, "x", "y"),
},
},
},
Expand Down Expand Up @@ -301,41 +298,6 @@ func TestSolve(t *testing.T) {

installed, err := s.Solve(context.TODO())

if installed != nil {
sort.SliceStable(installed, func(i, j int) bool {
return installed[i].Identifier() < installed[j].Identifier()
})
}

// Failed constraints are sorted in lexically
// increasing Order of the identifier of the
// constraint's variable, with ties broken
// in favor of the constraint that appears
// earliest in the variable's list of
// constraints.
var ns deppy.NotSatisfiable
if errors.As(err, &ns) {
sort.SliceStable(ns, func(i, j int) bool {
if ns[i].Variable.Identifier() != ns[j].Variable.Identifier() {
return ns[i].Variable.Identifier() < ns[j].Variable.Identifier()
}
var x, y int
for ii, c := range ns[i].Variable.Constraints() {
if reflect.DeepEqual(c, ns[i].Constraint) {
x = ii
break
}
}
for ij, c := range ns[j].Variable.Constraints() {
if reflect.DeepEqual(c, ns[j].Constraint) {
y = ij
break
}
}
return x < y
})
}

var ids []deppy.Identifier
for _, variable := range installed {
ids = append(ids, variable.Identifier())
Expand Down

0 comments on commit 11c5175

Please sign in to comment.