mirror of
https://github.com/mudler/luet.git
synced 2025-09-16 15:19:24 +00:00
🎨 Port package to types
This refactors DefaultPackage into types.Package and gets rid of the interface. This is a preceeding for a follow up where accessors will be removed from the code. It also does several cleanup, so we get rid also of some unneeded dependencies.
This commit is contained in:
@@ -16,21 +16,16 @@
|
||||
package solver
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/crillab/gophersat/bf"
|
||||
"github.com/crillab/gophersat/explain"
|
||||
"github.com/mudler/luet/pkg/api/core/types"
|
||||
"github.com/mudler/luet/pkg/helpers"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/ecooper/qlearning"
|
||||
pkg "github.com/mudler/luet/pkg/package"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -56,117 +51,6 @@ const (
|
||||
QLearningResolverType = "qlearning"
|
||||
)
|
||||
|
||||
// PackageResolver assists PackageSolver on unsat cases
|
||||
type PackageResolver interface {
|
||||
Solve(bf.Formula, PackageSolver) (PackagesAssertions, error)
|
||||
}
|
||||
|
||||
type Explainer struct{}
|
||||
|
||||
func decodeDimacs(vars map[string]string, dimacs string) (string, error) {
|
||||
res := ""
|
||||
sc := bufio.NewScanner(bytes.NewBufferString(dimacs))
|
||||
lines := strings.Split(dimacs, "\n")
|
||||
linenum := 1
|
||||
SCAN:
|
||||
for sc.Scan() {
|
||||
|
||||
line := sc.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "p":
|
||||
continue SCAN
|
||||
default:
|
||||
for i := 0; i < len(fields)-1; i++ {
|
||||
v := fields[i]
|
||||
negative := false
|
||||
if strings.HasPrefix(fields[i], "-") {
|
||||
v = strings.TrimLeft(fields[i], "-")
|
||||
negative = true
|
||||
}
|
||||
variable := vars[v]
|
||||
if negative {
|
||||
res += fmt.Sprintf("!(%s)", variable)
|
||||
} else {
|
||||
res += variable
|
||||
}
|
||||
|
||||
if i != len(fields)-2 {
|
||||
res += fmt.Sprintf(" or ")
|
||||
}
|
||||
}
|
||||
if linenum != len(lines)-1 {
|
||||
res += fmt.Sprintf(" and \n")
|
||||
}
|
||||
}
|
||||
linenum++
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return res, fmt.Errorf("could not parse problem: %v", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseVars(r io.Reader) (map[string]string, error) {
|
||||
sc := bufio.NewScanner(r)
|
||||
res := map[string]string{}
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "c":
|
||||
data := strings.Split(fields[1], "=")
|
||||
res[data[1]] = data[0]
|
||||
|
||||
default:
|
||||
continue
|
||||
|
||||
}
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return nil, fmt.Errorf("could not parse problem: %v", err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Solve tries to find the MUS (minimum unsat) formula from the original problem.
|
||||
// it returns an error with the decoded dimacs
|
||||
func (*Explainer) Solve(f bf.Formula, s PackageSolver) (PackagesAssertions, error) {
|
||||
buf := bytes.NewBufferString("")
|
||||
if err := bf.Dimacs(f, buf); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot extract dimacs from formula")
|
||||
}
|
||||
|
||||
copy := *buf
|
||||
|
||||
pb, err := explain.ParseCNF(©)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse problem")
|
||||
}
|
||||
pb2, err := pb.MUS()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not extract subset")
|
||||
}
|
||||
|
||||
variables, err := parseVars(buf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse variables")
|
||||
}
|
||||
|
||||
res, err := decodeDimacs(variables, pb2.CNF())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse dimacs")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not satisfy the constraints: \n%s", res)
|
||||
}
|
||||
|
||||
type QLearningResolver struct {
|
||||
Attempts int
|
||||
|
||||
@@ -176,24 +60,24 @@ type QLearningResolver struct {
|
||||
|
||||
Attempted map[string]bool
|
||||
|
||||
Solver PackageSolver
|
||||
Solver types.PackageSolver
|
||||
Formula bf.Formula
|
||||
|
||||
Targets pkg.Packages
|
||||
Current pkg.Packages
|
||||
Targets types.Packages
|
||||
Current types.Packages
|
||||
|
||||
observedDelta int
|
||||
observedDeltaChoice pkg.Packages
|
||||
observedDeltaChoice types.Packages
|
||||
|
||||
Agent *qlearning.SimpleAgent
|
||||
}
|
||||
|
||||
func SimpleQLearningSolver() PackageResolver {
|
||||
func SimpleQLearningSolver() types.PackageResolver {
|
||||
return NewQLearningResolver(DefaultLearningRate, DefaultDiscount, DefaultMaxAttempts, DefaultInitialObserved)
|
||||
}
|
||||
|
||||
// Defaults LearningRate 0.7, Discount 1.0
|
||||
func NewQLearningResolver(LearningRate, Discount float32, MaxAttempts, initialObservedDelta int) PackageResolver {
|
||||
func NewQLearningResolver(LearningRate, Discount float32, MaxAttempts, initialObservedDelta int) types.PackageResolver {
|
||||
return &QLearningResolver{
|
||||
Agent: qlearning.NewSimpleAgent(LearningRate, Discount),
|
||||
observedDelta: initialObservedDelta,
|
||||
@@ -201,7 +85,7 @@ func NewQLearningResolver(LearningRate, Discount float32, MaxAttempts, initialOb
|
||||
}
|
||||
}
|
||||
|
||||
func (resolver *QLearningResolver) Solve(f bf.Formula, s PackageSolver) (PackagesAssertions, error) {
|
||||
func (resolver *QLearningResolver) Solve(f bf.Formula, s types.PackageSolver) (types.PackagesAssertions, error) {
|
||||
// Info("Using QLearning solver to resolve conflicts. Please be patient.")
|
||||
resolver.Solver = s
|
||||
|
||||
@@ -276,10 +160,10 @@ func (resolver *QLearningResolver) IsComplete() int {
|
||||
|
||||
func (resolver *QLearningResolver) Try(c Choice) error {
|
||||
pack := c.Package
|
||||
packtoAdd := pkg.FromString(pack)
|
||||
packtoAdd := types.PackageFromString(pack)
|
||||
resolver.Attempted[pack+strconv.Itoa(int(c.Action))] = true // increase the count
|
||||
s, _ := resolver.Solver.(*Solver)
|
||||
var filtered pkg.Packages
|
||||
var filtered types.Packages
|
||||
|
||||
switch c.Action {
|
||||
case ActionAdded:
|
||||
|
Reference in New Issue
Block a user