Skip to content

Commit

Permalink
sat: sort inputs to the sat solver for determinism
Browse files Browse the repository at this point in the history
Make sure the sat solver output is deterministic and reproducible by
making the input order stable
  • Loading branch information
manuelnaranjo committed Jan 14, 2025
1 parent 73ea213 commit e9f6570
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 5 deletions.
2 changes: 2 additions & 0 deletions pkg/sat/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ go_library(
"@com_github_crillab_gophersat//explain",
"@com_github_crillab_gophersat//maxsat",
"@com_github_sirupsen_logrus//:logrus",
"@org_golang_x_exp//maps",
"@org_golang_x_exp//slices",
],
)

Expand Down
34 changes: 29 additions & 5 deletions pkg/sat/sat.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sat

import (
"bufio"
"cmp"
"fmt"
"io"
"regexp"
Expand All @@ -16,6 +17,8 @@ import (
"github.com/rmohr/bazeldnf/pkg/reducer"
"github.com/rmohr/bazeldnf/pkg/rpm"
"github.com/sirupsen/logrus"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
)

type VarType string
Expand All @@ -34,6 +37,13 @@ type VarContext struct {
Version api.Version
}

func varContextSort(a VarContext, b VarContext) int {
return cmp.Or(
cmp.Compare(a.Package, b.Package),
rpm.Compare(a.Version, b.Version),
)
}

type Var struct {
satVarName string
varType VarType
Expand Down Expand Up @@ -129,8 +139,12 @@ func (r *Resolver) LoadInvolvedPackages(packages []*api.Package, ignoreRegex []s
deduplicated[pkg.String()] = packages[i]
}
}

deduplicatedKeys := maps.Keys(deduplicated)
slices.Sort(deduplicatedKeys)

packages = nil
for k, _ := range deduplicated {
for _, k := range deduplicatedKeys {
reducer.FixPackages(deduplicated[k])
packages = append(packages, deduplicated[k])
}
Expand All @@ -146,8 +160,10 @@ func (r *Resolver) LoadInvolvedPackages(packages []*api.Package, ignoreRegex []s

if !r.nobest {
packages = nil
for _, v := range r.bestPackages {
packages = append(packages, v)
bestPackagesKeys := maps.Keys(r.bestPackages)
slices.Sort(bestPackagesKeys)
for _, v := range bestPackagesKeys {
packages = append(packages, r.bestPackages[v])
}
}
// Generate variables
Expand All @@ -161,17 +177,25 @@ func (r *Resolver) LoadInvolvedPackages(packages []*api.Package, ignoreRegex []s
}
}

for x, _ := range r.packages {
packagesKeys := maps.Keys(r.packages)
slices.Sort(packagesKeys)

for _, x := range packagesKeys {
sort.SliceStable(r.packages[x], func(i, j int) bool {
return rpm.Compare(r.packages[x][i].Package.Version, r.packages[x][j].Package.Version) < 0
})
}

logrus.Infof("Loaded %v packages.", len(r.pkgProvides))

pkgProvideKeys := maps.Keys(r.pkgProvides)
slices.SortFunc(pkgProvideKeys, varContextSort)

// Generate imply rules
for _, resourceVars := range r.pkgProvides {
for _, provided := range pkgProvideKeys {
// Create imply rules for every package and add them to the formula
// one provided dependency implies all dependencies from that package
resourceVars := r.pkgProvides[provided]
bfVar := bf.And(toBFVars(resourceVars)...)
var ands []bf.Formula
for _, res := range resourceVars {
Expand Down

0 comments on commit e9f6570

Please sign in to comment.