1 module dkh.twosat; 2 3 import dkh.graph.scc; 4 import dkh.container.stackpayload; 5 6 /// 2-SAT Solver 7 struct TwoSat { 8 bool[] vars; /// assigned variable 9 10 static struct Edge {uint to;} 11 private StackPayload!Edge[] g; 12 13 /// Clause $(D (vars[a] == expectedA) || (vars[b] == expectedB)) 14 void addClause(size_t a, bool expectedA, size_t b, bool expectedB) { 15 import std.conv : to; 16 g[2*a+(expectedA?0:1)] ~= Edge((2*b+(expectedB?1:0)).to!uint); 17 g[2*b+(expectedB?0:1)] ~= Edge((2*a+(expectedA?1:0)).to!uint); 18 } 19 20 /** 21 Solve 2-SAT 22 23 Returns: 24 satisfiable or not 25 */ 26 bool solve() { 27 import std.array : array; 28 import std.algorithm : map; 29 auto sccInfo = scc(g.map!(v => v.data).array); 30 foreach (i; 0..vars.length) { 31 if (sccInfo.id[2*i] == sccInfo.id[2*i+1]) return false; 32 vars[i] = sccInfo.id[2*i] < sccInfo.id[2*i+1]; 33 } 34 return true; 35 } 36 37 /** 38 Params: 39 n = # of variables 40 */ 41 this(size_t n) { 42 vars = new bool[n]; 43 g = new StackPayload!Edge[](2*n); 44 } 45 } 46 47 /// 48 unittest { 49 // Solve (x0 v x1) ^ (~x0 v x2) ^ (~x1 v ~x2) 50 auto sat = TwoSat(3); 51 sat.addClause(0, true, 1, true); // (vars[0] == true || vars[1] == true) 52 sat.addClause(0, false, 2, true); // (vars[0] == false || vars[2] == true) 53 sat.addClause(1, false, 2, false); // (vars[1] == false || vars[2] == false) 54 assert(sat.solve() == true); 55 auto vars = sat.vars; 56 assert(vars[0] == true || vars[1] == true); 57 assert(vars[0] == false || vars[2] == true); 58 assert(vars[1] == false || vars[2] == false); 59 } 60 61 unittest { 62 import std.algorithm, std.conv, std.stdio, std.range; 63 import std.random; 64 import std.typecons; 65 66 struct E {int to;} 67 68 void f() { 69 int n = uniform(1, 50); 70 int m = uniform(1, 100); 71 auto ans = new bool[n]; 72 auto sat = TwoSat(n); 73 ans.each!((ref x) => x = uniform(0, 2) == 1); 74 struct N {int i; bool expect;} 75 N[2][] conds; 76 foreach (i; 0..m) { 77 int x = uniform(0, n); 78 int y = uniform(0, n); 79 while (true) { 80 bool f = uniform(0, 2) == 1; 81 bool g = uniform(0, 2) == 1; 82 if (ans[x] != f && ans[y] != g) continue; 83 sat.addClause(x, f, y, g); 84 conds ~= [N(x, f), N(y, g)]; 85 break; 86 } 87 } 88 assert(sat.solve()); 89 auto vars = sat.vars; 90 foreach (cond; conds) { 91 int x = cond[0].i; 92 bool f = cond[0].expect; 93 int y = cond[1].i; 94 bool g = cond[1].expect; 95 assert(vars[x] == f || vars[y] == g); 96 } 97 } 98 99 import dkh.stopwatch; 100 auto ti = benchmark!(f)(1000); 101 writeln("TwoSat Random1000: ", ti[0].toMsecs); 102 }