mirror of
https://github.com/mudler/luet.git
synced 2025-09-10 11:39:35 +00:00
update vendor
This commit is contained in:
149
vendor/github.com/crillab/gophersat/explain/check.go
generated
vendored
Normal file
149
vendor/github.com/crillab/gophersat/explain/check.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// Package explain provides facilities to check and understand UNSAT instances.
|
||||
package explain
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/crillab/gophersat/solver"
|
||||
)
|
||||
|
||||
// Options is a set of options that can be set to true during the checking process.
|
||||
type Options struct {
|
||||
// If Verbose is true, information about resolution will be written on stdout.
|
||||
Verbose bool
|
||||
}
|
||||
|
||||
// Checks whether the clause satisfies the problem or not.
|
||||
// Will return true if the problem is UNSAT, false if it is SAT or indeterminate.
|
||||
func unsat(pb *Problem, clause []int) bool {
|
||||
oldUnits := make([]int, len(pb.units))
|
||||
copy(oldUnits, pb.units)
|
||||
// lits is supposed to be implied by the problem.
|
||||
// We add the negation of each lit as a unit clause to see if this is true.
|
||||
for _, lit := range clause {
|
||||
if lit > 0 {
|
||||
pb.units[lit-1] = -1
|
||||
} else {
|
||||
pb.units[-lit-1] = 1
|
||||
}
|
||||
}
|
||||
res := pb.unsat()
|
||||
pb.units = oldUnits // We must restore the previous state
|
||||
return res
|
||||
}
|
||||
|
||||
// UnsatChan will wait RUP clauses from ch and use them as a certificate.
|
||||
// It will return true iff the certificate is valid, i.e iff it makes the problem UNSAT
|
||||
// through unit propagation.
|
||||
// If pb.Options.ExtractSubset is true, a subset will also be extracted for that problem.
|
||||
func (pb *Problem) UnsatChan(ch chan string) (valid bool, err error) {
|
||||
defer pb.restore()
|
||||
pb.initTagged()
|
||||
for line := range ch {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
if _, err := strconv.Atoi(fields[0]); err != nil {
|
||||
// This is not a clause: ignore the line
|
||||
continue
|
||||
}
|
||||
clause, err := parseClause(fields)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !unsat(pb, clause) {
|
||||
return false, nil
|
||||
}
|
||||
if len(clause) == 0 {
|
||||
// This is the empty and unit propagation made the problem UNSAT: we're done.
|
||||
return true, nil
|
||||
}
|
||||
// Since clause is a logical consequence, append it to the problem
|
||||
pb.Clauses = append(pb.Clauses, clause)
|
||||
}
|
||||
|
||||
// If we did not send any information through the channel
|
||||
// It implies that the problem is trivially unsatisfiable
|
||||
// Since we had only unit clauses inside the channel.
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Unsat will parse a certificate, and return true iff the certificate is valid, i.e iff it makes the problem UNSAT
|
||||
// through unit propagation.
|
||||
// If pb.Options.ExtractSubset is true, a subset will also be extracted for that problem.
|
||||
func (pb *Problem) Unsat(cert io.Reader) (valid bool, err error) {
|
||||
defer pb.restore()
|
||||
pb.initTagged()
|
||||
sc := bufio.NewScanner(cert)
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
if _, err := strconv.Atoi(fields[0]); err != nil {
|
||||
// This is not a clause: ignore the line
|
||||
continue
|
||||
}
|
||||
clause, err := parseClause(fields)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !unsat(pb, clause) {
|
||||
return false, nil
|
||||
}
|
||||
// Since clause is a logical consequence, append it to the problem
|
||||
pb.Clauses = append(pb.Clauses, clause)
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return false, fmt.Errorf("could not parse certificate: %v", err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ErrNotUnsat is the error returned when trying to get the MUS or UnsatSubset of a satisfiable problem.
|
||||
var ErrNotUnsat = fmt.Errorf("problem is not UNSAT")
|
||||
|
||||
// UnsatSubset returns an unsatisfiable subset of the problem.
|
||||
// The subset is not guaranteed to be a MUS, meaning some clauses of the resulting
|
||||
// problem might be removed while still keeping the unsatisfiability of the problem.
|
||||
// However, this method is much more efficient than extracting a MUS, as it only calls
|
||||
// the SAT solver once.
|
||||
func (pb *Problem) UnsatSubset() (subset *Problem, err error) {
|
||||
solverPb := solver.ParseSlice(pb.Clauses)
|
||||
if solverPb.Status == solver.Unsat {
|
||||
// Problem is trivially UNSAT
|
||||
// Make a copy so that pb and pb2 are not the same value.
|
||||
pb2 := *pb
|
||||
return &pb2, nil
|
||||
}
|
||||
s := solver.New(solver.ParseSlice(pb.Clauses))
|
||||
s.Certified = true
|
||||
s.CertChan = make(chan string)
|
||||
status := solver.Unsat
|
||||
go func() {
|
||||
status = s.Solve()
|
||||
close(s.CertChan)
|
||||
}()
|
||||
if valid, err := pb.UnsatChan(s.CertChan); !valid || status == solver.Sat {
|
||||
return nil, ErrNotUnsat
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("could not solve problem: %v", err)
|
||||
}
|
||||
subset = &Problem{
|
||||
NbVars: pb.NbVars,
|
||||
}
|
||||
for i, clause := range pb.Clauses {
|
||||
if pb.tagged[i] {
|
||||
// clause was used to prove pb is UNSAT: it's part of the subset
|
||||
subset.Clauses = append(subset.Clauses, clause)
|
||||
subset.NbClauses++
|
||||
}
|
||||
}
|
||||
return subset, nil
|
||||
}
|
Reference in New Issue
Block a user