func main() { glob.Init() if *glob.Ver { fmt.Println(`Bule CNF Grounder: Tag 0.97 Pseudo Booleans Copyright (C) Data61 and Valentin Mayer-Eichberger License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> There is NO WARRANTY, to the extent permitted by law.`) return } if len(flag.Args()) >= 2 { fmt.Println("Command line flags not recognized", flag.Args()) return } if len(flag.Args()) == 1 { *glob.Filename_flag = flag.Args()[0] } if *glob.Debug_filename != "" { var err error glob.Debug_file, err = os.Create(*glob.Debug_filename) if err != nil { panic(err) } defer glob.Debug_file.Close() } glob.D("Running Debug Mode...") problem := parser.New(*glob.Filename_flag) if *glob.Pbo_flag { problem.PrintPBO() return } if *glob.Gringo_flag { problem.PrintGringo() return } if *glob.Gurobi_flag { problem.PrintGurobi() return } pbs := problem.Pbs[1:] // opt is just a pointer to first in pbs. opt := problem.Opt primaryVars := make(map[string]bool, 0) for i, _ := range pbs { for _, x := range pbs[i].Entries { primaryVars[x.Literal.A.Id()] = true } } var clauses sat.ClauseSet // Categorize Version 1 (deprecated) switch *glob.Cat_flag { case 1: { for _, pb := range pbs { pb.Print10() pb.CategorizeTranslate1() clauses.AddClauseSet(pb.Clauses) } } case 2: { constraints.CategorizeTranslate2(pbs) for _, pb := range pbs { clauses.AddClauseSet(pb.Clauses) } } default: panic("Category not implemented") } if *glob.Dimacs_flag { clauses.PrintDebug() } if *glob.Solve_flag { g := sat.IdGenerator(clauses.Size()*7 + 1) g.PrimaryVars = primaryVars opt.NormalizePositiveCoefficients() opt.Offset = opt.K glob.A(opt.Positive(), "opt only has positive coefficients") g.Solve(clauses, opt, *glob.Opt_bound_flag, -opt.Offset) //fmt.Println() } }
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 printSAT(tasks []Task, workers []Worker) { pAssign := sat.Pred("assign") pWorks := sat.Pred("works") sat.SetUp(4, sorters.Pairwise) var clauses sat.ClauseSet // at least one: simple clause for _, t := range tasks { lits := make([]sat.Literal, len(t.worker)) i := 0 for wId, _ := range t.worker { lits[i] = sat.Literal{true, sat.Atom{pAssign, wId, t.id}} i++ } clauses.AddClause("al1", lits...) clauses.AddClauseSet(sat.CreateCardinality("am1", lits, 1, sorters.AtMost)) } // count number of employees for _, w := range workers { for _, tId := range w.skills { l1 := sat.Literal{false, sat.Atom{pAssign, w.id, tId}} l2 := sat.Literal{true, sat.Atom{pWorks, w.id, 0}} clauses.AddClause("wrk", l1, l2) } } lits := make([]sat.Literal, len(workers)) for i, w := range workers { lits[i] = sat.Literal{true, sat.Atom{pWorks, w.id, 0}} } clauses.AddClauseSet(sat.CreateCardinality("cWo", lits, *nWorkers, sorters.AtMost)) // intersections on the timeline: two ways to do it // 1) list all intersecting tasks // 2) find maximal cliques in the interval graph, and post for that for _, w := range workers { ts := make([]Task, len(w.skills)) for i, s := range w.skills { ts[i] = tasks[s] } sort.Sort(ByStart(ts)) switch *typeIntersect { case "simple": for i, t1 := range ts { for j := i + 1; j < len(ts); j++ { t2 := ts[j] if t2.start < t1.end { l1 := sat.Literal{false, sat.Atom{pAssign, w.id, t1.id}} l2 := sat.Literal{false, sat.Atom{pAssign, w.id, t2.id}} clauses.AddClause("isc1", l1, l2) } } } case "clique": // find the maximal cliques in the interval graph and pose AMO on them clique := make([]Task, 0) for _, t := range ts { sort.Sort(ByEnd(clique)) //todo: use a priority queue, e.g. heap //first one is earliest end time if len(clique) > 0 && clique[0].end <= t.start { // max clique reached //output the maximal clique! if len(clique) > 1 { lits := make([]sat.Literal, len(clique)) for i, c := range clique { lits[i] = sat.Literal{true, sat.Atom{pAssign, w.id, c.id}} fmt.Print(c.id, "(", c.start, ",", c.end, ") ") } fmt.Println() //fmt.Println("clique", w.id, lits) clauses.AddClauseSet(sat.CreateCardinality("cli", lits, 1, sorters.AtMost)) } //start removing elements: for len(clique) > 0 && clique[0].end <= t.start { clique = clique[1:] } } clique = append(clique, t) } if len(clique) > 1 { lits := make([]sat.Literal, len(clique)) for i, c := range clique { lits[i] = sat.Literal{true, sat.Atom{pAssign, w.id, c.id}} } //fmt.Println("clique", w.id, lits) clauses.AddClauseSet(sat.CreateCardinality("cli", lits, 1, sorters.AtMost)) } default: panic("Type not implemented") } } g := sat.IdGenerator(len(clauses) * 7) g.GenerateIds(clauses) //g.Filename = strings.Split(*f, ".")[0] + ".cnf" //g.Filename = *out if *dbg { g.PrintDebug(clauses) } else { g.PrintClausesDIMACS(clauses) } }
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 }