func (pb *Threshold) TranslateComplexThreshold() { glob.A(!pb.Empty(), "No Empty at this point.") glob.A(len(pb.Chains) == 0, "should not contain a chain") pb.Normalize(LE, true) pb.SortDescending() var err error switch *glob.Complex_flag { case "mdd": pb.Print10() pb.TranslateByMDD() if pb.Err != nil { panic(err.Error()) } glob.D(pb.Id, " mdd:", pb.Clauses.Size()) case "sn": pb.TranslateBySN() if pb.Err != nil { panic(err.Error()) } glob.D(pb.Id, " Complex, SN:", pb.Clauses.Size()) case "hybrid": tSN := pb.Copy() tMDD := pb.Copy() tSN.TranslateBySN() tMDD.TranslateByMDD() if tSN.Err != nil { panic(tSN.Err.Error()) } glob.D(pb.Id, "Complex, SN:", tSN.Clauses.Size(), " mdd:", tMDD.Clauses.Size()) if tMDD.Err == nil && tMDD.Clauses.Size() < tSN.Clauses.Size() { pb.Clauses.AddClauseSet(tMDD.Clauses) pb.TransTyp = CMDD } else { pb.Clauses.AddClauseSet(tSN.Clauses) pb.TransTyp = CSN } default: panic("Complex_flag option not available: " + *glob.Complex_flag) } glob.A(pb.Clauses.Size() > 0, pb.Id, " non-trivial pb should produce some clauses...") return }
// 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 }
// returns the encoding of this PB func (pb *Threshold) Translate(K_lessOffset int64) sat.ClauseSet { glob.A(pb.Positive(), "no negative coefficients beyond this point") K := K_lessOffset + pb.Offset if pb.SumWeights() <= K { glob.D("opt init ignored") return sat.ClauseSet{} } pb_K := pb.Copy() //removes all clauses ! pb_K.K = K pb_K.Typ = LE if len(pb_K.Chains) > 0 { pb_K.TranslateByMDDChain(pb_K.Chains) } else { pb_K.CategorizeTranslate1() } if pb_K.Err != nil { // case MDD construction did go wrong! glob.A(false, "Capacity of MDD reached, try to solve by not taking chains into account") pb_K := pb.Copy() //removes all clauses ! pb_K.K = K pb_K.Typ = LE pb_K.CategorizeTranslate1() } return pb_K.Clauses }
func TestTranslateAMO2(test *testing.T) { glob.D("TestTranslateAMO2") *glob.MDD_max_flag = 300000 *glob.MDD_redundant_flag = false results := []int{40, 33, 29} for i := 0; i < 3; i++ { //fmt.Println() pb1 := CreatePB([]int64{2, 2, 3, 4, 4, 5, 2, 1}, 8) pb2 := CreatePBOffset(i, []int64{1, 1, 1, 1}, 1) //pb1.Print10() //pb2.Print10() b, literals := pb2.Cardinality() amo := TranslateAtMostOne(Count, "c", literals) amo.PB = &pb2 TranslatePBwithAMO(&pb1, amo) //t.Clauses.PrintDebug() if !b || pb1.Clauses.Size() != results[i] { fmt.Println("translation size incorrect", pb1.Clauses.Size(), " should be", results[i]) //t.Clauses.PrintDebug() test.Fail() } } }
func TestTranslate(test *testing.T) { glob.D("TestTranslate") pb1 := CreatePB([]int64{1, 1, 1}, 1) pb1.CategorizeTranslate1() if pb1.TransTyp != AMO { pb1.Print10() test.Errorf("1: Does not classify atmostOne") } pb2 := CreatePB([]int64{1, 1, 1}, 1) pb2.Typ = GE pb2.CategorizeTranslate1() if pb2.TransTyp != Clause { pb2.Print10() test.Errorf("2: Does not classify a clause") } pb3 := CreatePB([]int64{1, 1, 1}, 1) pb3.Typ = EQ pb3.CategorizeTranslate1() if pb3.TransTyp != EX1 { pb3.Print10() test.Errorf("3: Does not classify ExactlyOne") } pb4 := CreatePB([]int64{1, 1, -1}, 0) pb4.Typ = EQ pb4.CategorizeTranslate1() if pb4.TransTyp != EX1 { pb4.Print10() test.Errorf("4: Does not classify ExactlyOne") } pb5 := CreatePB([]int64{-3, 3, -3}, 0) pb5.Typ = LE pb5.CategorizeTranslate1() if pb5.TransTyp != Clause { // should be different pb5.Print10() test.Errorf("5: Does not classify clause", pb5) } pb6 := CreatePB([]int64{1, 1, 1, 1, 1}, 4) pb6.Typ = EQ pb6.CategorizeTranslate1() if pb6.TransTyp != EX1 { test.Errorf("6: Does not classify ExactlyOne", pb6) } }
func TestRemoveZeros(test *testing.T) { glob.D("TestRemoveZeros") pb1 := CreatePB([]int64{1, 2, 3, 0, 321, 0, 0, -123, 0}, 1347) c := len(pb1.Entries) pb1.RemoveZeros() if len(pb1.Entries) != c-4 { test.Fail() } }
func doChaining(pbs []*Threshold, complOcc map[sat.Literal][]int, simplOcc map[sat.Literal][]int, lit2id map[sat.Literal]int, litSets []intsets.Sparse) { //2) Prepare Matchings checked := make(map[Match]bool, 0) //ex_matchings := make(map[int][]Matching, 0) // simpl_id -> []Matchings //currently ex and amo matchings are treated equivalently, the only //difference is that ex adds the unit clause of the ladder encoding, thus //the rewrite is correct and after UP the first value in the Ex is propagated. // TODO: explicitly rewrite and remove smallest value amo_matchings := make(map[int][]Matching, 0) // compl_id -> []Matchings for lit, list := range complOcc { //id2lit[lit2id[lit]] = lit for _, c := range list { for _, s := range simplOcc[lit] { if !checked[Match{c, s}] { // of comp c and simpl s there is at least checked[Match{c, s}] = true // 0 means it has not been checked, // as there is at least one intersection var inter intsets.Sparse inter.Intersection(&litSets[c], &litSets[s]) if pbs[s].Typ == LE { if inter.Len() >= *glob.Len_rewrite_amo_flag { amo_matchings[c] = append(amo_matchings[c], Matching{s, &inter}) } } else if pbs[s].Typ == EQ { if inter.Len() >= *glob.Len_rewrite_ex_flag { amo_matchings[c] = append(amo_matchings[c], Matching{s, &inter}) //ex_matchings[c] = append(amo_matchings[c], Matching{s, &inter}) } } else { glob.A(false, "case not treated") } } } } } glob.D("amo/ex_matchings:", len(amo_matchings)) //3) amo/ex matchings for comp, _ := range pbs { if matchings, b := amo_matchings[comp]; b { workOnMatching(pbs, comp, matchings, lit2id, litSets) } } }
func TestSNTranslation(test *testing.T) { glob.D("TestSortingNetworkTranslation") pb := createIgnasi2() pb.TranslateBySN() //filename := "test" //typ := sorters.Bubble //typ := sorters.Pairwise //typ := sorters.Bitonic //typ := sorters.OddEven //Example 1 //t := createCardinality(4, 15, 5) //t := createCardinality(2, 1, 1) //t := createCardinality(9, 1, 1) //Example 2 //t := createCardinality(8, 4, 1) //t := createCardinality(8,8,2) //t := createCardinality(8,16,4) //filename := "cardinality_8_16_4" //Example 3 //t := createCardinality(8,12,3) //filename := "cardinality_8_12_3" //Example 4 //t := createExample1() //filename := "example1" //Example 5 //t := createJapan1(80) //filename := "japan1_10" //Example 6 //t := createJapan2(3) //filename := "japan2_3" //t1 := createIgnasi1() //t2 := createIgnasi2() //s1 := NewSortingNetwork(t1) //s2 := NewSortingNetwork(t2) //fmt.Println(t) //PrintThresholdTikZ(filename+".tex", []SortingNetwork{s1, s2}) }
func (g *Gen) generateIds(cs ClauseSet, inferPrimeVars bool) { // recalculates new sat ids for each atom: // assuming full regeneration of Ids // might change existing mappings g.refresh() glob.D("c auxiliary Ids start with", g.nextId) for _, c := range cs.list { for _, l := range c.Literals { g.putAtom(l.A) } } }
func (pb *Threshold) Evaluate(a sat.Assignment) (r int64) { for _, e := range pb.Entries { v, b := a[e.Literal.A.Id()] glob.DT(!b, "Literal not found in assignment: ", e.Literal.ToTxt()) if e.Literal.Sign { r += int64(v) * e.Weight } else { r += (1 - int64(v)) * e.Weight } } glob.D("evaluate", r, pb.Offset) return r - pb.Offset }
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() } }
func TestMDDChains1(test *testing.T) { //glob.Debug_flag = true glob.D("TestMDDChains1") *glob.MDD_max_flag = 300000 *glob.MDD_redundant_flag = false var t Threshold t.Entries = createEntries([]int64{1, 2, 1, 1, 3, 1}) t.Typ = LE t.K = 5 //t.Print10() { // check store := mdd.InitIntervalMdd(len(t.Entries)) _, _, _, s1 := CreateMDD(&store, t.K, t.Entries) //store.Debug(true) if s1 != nil { test.Fail() } } chain := Chain(t.Literals()) //createLiterals(i, 3) //fmt.Println("\n\n Chain on index", i, i+3) chains := Chains{chain[0:3], chain[3:6]} //chains[0].Print() store := mdd.InitIntervalMdd(len(t.Entries)) _, _, _, s1 := CreateMDDChain(&store, t.K, t.Entries, chains) if s1 != nil { test.Fail() } if len(store.Nodes) != 6 { store.Debug(true) test.Fail() } //glob.Debug_flag = false }
func TestCleanChain(test *testing.T) { glob.D("TestCleanChain") pb := CreatePB([]int64{1, 2, 3, 0, 321, 0, 1, -123, 0}, 1347) results := []int{3, 3, 2, 0, 3, 0} chain := pb.Literals() pb.RemoveZeros() for i := 0; i < len(chain)-4; i++ { c1 := chain[i : i+4] c2 := CleanChain(pb.Entries, c1) if results[i] != len(c2) { fmt.Println(results[i], len(c2)) test.Fail() } } }
func TestMDDRedundant(test *testing.T) { //glob.Debug_flag = true //glob.Debug_flag = false glob.D("TestMDDRedundant") *glob.MDD_max_flag = 300000 *glob.MDD_redundant_flag = false var t Threshold t.Entries = createEntries([]int64{1, 2, 1, 1, 3, 1}) t.Typ = LE t.K = 5 store := mdd.InitIntervalMdd(len(t.Entries)) CreateMDD(&store, t.K, t.Entries) if store.RemoveRedundants() != 5 { test.Fail() } }
func TestMDDChains2(test *testing.T) { //glob.Debug_flag = true glob.D("TestMDDChains") *glob.MDD_max_flag = 300000 *glob.MDD_redundant_flag = false var t Threshold t.Entries = createEntries([]int64{1, 2, 1, 1, 3, 1, 3, 2, 1, 1, 1}) t.Typ = LE t.K = 10 //t.Print10() { // check store := mdd.InitIntervalMdd(len(t.Entries)) _, _, _, s1 := CreateMDD(&store, t.K, t.Entries) //store.Debug(true) if s1 != nil { test.Fail() } } chain := Chain(t.Literals()) //createLiterals(i, 3) chains := Chains{chain[1:3], chain[5:9]} store := mdd.InitIntervalMdd(len(t.Entries)) _, _, _, s1 := CreateMDDChain(&store, t.K, t.Entries, chains) if s1 != nil { test.Fail() } if len(store.Nodes) != 31 { store.Debug(true) test.Fail() } //glob.Debug_flag = false }
func TestRewriteExactly3(test *testing.T) { glob.D("TestExactly3") pb1 := CreatePB([]int64{2, 2, 3, 4, 1, 1}, 6) pb1.Typ = LE pb1.SortDescending() pb2 := CreatePB([]int64{1, 1, 1, 1}, 2) pb2.Typ = EQ //pb1.Print10() //pb2.Print10() b := PreprocessPBwithExactly(&pb1, &pb2) //pb1.Print10() //pb1.SortVar() //pb1.Print10() if !b && len(pb1.Entries) != 4 { test.Fail() } }
func TestRewriteExactly1(test *testing.T) { glob.D("TestExactly1") //+2 x1 +2 x2 +3 x3 +4 x4 +1 x5 +1 x6 <= 6 ; //+1 x1 +1 x2 +1 x3 +1 x4 = 1 ; pb1 := CreatePB([]int64{2, 2, 3, 4, 1, 1}, 6) pb1.Typ = LE pb2 := CreatePB([]int64{1, 1, 1, 1}, 1) pb2.Typ = EQ //pb1.Print10() //pb2.Print10() b := PreprocessPBwithExactly(&pb1, &pb2) if !b && len(pb1.Entries) != 4 { test.Fail() } //pb1.Print10() }
func TestTranslateAMO1(test *testing.T) { glob.D("TestTranslateAMO1") *glob.MDD_max_flag = 300000 *glob.MDD_redundant_flag = false pb1 := CreatePB([]int64{2, 2, 3, 4, 2, 3}, 6) pb2 := CreatePB([]int64{1, 1, 1, 1}, 1) //pb1.Print10() //pb2.Print10() //translate AMO, i.e. pb2 b, literals := pb2.Cardinality() amo := TranslateAtMostOne(Count, "c", literals) amo.PB = &pb2 TranslatePBwithAMO(&pb1, amo) if !b || pb1.Clauses.Size() != 13 { fmt.Println("translation size incorrect", pb1.Clauses.Size(), "should be:", 13) pb1.Clauses.PrintDebug() test.Fail() } }
func TestRewriteAMO(test *testing.T) { glob.D("TestRewriteAMO1") pb1 := CreatePB([]int64{2, 2, 3, 4, 1, 1}, 6) pb2 := CreatePB([]int64{1, 1, 1, 1}, 1) //pb1.Print10() //pb2.Print10() //translate AMO, i.e. pb2 b, literals := pb2.Cardinality() amo := TranslateAtMostOne(Count, "count", literals) amo.PB = &pb2 b = PreprocessPBwithAMO(&pb1, amo) if !b || len(pb1.Entries) != 5 { test.Fail() } if sumE(pb1) != 6 { test.Fail() } }
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 (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 }
func (g *Gen) Solve(cs ClauseSet, opt Optimizer, nextOpt int64, lb int64) (result Result) { glob.A(cs.Size() > 0, "Needs to contain at least 1 clause.") //generate the reverse mapping result_chan := make(chan rawResult) timeout := make(chan bool, 1) go func() { time.Sleep(time.Duration(*glob.Timeout_flag) * time.Second) timeout <- true }() finished := false current := cs result.Value = math.MaxInt64 if !opt.Empty() && nextOpt != math.MaxInt64 { glob.D("init", nextOpt, "lb", lb) opt_clauses := opt.Translate(nextOpt) fmt.Println("opt cls", opt_clauses.Size()) current.AddClauseSet(opt_clauses) } result.Value = math.MaxInt64 result.Assignment = make(Assignment, len(g.idMap)) time_total := time.Now() iterations := 0 for !finished { iterations++ //glob.D("Writing", current.Size(), "clauses") fmt.Println("tot cls", current.Size()) //current.PrintDebug() if opt.Empty() { glob.D("solving...") } else { fmt.Printf("i: %v\tcur: %v\t lb: %v\tbest: %v\n", iterations, maxS(nextOpt), lb, maxS(result.Value)) } time_before := time.Now() if *glob.Cnf_tmp_flag != "" { g.PrintDIMACS(current, false) } go g.solveProblem(current, result_chan) select { case r := <-result_chan: result.Solved = r.solved fmt.Printf("Time :\t%.3f s\n", time.Since(time_before).Seconds()) if r.solved { if r.satisfiable { result.Satisfiable = true ss := strings.Split(strings.TrimSpace(r.assignment), " ") count := 0 for _, x := range ss { x = strings.TrimSpace(x) if x == "" { continue } id, err := strconv.Atoi(x) if err != nil { glob.A(false, err.Error()) } if id != 0 { sign := 1 if id < 0 { sign = 0 id = -id } atom := g.idMap[id] if g.PrimaryVars[atom.Id()] { count++ result.Assignment[atom.Id()] = sign } } } glob.A(count == len(result.Assignment), "count != assignment") if !opt.Empty() { result.Value = opt.Evaluate(result.Assignment) g.printAssignment(result.Assignment) glob.D("SAT for value =", result.Value) finished, nextOpt = nextOptValue(lb, &result) if !finished { current = cs opt_clauses := opt.Translate(nextOpt) fmt.Println("opt cls", opt_clauses.Size()) current.AddClauseSet(opt_clauses) } else { fmt.Println("OPTIMIUM", result.Value) } } else { fmt.Println("SAT") result.M = "SAT" finished = true } } else { //UNSAT if !opt.Empty() { // update lower bound glob.D("UNSAT for opt <=", maxS(nextOpt)) if nextOpt == math.MaxInt64 { result.M = "UNSAT" finished = true } else { lb = nextOpt + 1 finished, nextOpt = nextOptValue(lb, &result) if !finished { current = cs opt_clauses := opt.Translate(nextOpt) fmt.Println("opt cls", opt_clauses.Size()) current.AddClauseSet(opt_clauses) } else { fmt.Println("OPTIMUM", result.Value) } } } else { finished = true result.Optimal = true result.M = "UNSAT" } } } else { result.Solved = false glob.D("Error received nothing solved, check log of solver?") result.M = "ERROR" finished = true } case <-timeout: fmt.Println("TIMEOUT") result.M = "TIMEOUT" finished = true result.Solved = false result.Timeout = true } } close(result_chan) close(timeout) // fmt.Printf("cTIME: %.3f s\n", time.Since(time_total).Seconds()) // fmt.Printf("%v;%v;%v;%v;%v;%v;%v;%.2f;%v;%v;%v\n", "name", "seed", "Amo_chain", "Amo_reuse", "Rewrite_same", "result.M", "maxS(result.Value)", "time ins", "iterations", "cs.Size()", "current.Size()-cs.Size()") // fmt.Printf("%v;%v;%v;%v;%v;%v;%v;%.2f;%v;%v;%v\n", *glob.Filename_flag, *glob.Seed_flag, *glob.Amo_chain_flag, *glob.Amo_reuse_flag, *glob.Rewrite_same_flag, result.M, maxS(result.Value), time.Since(time_total).Seconds(), iterations, cs.Size(), current.Size()-cs.Size()) fmt.Printf("%v;%v;%v;%.2f\n", *glob.Filename_flag, result.M, maxS(result.Value), time.Since(time_total).Seconds()) return }
// TODO : set seed func (g *Gen) solveProblem(clauses ClauseSet, result chan<- rawResult) { var solver *exec.Cmd switch *glob.Solver_flag { case "minisat": //solver = exec.Command("minisat", "-rnd-seed=123") //solver = exec.Command("minisat", "-rnd-seed="+strconv.FormatInt(*glob.Seed_flag, 10)) solver = exec.Command("minisat") case "glucose": solver = exec.Command("glucose", "-model") case "clasp": solver = exec.Command("clasp") case "lingeling": solver = exec.Command("lingeling") case "treengeling": solver = exec.Command("treengeling") case "plingeling": solver = exec.Command("plingeling") case "dimetheus": solver = exec.Command("dimetheus", "-seed="+strconv.FormatInt(*glob.Seed_flag, 10)) case "cmsat": solver = exec.Command("cmsat") case "local": solver = exec.Command("CCAnr", strconv.FormatInt(*glob.Seed_flag, 10)) case "microsat": solver = exec.Command("microsat") default: glob.A(false, "Solver not available", *glob.Solver_flag) } stdin, err := solver.StdinPipe() if err != nil { panic(err) } stdout, err := solver.StdoutPipe() if err != nil { panic(err) } err = solver.Start() if err != nil { panic(err) } var wg sync.WaitGroup wg.Add(2) go func() { time_before := time.Now() defer stdin.Close() defer wg.Done() g.generateIds(clauses, false) io.Copy(stdin, bytes.NewReader([]byte(fmt.Sprintf("p cnf %v %v\n", g.nextId, len(clauses.list))))) for _, c := range clauses.list { io.Copy(stdin, bytes.NewReader(g.toBytes(c))) } fmt.Printf("Read :\t%.3f s\n", time.Since(time_before).Seconds()) }() var res rawResult go func() { defer wg.Done() r := bufio.NewReader(stdout) s, err := r.ReadString('\n') //fmt.Print(s) for { if strings.HasPrefix(s, "v ") { res.assignment += s[1:] } else if strings.HasPrefix(s, "s ") { if strings.Contains(s, "UNSATISFIABLE") { res.solved = true res.satisfiable = false } else if strings.Contains(s, "SATISFIABLE") { res.solved = true res.satisfiable = true } else { res.solved = false glob.D("whats up? Result of sat solver does not contain proper answer!") } } s, err = r.ReadString('\n') // fmt.Print(s) if err == io.EOF { break } if err != nil { panic(err.Error()) } } }() wg.Wait() err_tmp := solver.Wait() if err_tmp != nil { //glob.D("return value:",err_tmp() ) } // TODO: why is this uncommented? //if err = solver.Process.Kill(); err != nil { // panic(err.Error()) //} result <- res }
func TestAtMostOne(test *testing.T) { glob.D("TestTranslateAtMostOne") k := 6 lits := make([]sat.Literal, k) atoms := make(map[string]bool) for i, _ := range lits { lits[i] = sat.Literal{true, sat.NewAtomP1(sat.Pred("x"), i)} atoms[lits[i].A.Id()] = true } t := TranslateAtMostOne(Naive, "naive", lits) if t.Clauses.Size() == 0 { test.Fail() } t = TranslateAtMostOne(Split, "split", lits) if t.Clauses.Size() == 0 { test.Fail() } // t = TranslateAtMostOne(Sort, "sorter", lits) // if t.Clauses.Size() == 0 { // test.Fail() // } t = TranslateAtMostOne(Heule, "heule", lits) if t.Clauses.Size() == 0 { test.Fail() } t = TranslateAtMostOne(Log, "Log", lits) if t.Clauses.Size() == 0 { test.Fail() } //fmt.Println() t = TranslateAtMostOne(Count, "counter", lits) if t.Clauses.Size() == 0 { test.Fail() } //t.Clauses.PrintDebug() //g := sat.IdGenerator(t.Clauses.Size() * 7) //g.Filename = "out.cnf" //g.PrimaryVars = atoms //g.Solve(t.Clauses) //g.PrintSymbolTable("sym.txt") //fmt.Println() t = TranslateExactlyOne(Naive, "naive", lits) if t.Clauses.Size() == 0 { test.Fail() } t = TranslateExactlyOne(Split, "split", lits) if t.Clauses.Size() == 0 { test.Fail() } t = TranslateExactlyOne(Count, "counter", lits) if t.Clauses.Size() == 0 { test.Fail() } //t = TranslateExactlyOne(Sort, "sorter", lits) //if t.Clauses.Size() == 0 { // test.Fail() //} t = TranslateExactlyOne(Heule, "heule", lits) if t.Clauses.Size() == 0 { test.Fail() } t = TranslateExactlyOne(Log, "Log", lits) if t.Clauses.Size() == 0 { test.Fail() } }
func CategorizeTranslate2(pbs []*Threshold) { //1) Categorize simplOcc := make(map[sat.Literal][]int, len(pbs)) // literal to list of simplifiers it occurs in complOcc := make(map[sat.Literal][]int, len(pbs)) // literal to list of complex pbs it occurs in litSets := make([]intsets.Sparse, len(pbs)) // pb.Id -> intsSet of literalIds nextId := 0 lit2id := make(map[sat.Literal]int, 0) // literal to its id for i, pb := range pbs { if pb.Empty() { glob.D("pb is empty. pb.Id:", pb.Id) continue } pb.Normalize(LE, true) pb.SortVar() pb.CatSimpl() switch pb.TransTyp { case UNKNOWN: addToCategory(&nextId, pb, complOcc, lit2id, &litSets[i]) case AMO, EX1: //fmt.Println(pb.Id, len(pbs)) //pb.Print10() addToCategory(&nextId, pb, simplOcc, lit2id, &litSets[i]) default: // already translated glob.DT(pb.Clauses.Size() == 0, "Translated pb should contain clauses, special case?", pb.Id) pb.Translated = true } } if *glob.Amo_chain_flag || *glob.Ex_chain_flag { doChaining(pbs, complOcc, simplOcc, lit2id, litSets) } for _, pb := range pbs { if pb.IsComplexTranslation() { sort.Sort(EntriesDescending(pb.Entries[pb.PosAfterChains():])) if *glob.Rewrite_same_flag { pb.RewriteSameWeights() //glob.D("rewrite same weights:", pb.Id, len(pb.Chains)) } //pb.Print10() if pb.Typ != OPT && len(pb.Chains) > 0 { //TODO: decide on what to use ... pb.TranslateByMDDChain(pb.Chains) //pbTMP := pb.Copy() //pbTMP.Chains = nil //pbTMP.TranslateBySN() //pb.Clauses = pbTMP.Clauses pb.Translated = true } } if !pb.Translated && pb.Typ != OPT { glob.A(len(pb.Chains) == 0, "At this point no chain.", pb) //glob.A(pb.Clauses.Size() == 0, pb.Id, pb, "not translation means also that there should not be any clauses.") pb.CategorizeTranslate1() pb.Translated = true } if pb.Err != nil { panic(pb.Err.Error()) } //pb.Print10() } }
// returns list of *pb; first one is optimization statement, possibly empty func parse(filename string) (pbs []*constraints.Threshold, err error) { input, err2 := os.Open(filename) defer input.Close() if err2 != nil { err = errors.New("Please specify correct path to instance. Does not exist") return } scanner := bufio.NewScanner(input) buf := make([]byte, 0, 64*1024) scanner.Buffer(buf, 1024*1024) // 0 : first line, 1 : rest of the lines var count int state := 1 t := 0 pbs = make([]*constraints.Threshold, 0) for scanner.Scan() { l := strings.Trim(scanner.Text(), " ") if l == "" || strings.HasPrefix(l, "%") || strings.HasPrefix(l, "*") { continue } elements := strings.Fields(l) if len(elements) == 1 { // quick hack to ignore single element lines (not necessary) continue } switch state { case 0: // deprecated: for parsing the "header" of pb files, now parser is flexible { glob.D(l) var b1 error count, b1 = strconv.Atoi(elements[4]) vars, b2 := strconv.Atoi(elements[2]) if b1 != nil || b2 != nil { glob.D("cant convert to threshold:", l) panic("bad conversion of numbers") } glob.D("File PB file with", count, "constraints and", vars, "variables") state = 1 } case 1: { var n int // number of entries var f int // index of entry var o bool //optimization var pb constraints.Threshold offset_back := 0 if elements[len(elements)-1] != ";" { offset_back = 1 } if elements[0] == "min:" || elements[0] == "Min" { o = true n = (len(elements) + offset_back - 2) / 2 f = 1 } else { o = false n = (len(elements) + offset_back - 3) / 2 f = 0 } pb.Entries = make([]constraints.Entry, n) for i := f; i < 2*n; i++ { weight, b1 := strconv.ParseInt(elements[i], 10, 64) i++ if b1 != nil { glob.D("cant convert to threshold:", elements[i], "\nin PB\n", l) panic("bad conversion of numbers") } atom := sat.NewAtomP(sat.Pred(elements[i])) pb.Entries[(i-f)/2] = constraints.Entry{sat.Literal{true, atom}, weight} } // fake empty opt in case it does not exist if t == 0 && !o { pbs = append(pbs, &constraints.Threshold{}) t++ } pb.Id = t if o { pb.Typ = constraints.OPT glob.D("Scanned optimization statement") } else { pb.K, err = strconv.ParseInt(elements[len(elements)-2+offset_back], 10, 64) if err != nil { glob.A(false, " cant parse threshold, error", err.Error(), pb.K) } typS := elements[len(elements)-3+offset_back] if typS == ">=" { pb.Typ = constraints.GE } else if typS == "<=" { pb.Typ = constraints.LE } else if typS == "==" || typS == "=" { pb.Typ = constraints.EQ } else { glob.A(false, "cant convert to threshold, equationtype typS:", typS) } } pbs = append(pbs, &pb) t++ //fmt.Println(pb.Id) //pb.Print10() } } } glob.A(len(pbs) == t, "Id of constraint must correspond to position") glob.D("Scanned", t-1, "PB constraints.") if len(pbs) > 0 && !pbs[0].Empty() { glob.D("Scanned OPT statement.") } return }
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 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) }