Example #1
0
// Returns a zero terminated list of failed assumption in the last call to
// Solve().  The pointer is valid until the next call to
// Solve() or FailedAssumptions.  It only makes sense if the
// last call to Solve() returned Unsatisfiable.
func (p *Pigosat) FailedAssumptions() Clause {
	if p.Res() != Unsatisfiable {
		return nil
	}
	defer p.ready(true)()

	p_int := C.picosat_failed_assumptions(p.p)

	// It should be reasonable to use the number of vars in
	// the solver as the max array size, since we aren't tracking
	// the active number of assumptions.
	size := int(C.picosat_variables(p.p))

	var cints []C.int
	header := (*reflect.SliceHeader)(unsafe.Pointer(&cints))
	header.Cap = size
	header.Len = size
	header.Data = uintptr(unsafe.Pointer(p_int))

	// The returns int pointer is both temporary, and larger than
	// needed, so we need to copy the real values into a new slice,
	// up until the terminator.
	ints := Clause{}
	for _, cint := range cints {
		// break at the first sign of the 0 terminator.
		if cint == 0 {
			break
		}
		ints = append(ints, Literal(cint))
	}
	return ints
}
Example #2
0
// BlockSolution adds a clause to the formula ruling out a given solution. It is
// a no-op if p is nil and returns an error if the solution is the wrong
// length. There is no need to call BlockSolution after calling Pigosat.Solve,
// which calls it automatically for every Satisfiable solution.
func (p *Pigosat) BlockSolution(solution Solution) error {
	defer p.ready(false)()
	if n := int(C.picosat_variables(p.p)); len(solution) != n+1 {
		return fmt.Errorf("solution length %d, but have %d variables",
			len(solution), n)
	}
	p.blocksol(solution)
	return nil
}
Example #3
0
// blocksol adds the inverse of the solution to the clauses.
// This private method does not acquire the lock or check if p is nil.
func (p *Pigosat) blocksol(sol Solution) {
	n := C.picosat_variables(p.p)
	clause := make([]C.int, n+1)
	for i := C.int(1); i <= n; i++ {
		if sol[i] {
			clause[i-1] = -i
		} else {
			clause[i-1] = i
		}
	}
	// int picosat_add_lits (PicoSAT *, int * lits);
	C.picosat_add_lits(p.p, &clause[0])
}
Example #4
0
// Solve the formula and return the status of the solution: one of the constants
// Unsatisfiable, Satisfiable, or Unknown. If satisfiable, return a slice
// indexed by the variables in the formula (so the first element is always
// false). Solve can be used like an iterator, yielding a new solution until
// there are no more feasible solutions:
//    for status, solution := p.Solve(); status == Satisfiable; status, solution = p.Solve() {
//        // Do stuff with status, solution
//    }
func (p *Pigosat) Solve() (status Status, solution Solution) {
	defer p.ready(false)()
	// int picosat_sat (PicoSAT *, int decision_limit);
	status = Status(C.picosat_sat(p.p, -1))
	if status == Unsatisfiable || status == Unknown {
		return
	} else if status != Satisfiable {
		panic(fmt.Errorf("Unknown sat status: %d", status))
	}
	n := int(C.picosat_variables(p.p)) // Calling Pigosat.Variables deadlocks
	solution = make(Solution, n+1)
	for i := 1; i <= n; i++ {
		// int picosat_deref (PicoSAT *, int lit);
		if val := C.picosat_deref(p.p, C.int(i)); val > 0 {
			solution[i] = true
		} else if val == 0 {
			panic(fmt.Errorf("Variable %d was assigned value 0", i))
		}
	}
	p.blocksol(solution)
	return
}
Example #5
0
// Variables returns the number of variables in the formula: The m in the DIMACS
// header "p cnf <m> n".
func (p *Pigosat) Variables() int {
	defer p.ready(true)()
	// int picosat_variables (PicoSAT *);
	return int(C.picosat_variables(p.p))
}