func buildLogEncoding(pred sat.Pred, uId int, cutoff int, depth int, tag string, lits []sat.Literal) (clauses sat.ClauseSet) { if len(lits) <= cutoff { trans2 := TranslateAtMostOne(Naive, tag, lits) clauses.AddClauseSet(trans2.Clauses) } else { atom := sat.NewAtomP2(pred, uId, depth) first := lits[:len(lits)/2] for _, l := range first { clauses.AddTaggedClause(tag, sat.Literal{true, atom}, sat.Neg(l)) } second := lits[len(lits)/2:] for _, l := range second { clauses.AddTaggedClause(tag, sat.Literal{false, atom}, sat.Neg(l)) } depth++ clauses.AddClauseSet(buildLogEncoding(pred, uId, cutoff, depth, tag, first)) clauses.AddClauseSet(buildLogEncoding(pred, uId, cutoff, depth, tag, second)) } return }
func (t *Threshold) NormalizePositiveLiterals() { glob.A(len(t.Chains) == 0, "cant reorder Entries with chains") for i, e := range t.Entries { if t.Entries[i].Literal.Sign == false { t.Entries[i].Literal = sat.Neg(e.Literal) t.K -= t.Entries[i].Weight t.Entries[i].Weight = -t.Entries[i].Weight } } }
// finds trivially implied facts, returns set of facts // removes such entries from the pb // threshold can become empty! func (pb *Threshold) Simplify() { if pb.Typ == OPT { glob.D(pb.IdS(), " is not simplyfied because is OPT") return } pb.Normalize(LE, true) entries := make([]Entry, 0, len(pb.Entries)) for _, x := range pb.Entries { if x.Weight > pb.K { pb.Clauses.AddTaggedClause(pb.IdS()+"-simpl", sat.Neg(x.Literal)) } else { entries = append(entries, x) } } pb.Entries = entries pb.Normalize(GE, true) if pb.SumWeights() == pb.K { for _, x := range pb.Entries { pb.Clauses.AddTaggedClause("Fact", x.Literal) } pb.Entries = []Entry{} } if pb.SumWeights() < pb.K { glob.D("c PB", pb.Id, "is UNSAT") pb.Entries = []Entry{} pb.K = -1 // is unsatisfied: how to do that? } pb.Normalize(LE, true) if pb.SumWeights() <= pb.K { glob.D("c PB", pb.Id, "is redundant") pb.Entries = []Entry{} } if pb.Empty() { pb.Translated = true } return }
func TestRewriteExactly4(test *testing.T) { glob.D("TestExactly3") pb1 := CreatePB([]int64{2, 2, 3, 4, 1, 1}, 6) pb1.Typ = LE pb2 := CreatePB([]int64{1, 1, 1, 1}, 2) pb2.Typ = EQ pb2.Entries[2].Literal = sat.Neg(pb2.Entries[2].Literal) b := PreprocessPBwithExactly(&pb1, &pb2) if b { test.Fail() } }
// Translate monotone MDDs to SAT // Together with AMO translation func convertMDD2Clauses(store mdd.IntervalMddStore, pb *Threshold) (clauses sat.ClauseSet) { pred := sat.Pred("mdd" + strconv.Itoa(pb.Id)) top_lit := sat.Literal{true, sat.NewAtomP1(pred, store.Top)} clauses.AddTaggedClause("Top", top_lit) for _, n := range store.Nodes { v_id, l, vds := store.ClauseIds(*n) if !n.IsZero() && !n.IsOne() { v_lit := sat.Literal{false, sat.NewAtomP1(pred, v_id)} last_id := -1 for i, vd_id := range vds { if last_id != vd_id { vd_lit := sat.Literal{true, sat.NewAtomP1(pred, vd_id)} if i > 0 { literal := pb.Entries[len(pb.Entries)-l+i-1].Literal clauses.AddTaggedClause("1B", v_lit, sat.Neg(literal), vd_lit) } else { clauses.AddTaggedClause("0B", v_lit, vd_lit) } } last_id = vd_id } } else if n.IsZero() { v_lit := sat.Literal{false, sat.NewAtomP1(pred, v_id)} clauses.AddTaggedClause("False", v_lit) } else if n.IsOne() { v_lit := sat.Literal{true, sat.NewAtomP1(pred, v_id)} clauses.AddTaggedClause("True", v_lit) } } return }
// Create Encoding for Sorting Network // 0) Omitted for clarity (ids as in paper) // 1) A or -D // 2) B or -D // 3) -A or -B or D // 4) -A or C // 5) -B or C // 6) A or B or -C // 7) C or -D // -1,0,1 = *, false, true func CreateEncoding(input []sat.Literal, which [8]bool, output []sat.Literal, tag string, pred sat.Pred, sorter sorters.Sorter) (cs sat.ClauseSet) { //cs.list = make([]Clause, 0, 7*len(sorter.Comparators)) backup := make(map[int]sat.Literal, len(sorter.Out)+len(sorter.In)) for i, x := range sorter.In { backup[x] = input[i] } for i, x := range sorter.Out { backup[x] = output[i] } for _, comp := range sorter.Comparators { if comp.D == 1 || comp.C == 0 { fmt.Println("something is wrong with the comparator", comp) panic("something is wrong with the comparator") } getLit := func(x int) sat.Literal { if lit, ok := backup[x]; ok { return lit } else { return sat.Literal{true, sat.NewAtomP1(pred, x)} } } a := getLit(comp.A) b := getLit(comp.B) c := getLit(comp.C) d := getLit(comp.D) if comp.C == 1 { // 6) A or B //if which[6] { cs.AddTaggedClause(tag, a, b) //} } else if comp.C > 0 { // 4) 5) 6) //4) if which[4] { cs.AddTaggedClause(tag, sat.Neg(a), c) } //5) if which[5] { cs.AddTaggedClause(tag, sat.Neg(b), c) } //6) if which[6] { cs.AddTaggedClause(tag, a, b, sat.Neg(c)) } } if comp.D == 0 { //3) //if which[3] { cs.AddTaggedClause(tag, sat.Neg(a), sat.Neg(b)) //} } else if comp.D > 0 { // 1) 2) 3) //1) if which[1] { cs.AddTaggedClause(tag, a, sat.Neg(d)) } //2) if which[2] { cs.AddTaggedClause(tag, b, sat.Neg(d)) } //3) if which[3] { cs.AddTaggedClause(tag, sat.Neg(a), sat.Neg(b), d) } } if which[7] && comp.C != 1 && comp.D != 0 && comp.C != -1 && comp.D != -1 { // 7) if comp.C == 0 || comp.D == 1 { panic("something is wrong with this comparator") } cs.AddTaggedClause(tag, c, sat.Neg(d)) } } return }
func main() { glob.Init() input, err2 := os.Open(*glob.Filename_flag) defer input.Close() if err2 != nil { panic("Could not read file") return } scanner := bufio.NewScanner(input) buf := make([]byte, 0, 64*1024) scanner.Buffer(buf, 1024*1024) state := 0 // 0: read size, 1: read graph 1, 2: read graph 2 vars := 0 orig_vars := 0 size := 0 i := 0 var entries []entry for scanner.Scan() { l := strings.Trim(scanner.Text(), " ") if l == "" || strings.HasPrefix(l, "%") || strings.HasPrefix(l, "*") { continue } elements := strings.Fields(l) var b error switch state { case 0: // deprecated: for parsing the "header" of pb files, now parser is flexible { vars, b = strconv.Atoi(elements[0]) if b != nil { panic("bad conversion of numbers") } orig_vars = vars size, b = strconv.Atoi(elements[1]) if b != nil { panic("bad conversion of numbers") } entries = make([]entry, size) state = 1 } case 1: { entries[i].id1, b = strconv.Atoi(elements[0]) if b != nil { panic("bad conversion of numbers") } entries[i].id2, b = strconv.Atoi(elements[1]) if b != nil { panic("bad conversion of numbers") } var f float64 f, b = strconv.ParseFloat(elements[2], 64) if b != nil { panic("bad conversion of numbers") } entries[i].c = int64(f) if entries[i].id1 != entries[i].id2 { vars++ entries[i].and = vars } i++ } } } var clauses sat.ClauseSet var opt constraints.Threshold opt.Typ = constraints.OPT lits := make([]sat.Literal, vars+1) primaryVars := make(map[string]bool, 0) for i := 0; i <= vars; i++ { primaryVars[sat.NewAtomP1(sat.Pred("x"), i).Id()] = true } for i, _ := range lits { lits[i] = sat.Literal{true, sat.NewAtomP1(sat.Pred("x"), i)} } for _, e := range entries { if e.id1 == e.id2 { opt.Entries = append(opt.Entries, constraints.Entry{lits[e.id1], int64(e.c)}) } else { clauses.AddClause(sat.Neg(lits[e.id1]), sat.Neg(lits[e.id2]), lits[e.and]) clauses.AddClause(lits[e.id1], sat.Neg(lits[e.and])) clauses.AddClause(lits[e.id2], sat.Neg(lits[e.and])) opt.Entries = append(opt.Entries, constraints.Entry{lits[e.and], int64(e.c)}) } } if *glob.Gringo_flag { for i := 0; i <= orig_vars; i++ { fmt.Println("{x(", i, ")}.") } for _, e := range entries { if e.id1 != e.id2 { fmt.Println(lits[e.and].ToTxt(), ":-", lits[e.id1].ToTxt(), ",", lits[e.id2].ToTxt(), ".") } } opt.PrintGringo() return } g := sat.IdGenerator(clauses.Size()*7 + 1) g.PrimaryVars = primaryVars opt.NormalizePositiveCoefficients() opt.Offset = opt.K // opt.PrintGringo() // clauses.PrintDebug() glob.D("offset", opt.Offset) glob.A(opt.Positive(), "opt only has positive coefficients") g.Solve(clauses, &opt, *glob.Opt_bound_flag, -opt.Offset) }
func (pb *Threshold) CatSimpl() { glob.A(!pb.Empty(), "pb should not be empty") if pb.Typ == OPT { glob.D(pb.IdS(), " is not simplyfied because is OPT") pb.TransTyp = UNKNOWN return } pb.Simplify() if pb.Empty() { pb.TransTyp = Facts return } else { if b, literals := pb.Cardinality(); b { if pb.K == int64(len(pb.Entries)-1) { switch pb.Typ { case LE: pb.Normalize(GE, true) for i, x := range literals { literals[i] = sat.Neg(x) } case GE: for i, x := range literals { literals[i] = sat.Neg(x) } pb.Normalize(LE, true) case EQ: for i, x := range literals { literals[i] = sat.Neg(x) } pb.Multiply(-1) pb.NormalizePositiveCoefficients() } } if pb.K == 1 { switch pb.Typ { case LE: // check for binary, which is also a clause ( ~l1 \/ ~l2 ) if len(pb.Entries) == 2 { pb.Clauses.AddTaggedClause("Cls", sat.Neg(pb.Entries[0].Literal), sat.Neg(pb.Entries[1].Literal)) pb.TransTyp = Clause } else { pb.TransTyp = AMO } case GE: // its a clause! pb.Clauses.AddTaggedClause("Cls", literals...) pb.TransTyp = Clause case EQ: pb.TransTyp = EX1 } } else { //cardinality switch pb.Typ { case LE, GE, EQ: pb.CreateCardinality() pb.TransTyp = CARD } } } } return }
func TranslateAtMostOne(typ OneTranslationType, tag string, lits []sat.Literal) (trans CardTranslation) { var clauses sat.ClauseSet switch typ { case Naive: for i, l := range lits { for j := i + 1; j < len(lits); j++ { clauses.AddTaggedClause(tag, sat.Neg(l), sat.Neg(lits[j])) } } case Split: // a constant that should be exposed, // its the cuttoff for the split method of atMostOne cutoff := 5 if len(lits) <= cutoff { return TranslateAtMostOne(Naive, tag, lits) } else { aux := sat.NewAtomP1(sat.Pred("split"), newId()) trans.Aux = append(trans.Aux, sat.Literal{true, aux}) for _, l := range lits[:len(lits)/2] { clauses.AddTaggedClause(tag, sat.Literal{true, aux}, sat.Neg(l)) } for _, l := range lits[len(lits)/2:] { clauses.AddTaggedClause(tag, sat.Literal{false, aux}, sat.Neg(l)) } clauses.AddClauseSet(TranslateAtMostOne(typ, tag, lits[:len(lits)/2]).Clauses) clauses.AddClauseSet(TranslateAtMostOne(typ, tag, lits[len(lits)/2:]).Clauses) } case Count: pred := sat.Pred("c") counterId := newId() auxs := make([]sat.Literal, len(lits)) for i, _ := range auxs { auxs[i] = sat.Literal{true, sat.NewAtomP2(pred, counterId, i)} } trans.Aux = auxs // S_i -> S_{i-1} for i := 1; i < len(lits); i++ { clauses.AddTaggedClause(tag, auxs[i-1], sat.Neg(auxs[i])) } // X_i -> S_i for i := 0; i < len(lits); i++ { clauses.AddTaggedClause(tag, auxs[i], sat.Neg(lits[i])) } // X_i-1 -> -S_i for i := 1; i < len(lits); i++ { clauses.AddTaggedClause(tag, sat.Neg(auxs[i]), sat.Neg(lits[i-1])) } // (S_i-1 /\ -S_i) -> X_i-1 for i := 1; i <= len(lits); i++ { if i != len(lits) { clauses.AddTaggedClause(tag, sat.Neg(auxs[i-1]), auxs[i], lits[i-1]) } else { clauses.AddTaggedClause(tag, sat.Neg(auxs[i-1]), lits[i-1]) } } case Heule: k := 4 // fixed size for the heule encoding if len(lits) > k+1 { aux := sat.NewAtomP1(sat.Pred("heule"), newId()) trans.Aux = append(trans.Aux, sat.Literal{true, aux}) front := make([]sat.Literal, k+1) copy(front, lits[:k]) front[k] = sat.Literal{true, aux} trans2 := TranslateAtMostOne(Naive, tag, front) clauses.AddClauseSet(trans2.Clauses) back := make([]sat.Literal, len(lits)-k+1) copy(back, lits[k:]) back[len(lits)-k] = sat.Literal{false, aux} trans2 = TranslateAtMostOne(typ, tag, back) trans.Aux = append(trans.Aux, trans2.Aux...) clauses.AddClauseSet(trans2.Clauses) } else { trans2 := TranslateAtMostOne(Naive, tag, lits) clauses.AddClauseSet(trans2.Clauses) } case Log: cutoff := 5 //will be a parameter of this encoding clauses = buildLogEncoding(sat.Pred("logE"), newId(), cutoff, 0, tag, lits) case Sort: panic("CNF translation for this type not implemented yet") default: panic("CNF translation for this type not implemented yet") } trans.Typ = typ trans.Clauses = clauses return }
func TranslateExactlyOne(typ OneTranslationType, tag string, lits []sat.Literal) (trans CardTranslation) { var clauses sat.ClauseSet switch typ { case Heule, Log, Naive, Split: trans2 := TranslateAtMostOne(typ, tag, lits) trans.Aux = append(trans.Aux, trans2.Aux...) clauses.AddClauseSet(trans2.Clauses) clauses.AddTaggedClause(tag, lits...) case Count: pred := sat.Pred("cx") counterId := newId() auxs := make([]sat.Literal, len(lits)) for i, _ := range auxs { auxs[i] = sat.Literal{true, sat.NewAtomP2(pred, counterId, i)} } trans.Aux = auxs // S_i -> S_{i-1} for i := 1; i < len(lits); i++ { clauses.AddTaggedClause(tag, auxs[i-1], sat.Neg(auxs[i])) } // X_i -> S_i for i := 0; i < len(lits); i++ { clauses.AddTaggedClause(tag, auxs[i], sat.Neg(lits[i])) } // X_i-1 -> -S_i for i := 1; i < len(lits); i++ { clauses.AddTaggedClause(tag, sat.Neg(auxs[i]), sat.Neg(lits[i-1])) } // (S_i-1 /\ -S_i) -> X_i-1 for i := 1; i <= len(lits); i++ { if i != len(lits) { clauses.AddTaggedClause(tag, sat.Neg(auxs[i-1]), auxs[i], lits[i-1]) } else { clauses.AddTaggedClause(tag, sat.Neg(auxs[i-1]), lits[i-1]) } } clauses.AddTaggedClause(tag, auxs[0]) case Sort: panic("CNF translation for this type not implemented yet") default: panic("CNF translation for this type not implemented yet") } trans.Typ = typ trans.Clauses = clauses return }
func (pb *Threshold) CategorizeTranslate1() { pb.SortDescending() // per default all information that can be simplified will be in form of facts pb.Simplify() pb.TransTyp = Facts pb.Translated = true if len(pb.Entries) == 0 { //glob.D(pb.Id, "was simplified completely") } else { if b, literals := pb.Cardinality(); b { // glob.D("debug") // pb.Print10() if pb.K == int64(len(pb.Entries)-1) { switch pb.Typ { case LE: pb.Normalize(GE, true) for i, x := range literals { literals[i] = sat.Neg(x) } case GE: for i, x := range literals { literals[i] = sat.Neg(x) } pb.Normalize(LE, true) case EQ: for i, x := range literals { literals[i] = sat.Neg(x) } pb.Multiply(-1) pb.NormalizePositiveCoefficients() } } if pb.K == 1 { switch pb.Typ { case LE: // AMO if len(pb.Entries) == 2 { pb.Clauses.AddTaggedClause("Cls", sat.Neg(pb.Entries[0].Literal), sat.Neg(pb.Entries[1].Literal)) pb.TransTyp = Clause } else { trans := TranslateAtMostOne(Heule, "H_AMO", literals) pb.Clauses.AddClauseSet(trans.Clauses) pb.TransTyp = AMO } case GE: // its a clause! pb.Clauses.AddTaggedClause("Cls", literals...) pb.TransTyp = Clause case EQ: // Ex1 trans := TranslateExactlyOne(Heule, "H_EX1", literals) pb.Clauses.AddClauseSet(trans.Clauses) pb.TransTyp = EX1 } } else { pb.CreateCardinality() pb.TransTyp = CARD } } else { // treat equality as two constraints! if pb.Typ == EQ { glob.D(pb.Id, " decompose in >= amd <=") pbLE := pb.Copy() pbLE.Typ = LE pbGE := pb.Copy() pbGE.Typ = GE pbGE.Id = -pb.Id pbLE.TranslateComplexThreshold() pbGE.TranslateComplexThreshold() pb.Clauses.AddClauseSet(pbLE.Clauses) pb.Clauses.AddClauseSet(pbGE.Clauses) } else { pb.TranslateComplexThreshold() } } } return }