// chains must be in order of pb and be subsets of its literals func (pb *Threshold) TranslateByMDDChain(chains Chains) { glob.A(!pb.Empty(), pb.Id, "works only for non-empty mdds") glob.A(pb.Positive(), pb.Id, "Weights need to be positive") glob.A(pb.Typ == LE, pb.Id, "works only on LE, but is", pb.Typ, pb.String()) if len(chains) == 0 { pb.TransTyp = CMDD } else { pb.TransTyp = CMDDC } store := mdd.InitIntervalMdd(len(pb.Entries)) topId, _, _, err := CreateMDDChain(&store, pb.K, pb.Entries, chains) store.Top = topId //store.Debug(true) if err != nil { pb.Err = err return } if *glob.MDD_redundant_flag { store.RemoveRedundants() //glob.D("remove redundant nodes in MDD", removed) } pb.Clauses.AddClauseSet(convertMDD2Clauses(store, pb)) }
// 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 }
// finds the subexpression of chain1 in e and // returns the entries of chain1 existing in e. func CleanChain(entries []Entry, chain1 Chain) (chain2 Chain) { glob.A(len(chain1) > 0, "no non-empty chains") chain2 = make(Chain, len(chain1)) e := 0 // find start of chain for i, x := range entries { if x.Literal == chain1[0] { e = i break } glob.A(i <= len(entries)-1, "chain must exist within entries") } j2 := 0 for j1, l := range chain1 { //fmt.Println("e", e, "j1", j1, "j2", j2) if e+j2 == len(entries) { break } if l == entries[e+j2].Literal { chain2[j2] = chain1[j1] j2++ } } return chain2[:j2] }
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 }
func (pb *Threshold) TranslateBySN() { pb.TransTyp = CSN pb.Normalize(LE, true) glob.A(pb.Typ == LE, "does not work on OPT or ==, but we have", pb.Typ) pb.SortDescending() sn := NewSortingNetwork(*pb) sn.CreateSorter() //glob.D("size of comparators", len(sn.Sorter.Comparators)) //PrintThresholdTikZ("sn.tex", []SortingNetwork{sn}) wh := 1 var which [8]bool switch wh { case 1: which = [8]bool{false, false, false, true, true, true, false, false} case 2: which = [8]bool{false, false, false, true, true, true, false, true} case 3: which = [8]bool{false, true, true, true, true, true, true, false} case 4: which = [8]bool{false, true, true, true, true, true, true, true} } pred := sat.Pred("auxSN_" + strconv.Itoa(pb.Id)) pb.Clauses.AddClauseSet(CreateEncoding(sn.LitIn, which, []sat.Literal{}, "BnB", pred, sn.Sorter)) }
// returns if preprocessing was successful // Uses the translation of pb2 (count translation) func PreprocessPBwithAMO(pb *Threshold, amo CardTranslation) bool { //assumptions: //check for correct property of pb2 //check for overlap of literals //both pb1 and amo are in the same ordering glob.A(amo.PB != nil, "amo PB pointer is not set correctly!") b, es := CommonSlice(pb.Entries, amo.PB.Entries) //fmt.Println(amo.PB.Entries, es) if !b { panic("Check if amo fits with the pb1") } last := int64(0) for i, e := range es { es[i].Weight = e.Weight - last es[i].Literal = amo.Aux[i] last = e.Weight } pb.RemoveZeros() return true }
// all weights are the same; performs rounding // if this is true, then all weights are 1, and K is the cardinality func (t *Threshold) Cardinality() (allSame bool, literals []sat.Literal) { glob.A(len(t.Chains) == 0, "cant reorder Entries with chains") t.NormalizePositiveCoefficients() allSame = true coeff := t.Entries[0].Weight for _, x := range t.Entries { if x.Weight != coeff { allSame = false break } } if allSame { literals = make([]sat.Literal, len(t.Entries)) /// was ceil before, what happened here? t.K = int64(math.Floor(float64(t.K) / float64(coeff))) for i, x := range t.Entries { t.Entries[i].Weight = 1 literals[i] = x.Literal } } return allSame, literals }
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 } } }
func nextOptIterative(lb int64, result *Result) (bool, int64) { if lb == result.Value { result.M = "OPTIMUM" return true, result.Value } else if lb < result.Value { return false, result.Value - 1 } else { glob.A(false, "lb <= ub") return false, 0 } }
func nextOptValue(lb int64, result *Result) (finished bool, nextOpt int64) { switch *glob.Search_strategy_flag { case "iterative": finished, nextOpt = nextOptIterative(lb, result) case "binary": finished, nextOpt = nextOptBinary(lb, result) default: glob.A(false, "Search strategy not implemented", *glob.Search_strategy_flag) } return }
func (pb *Threshold) PosAfterChains() int { current := 0 for _, chain := range pb.Chains { for _, lit := range chain { glob.A(pb.Entries[current].Literal == lit, "chain is not aligned with PB", chain, pb) current++ } } return current }
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 nextOptBinary(lb int64, result *Result) (bool, int64) { if lb == result.Value { result.M = "OPTIMUM" return true, result.Value } else if lb < result.Value { return false, (lb + result.Value) / 2 } else { glob.A(false, "lb <= ub") return false, 0 } }
// normalizes the threshold // Change EquationType in case of LE/GE // in case of EQ and OPT, positive weights func (t *Threshold) Normalize(typ EquationType, posWeights bool) { glob.A(len(t.Chains) == 0, "cant reorder Entries with chains") if (typ == LE && t.Typ == GE) || (typ == GE && t.Typ == LE) { t.Multiply(-1) } if posWeights { t.NormalizePositiveCoefficients() } else { t.NormalizePositiveLiterals() } return }
func (mddStore *IntervalMddStore) Insert(n IntervalNode) (id int) { //check code start TODO: remove for performance if a := mddStore.storage.Get(n); a != nil { fmt.Println("FAIL") printNode(a.(IntervalNode)) panic("node should not exist") } //check code end n.Id = mddStore.NextId mddStore.Nodes = append(mddStore.Nodes, &n) mddStore.NextId++ glob.A(mddStore.NextId == len(mddStore.Nodes), "nextId calculation and length of Nodes list is wrong") mddStore.storage.Insert(n) return n.Id }
func printStats(stats []int) { glob.A(len(stats) == int(constraints.TranslationTypes), "Stats for translation errornous") trans := constraints.Facts fmt.Print("Name;") for i := trans; i < constraints.TranslationTypes; i++ { if i > 0 { fmt.Printf("%v;", constraints.TranslationType(i)) } } fmt.Println() fmt.Print(*glob.Filename_flag, ";") for i := trans; i < constraints.TranslationTypes; i++ { if i > 0 { fmt.Printf("%v;", stats[i]) } } fmt.Println() }
func (g *Gen) putAtom(a Atom) { if _, b := g.mapping[a.Id()]; !b { succ := false if *glob.Infer_var_ids { id, err := strconv.Atoi(strings.TrimLeft(a.Id(), "v")) v := strings.TrimRight(a.Id(), "0123456789") if v == "v" && err == nil { glob.A(*glob.First_aux_id_flag > id, "Inferred number ID if higher than First_aux_id. Use values for first_aux that a larger than id in all variables v<id>.") succ = true g.mapping[a.Id()] = id g.idMap[id] = a } } if !succ { g.nextId++ g.mapping[a.Id()] = g.nextId g.idMap = append(g.idMap, a) } } }
// CreateCardinality takes set of literals and creates a sorting network func (pb *Threshold) CreateCardinality() { for _, x := range pb.Entries { glob.A(x.Weight == 1, "Prerequisite for this translation") } literals := pb.Literals() sx := strconv.Itoa(int(pb.K)) + "\\" + strconv.Itoa(len(literals)) var s string var sorterEqTyp sorters.EquationType var w int // which type of clauses switch pb.Typ { case LE: w = 0 sorterEqTyp = sorters.AtMost s = pb.IdS() + "pb<SN" + sx case GE: w = 3 sorterEqTyp = sorters.AtLeast s = pb.IdS() + "pb>SN" + sx case EQ: w = 3 s = pb.IdS() + "pb=SN" + sx sorterEqTyp = sorters.Equal default: panic("Not supported") } sorter := sorters.CreateCardinalityNetwork(len(literals), int(pb.K), sorterEqTyp, sorters.Pairwise) sorter.RemoveOutput() pred := sat.Pred("SN-" + pb.IdS()) output := make([]sat.Literal, 0) pb.Clauses.AddClauseSet(CreateEncoding(literals, sorters.WhichCls(w), output, s, pred, sorter)) }
func workOnMatching(pbs []*Threshold, comp int, matchings []Matching, lit2id map[sat.Literal]int, litSets []intsets.Sparse) { glob.A(!pbs[comp].Translated, "comp", comp, "should not have been translated yet") var chains Chains //inter := &intsets.Sparse{} var comp_offset int // the new first position of Entries in comp if !*glob.Amo_reuse_flag { //fmt.Println("before remove translated matches: len", len(matchings)) // remove translated ones... p := len(matchings) for i := 0; i < p; i++ { // find the next non-translated one if pbs[matchings[i].simp].Translated { p-- matchings[i] = matchings[p] i-- } } matchings = matchings[:p] //fmt.Println("after removing translated matches: len", len(matchings)) } for len(matchings) > 0 { //fmt.Println("len(matchings", len(matchings)) sort.Sort(MatchingsBySize(matchings)) matching := matchings[0] //glob.D(comp, matching.simp, matching.inter.Len()) // choose longest matching, that is not translated yet //fmt.Println("check matching: simp", matching.simp, "inter", matching.inter.String()) //matching.inter.IntersectionWith(&litSets[comp]) //update matching if matching.inter.Len() < *glob.Len_rewrite_amo_flag { break } inter := matching.inter simp := matching.simp //pbs[comp].Print10() //pbs[simp].Print10() //glob.D("entries", comp, litSets[comp].String(), simp, litSets[simp].String(), inter.String()) ind_entries := make(IndEntries, inter.Len()) comp_rest := make([]*Entry, len(pbs[comp].Entries)-inter.Len()-comp_offset) simp_rest := make([]*Entry, len(pbs[simp].Entries)-inter.Len()) simp_offset := len(simp_rest) ind_pos := 0 rest_pos := 0 for i := comp_offset; i < len(pbs[comp].Entries); i++ { if inter.Has(lit2id[pbs[comp].Entries[i].Literal]) { ind_entries[ind_pos].c = &pbs[comp].Entries[i] ind_pos++ } else { comp_rest[rest_pos] = &pbs[comp].Entries[i] rest_pos++ } } ind_pos = 0 rest_pos = 0 for i, x := range pbs[simp].Entries { if inter.Has(lit2id[x.Literal]) { ind_entries[ind_pos].s = &pbs[simp].Entries[i] ind_pos++ } else { simp_rest[rest_pos] = &pbs[simp].Entries[i] rest_pos++ } } //fmt.Println("intersection of", litSets[comp].String(), litSets[simp].String()) //fmt.Println("intersection", inter.String(), " len:", inter.Len()) litSets[comp].DifferenceWith(inter) { // remove intersecting matchings //fmt.Println("before remove intersecting matches: len", len(matchings)) p := len(matchings) for i := 1; i < p; i++ { // find the next non-translated one //var tmp intsets.Sparse // glob.D("before", matchings[i].inter.String()) // glob.D("inter", inter.String()) matchings[i].inter.DifferenceWith(inter) // glob.D("after ", matchings[i].inter.String()) //if tmp.Intersection(inter, matchings[i].inter); !tmp.IsEmpty() { if matchings[i].inter.IsEmpty() { // fmt.Println("remove", matchings[i].inter.String()) p-- matchings[i] = matchings[p] i-- } } matchings = matchings[1:p] //fmt.Println("after removing intersecting matches: len", len(matchings)) } sort.Sort(ind_entries) compEntries := make([]Entry, len(pbs[comp].Entries)) simpEntries := make([]Entry, len(pbs[simp].Entries)) // fill the compEntries and simpEntries copy(compEntries, pbs[comp].Entries[:comp_offset]) for i, ie := range ind_entries { glob.A(ie.c.Literal == ie.s.Literal, "Indicator entries should be aligned but", ie.c.Literal, ie.s.Literal) compEntries[i+comp_offset] = *ie.c simpEntries[i+simp_offset] = *ie.s } for i, _ := range comp_rest { compEntries[comp_offset+len(ind_entries)+i] = *comp_rest[i] } for i, _ := range simp_rest { simpEntries[i] = *simp_rest[i] } pbs[comp].Entries = compEntries pbs[simp].Entries = simpEntries var simp_translation CardTranslation if pbs[simp].Typ == EQ { simp_translation = TranslateExactlyOne(Count, pbs[simp].IdS()+"-cnt", pbs[simp].Literals()) } else { glob.A(pbs[simp].Typ == LE) simp_translation = TranslateAtMostOne(Count, pbs[simp].IdS()+"-cnt", pbs[simp].Literals()) } //simp_translation := TranslateAtMostOne(Count, pbs[simp].IdS()+"-cnt", pbs[simp].Literals()) pbs[simp].Translated = true pbs[simp].Clauses.AddClauseSet(simp_translation.Clauses) simp_translation.PB = pbs[simp] // replaces entries with auxiliaries of the AMO last := int64(0) for i, _ := range ind_entries { tmp := compEntries[i+comp_offset].Weight compEntries[i+comp_offset].Weight -= last glob.A(compEntries[i+comp_offset].Weight >= 0, "After rewriting PB weights cannot be negative") compEntries[i+comp_offset].Literal = simp_translation.Aux[i+simp_offset] last = tmp } pbs[comp].RemoveZeros() chain := CleanChain(pbs[comp].Entries, simp_translation.Aux[simp_offset:]) //pbs[comp].Print10() //pbs[simp].Print10() //glob.D(len(chain)) //glob.D(Chain(simp_translation.Aux)) glob.A(len(chain) > 0, "chain has to have at least one element") comp_offset += len(chain) chains = append(chains, chain) //fmt.Println("chain:") //fmt.Println("rewritten:") pbs[simp].SortVar() // for reuse of other constraints } pbs[comp].Chains = chains }
func (t *SortingNetwork) CreateSorter() { glob.A(!t.pb.Empty(), "No empty at this point.") t.CreateBags() layers := make([]sorters.Sorter, len(t.Bags)) for i, bag := range t.Bags { layers[i] = sorters.CreateSortingNetwork(len(bag), -1, t.typ) t.LitIn = append(t.LitIn, bag...) } t.Sorter.In = make([]int, 0, len(t.LitIn)) t.Sorter.Out = make([]int, 0, len(t.LitIn)) offset := 2 // determine the constant and what to add on both sides layerPow2 := int64(1 << uint(len(t.Bags))) tare := layerPow2 - ((t.pb.K + 1) % layerPow2) tare = tare % layerPow2 t.Tare = tare bTare := Binary(tare) // output of sorter in layer $i-1$ bIn := make([]int, 0) finalMapping := make(map[int]int, len(t.Sorter.In)) for i, layer := range layers { offset = layer.Normalize(offset, []int{}) t.Sorter.Comparators = append(t.Sorter.Comparators, layer.Comparators...) t.Sorter.In = append(t.Sorter.In, layer.In...) size := len(bIn) + len(layers[i].In) mergeIn := make([]int, 0, size) mergeIn = append(mergeIn, bIn...) mergeIn = append(mergeIn, layer.Out...) merger := sorters.CreateSortingNetwork(size, len(bIn), t.typ) offset = merger.Normalize(offset, mergeIn) // halving circuit: odd := 1 if i < len(bTare) && bTare[i] == 1 { odd = 0 bIn = make([]int, (len(merger.Out)+1)/2) } else { bIn = make([]int, len(merger.Out)/2) } // Alternate depending on bTare for j, x := range merger.Out { if j%2 == odd { bIn[j/2] = x } else if i < len(layers)-1 { // not in last layer, but else finalMapping[x] = -1 } } t.Sorter.Comparators = append(t.Sorter.Comparators, merger.Comparators...) } // outLastLayer identifies the nth output in the last layer outLastLayer := ((t.pb.K + 1 + tare) / int64(layerPow2)) - 1 // debug stuff: //glob.D("len last layer:", len(bIn), "kth output in last layer: ", outLastLayer) //glob.D("K+1+tar", t.pb.K+1+tare, "n layers", layerPow2) idSetToZero := bIn[outLastLayer] // and propagate the rest backwards setTo := -1 // dont care for _, id := range t.Sorter.ComputeOut() { if id == idSetToZero { setTo = 0 } if _, ok := finalMapping[id]; !ok { finalMapping[id] = setTo } } t.Sorter.PropagateBackwards(finalMapping) t.Sorter.Normalize(2, []int{}) //fmt.Println("LitIn", t.LitIn) //fmt.Println("final debug: tSorter", t.Sorter) }
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 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() } }
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 (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 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) }
// Chains is a set of chains in order of the PB // Chain: there are clauses xi <-xi+1 <- xi+2 ... <- xi+k, and xi .. xi+k are in order of PB // assumption: chains are subsets of literals of PB and in their order func CreateMDDChain(store *mdd.IntervalMddStore, K int64, entries []Entry, chains Chains) (int, int64, int64, error) { l := len(entries) ///level if store.MaxNodes < len(store.Nodes) { return 0, 0, 0, errors.New("mdd max nodes reached") } //chain.Print() //fmt.Println(l, K, entries) if id, wmin_cache, wmax_cache := store.GetByWeight(l, K); id != -1 { // fmt.Println("exists", l, K, "[", wmin, wmax, "]") return id, wmin_cache, wmax_cache, nil } else { //domain of variable [0,1], extend to [0..n] soon (MDDs) // entry of variable domain, atom: Dom: 2 var n mdd.IntervalNode var err error //glob.D(entries, chains) glob.A(len(chains) == 0 || len(chains[0]) > 0, "if exists, then chain must contain at least 1 element") if len(chains) > 0 && chains[0][0] == entries[0].Literal { //chain mode chain := chains[0] var jumpEntries []Entry if len(entries) <= len(chain) { // can this happen if entries and chains are perfectly aligned? jumpEntries = []Entry{} } else { jumpEntries = entries[len(chain):] } // iterate over the chain n.Level = l n.Children = make([]int, len(chain)+1) n.Children[0], n.Wmin, n.Wmax, err = CreateMDDChain(store, K, jumpEntries, chains[1:]) if err != nil { return 0, 0, 0, err } acc := int64(0) // fmt.Printf("entries:%v chain: %v", entries, chain) for i, _ := range chain { glob.A(len(chain) <= len(entries), "chain and PB are not aligned!!!! ") glob.A(chain[i] == entries[i].Literal, "chain and PB are not aligned!!!! ") var wmin2, wmax2 int64 acc += entries[i].Weight n.Children[i+1], wmin2, wmax2, err = CreateMDDChain(store, K-acc, jumpEntries, chains[1:]) n.Wmin = maxx(n.Wmin, wmin2+acc) n.Wmax = min(n.Wmax, wmax2+acc) if err != nil { return 0, 0, 0, err } } } else { //usual mode or for int-variables dom := 2 n.Level = l n.Children = make([]int, dom) n.Wmin = math.MinInt64 n.Wmax = math.MaxInt64 var err error for i := int64(0); i < int64(dom); i++ { var wmin2, wmax2 int64 n.Children[i], wmin2, wmax2, err = CreateMDDChain(store, K-i*entries[0].Weight, entries[1:], chains) n.Wmin = maxx(n.Wmin, wmin2+i*entries[0].Weight) n.Wmax = min(n.Wmax, wmax2+i*entries[0].Weight) if err != nil { return 0, 0, 0, err } } } return store.Insert(n), n.Wmin, n.Wmax, nil } }
// 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 }