//[TestMethod] //public void InverseFloyWarshall10Test() //{ // // Make a random 5-node undirected graph with designated connected components. // // Computes transitive closure of using Floyd-Warshall // InverseFWTest("IFW10", new[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }); //} //[TestMethod] //public void InverseFloyWarshall20Test() //{ // // Make a random 5-node undirected graph with designated connected components. // // Computes transitive closure of using Floyd-Warshall // InverseFWTest("IFW20", new[] // { // "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", // "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" // }); //} private static void InverseFWTest(string name, string[] vertices) { var p = new Problem(name); var adjacent = Predicate <string, string>("adjacent"); var floyd = Predicate <string, string, int>("d"); // Inlines either adjacent or floyd, depending on k Proposition D(string v1, string v2, int k) => k == 0 ? adjacent(v1, v2) : floyd(v1, v2, k); for (int k = 1; k < vertices.Length; k++) { var vk = vertices[k]; foreach (var v1 in vertices) { foreach (var v2 in vertices) { p.Assert( D(v1, v2, k) <= D(v1, v2, k - 1), D(v1, v2, k) <= (D(v1, vk, k - 1) & D(vk, v2, k - 1)) ); } } } Proposition Connected(string v1, string v2) => D(v1, v2, vertices.Length - 1); // Now constrain its connectivity foreach (var v1 in vertices) { foreach (var v2 in vertices) { if (v1 == v2 || (v1 != "e" && v2 != "e")) { p.Assert(Connected(v1, v2)); } else { p.Assert(Not(Connected(v1, v2))); } } } p.Optimize(); for (int i = 0; i < 100; i++) { var s = p.Solve(); // a, b, c, d should be a connected component, e should be unconnected to anything but e foreach (var v1 in vertices) { foreach (var v2 in vertices) { Assert.IsTrue(s[Connected(v1, v2)] == (v1 == v2) || (v1 != "e" && v2 != "e")); } } } p.LogPerformanceData(); }
public void FloydWarshallTest() { // Compute the transitive closure of a 5-node graph using Floyd-Warshall // This *should* get constant-folded away var p = new Problem("transitive closure test"); var vertices = new[] { "a", "b", "c", "d", "e" }; var edges = new[] { new[] { "a", "b" }, new[] { "a", "d" }, new[] { "b", "c" }, new[] { "d", "c" }, }; Proposition Adjacent(string v1, string v2) => edges.Any(e => (v1 == v2) || (e[0] == v1 && e[1] == v2) || (e[0] == v2 && e[1] == v1)); var floyd = Predicate <string, string, int>("d"); // Inlines either adjacent or floyd, depending on k Proposition D(string v1, string v2, int k) => k == 0 ? Adjacent(v1, v2) : floyd(v1, v2, k); for (int k = 1; k < vertices.Length; k++) { var vk = vertices[k]; foreach (var v1 in vertices) { foreach (var v2 in vertices) { p.Assert( D(v1, v2, k) <= D(v1, v2, k - 1), D(v1, v2, k) <= (D(v1, vk, k - 1) & D(vk, v2, k - 1)) ); } } } Proposition Connected(string v1, string v2) => D(v1, v2, vertices.Length - 1); p.Optimize(); for (int i = 0; i < 100; i++) { var s = p.Solve(); // a, b, c, d should be a connected component, e should be unconnected to anything but e foreach (var v1 in vertices) { foreach (var v2 in vertices) { Assert.IsTrue(s[Connected(v1, v2)] == (v1 == v2) || (v1 != "e" && v2 != "e")); } } } }
public void TransitiveClosureTest() { // Compute the transitive closure of a 5-node graph using Floyd-Warshall // This *should* get constant-folded away var p = new Problem("transitive closure test"); var vertices = new[] { "a", "b", "c", "d", "e" }; var edges = new[] { new[] { "a", "b" }, new[] { "a", "d" }, new[] { "b", "c" }, new[] { "d", "c" }, }; Proposition Adjacent(string v1, string v2) => edges.Any(e => (v1 == v2) || (e[0] == v1 && e[1] == v2) || (e[0] == v2 && e[1] == v1)); var connected = SymmetricPredicate <string>("connected"); foreach (var from in vertices) { foreach (var to in vertices) { if (from == to) { continue; } p.Assert(connected(from, to) <= Adjacent(from, to)); foreach (var intermediary in vertices) { if (intermediary != from && intermediary != to) { p.Assert(connected(from, to) <= (Adjacent(from, intermediary) & connected(intermediary, to))); } } } } p.Optimize(); for (int i = 0; i < 100; i++) { var s = p.Solve(); // a, b, c, d should be a connected component, e should be unconnected to anything but e foreach (var v1 in vertices) { foreach (var v2 in vertices) { Assert.IsTrue(s[connected(v1, v2)] == (v1 == v2) || (v1 != "e" && v2 != "e")); } } } }
public void ContradictionTest() { var prog = new Problem("Contradiction test"); var p = (Proposition)"p"; var q = (Proposition)"q"; var r = (Proposition)"r"; prog.Assert( p <= q, p <= r, Not(p), q ); prog.Optimize(); Assert.Fail(); }
public void OptimizationTest() { var prog = new Problem("Optimzer test"); var p = (Proposition)"p"; var q = (Proposition)"q"; var r = (Proposition)"r"; var s = (Proposition)"s"; prog.Assert( p <= q, p <= r, Not(p) ); prog.Optimize(); Assert.IsTrue(prog.IsAlwaysFalse(p)); Assert.IsTrue(prog.IsAlwaysFalse(q)); Assert.IsTrue(prog.IsAlwaysFalse(r)); Assert.IsFalse(prog.IsConstant(s)); }
public void StoryTest() { var p = new Problem("murder test") { TimeHorizon = 4, Timeout = 50000 }; var cast = new[] { "Fred", "Betty", "Frieda" }; // FLUENTS // alive(a, t) iff a alive at time t var alive = Fluent("alive", cast); var married = Fluent("married", cast); // Everyone is initially alive an unmarried foreach (var c in cast) { p.Assert(alive(c, 0), Not(married(c, 0))); } var hates = Fluent("hates", cast, cast); var loves = Fluent("loves", cast, cast); var marriedTo = SymmetricFluent("marriedTo", cast); foreach (var c1 in cast) { foreach (var c2 in cast) { p.Assert(Not(marriedTo(c1, c2, 0)), Not(loves(c1, c2, 0))); } } // Love and hate disable one another foreach (var agent in cast) { foreach (var patient in cast) { foreach (var t in ActionTimePoints) { p.Assert(Deactivate(hates(agent, patient, t)) <= Activate(loves(agent, patient, t)), Deactivate(loves(agent, patient, t)) <= Activate(hates(agent, patient, t))); } } } // ACTIONS // kill(a,b,t) means a kills b at time t var kill = Action("kill", cast, cast); Precondition(kill, (a, b, t) => alive(b, t)); Precondition(kill, (a, b, t) => alive(a, t)); Precondition(kill, (a, b, t) => hates(a, b, t)); Deletes(kill, (a, b, t) => alive(b, t)); // fallFor(faller, loveInterest, time) var fallFor = Action("fallFor", cast, cast); Precondition(fallFor, (f, l, t) => Not(loves(f, l, t))); Precondition(fallFor, (f, l, t) => alive(f, t)); Precondition(fallFor, (f, l, t) => alive(l, t)); Precondition(fallFor, (f, l, t) => f != l); Adds(fallFor, (f, l, t) => loves(f, l, t)); // marry(a, b, t) var marry = SymmetricAction("marry", cast); Precondition(marry, (a, b, t) => loves(a, b, t)); Precondition(marry, (a, b, t) => loves(b, a, t)); Precondition(marry, (a, b, t) => a != b); Precondition(marry, (a, b, t) => alive(a, t)); Precondition(marry, (a, b, t) => alive(b, t)); Precondition(marry, (a, b, t) => Not(married(a, t))); Precondition(marry, (a, b, t) => Not(married(b, t))); Adds(marry, (a, b, t) => marriedTo(a, b, t)); Adds(marry, (a, b, t) => married(a, t)); Adds(marry, (a, b, t) => married(b, t)); // You can't marry or fall in love with yourself foreach (var t in ActionTimePoints) { foreach (var c in cast) { p.Assert(Not(marry(c, c, t)), Not(fallFor(c, c, t))); } } IEnumerable <ActionInstantiation> PossibleActions(int t) { return(Instances(kill, t).Concat(Instances(fallFor, t)).Concat(Instances(marry, t))); } foreach (var t in ActionTimePoints) { // Exactly one action per time point p.AtMost(1, PossibleActions(t)); } // Tragedy strikes //foreach (var c in cast) // p.Assert(Not(alive(c, TimeHorizon-1))); //p.Assert(married("Fred", 3)); p.Optimize(); Console.WriteLine(p.Stats); var s = p.Solve(); foreach (var t in ActionTimePoints) { Console.Write($"Time {t}: "); foreach (var a in PossibleActions(t)) { if (s[a]) { Console.Write($"{a}, "); } } Console.WriteLine(); } }
public void FamilyGeneratorTest() { var p = new Problem("family generator"); var FamilySize = 25; var generationCount = 5; var matriarch = 1; var cast = Enumerable.Range(matriarch, FamilySize).ToArray(); var kids = Enumerable.Range(matriarch + 1, FamilySize - 1).ToArray(); var childGenerations = Enumerable.Range(1, generationCount - 1).ToArray(); var female = Predicate <int>("female"); var generation = Predicate <int, int>("generation"); var parent = Predicate <int, int>("parent"); // Interestingly, this doesn't seem to speed things up. //Func<int, int, Proposition> parent = (child, par) => // child > par ? p.GetProposition(Call.FromArgs(Problem.Current, "parent", child, par)) : false; // Make of person # who is person number -who int Mate(int who) => - who; // Family must be 40-60% female p.Quantify((int)(FamilySize * .4), (int)(FamilySize * .6), kids, female); // Matriarch is the generation 0 female p.Assert(female(matriarch), Not(female(Mate(matriarch)))); p.Assert(generation(matriarch, 0)); foreach (var child in kids) { // Everyone has exactly one parent from within the family (and one from outside) p.Unique(cast, par => parent(child, par)); foreach (var par in cast) { parent(child, par).InitialProbability = 0; } // Everyone has a generation number p.Unique(childGenerations, g => generation(child, g)); p.Assert( // Only matriarch and patriarch are generation 0 Not(generation(child, 0)), // Heteronormativity female(child) == Not(female(Mate(child)))); foreach (var par in cast) { foreach (var g in childGenerations) { // Child's generation is one more than parent's generation p.Assert(generation(child, g) <= (parent(child, par) & generation(par, g - 1))); } } } // Every generation has at least one kid foreach (var g in childGenerations) { p.Exists(kids, k => generation(k, g)); } p.Optimize(); Console.WriteLine(p.Stats); Console.WriteLine(p.PerformanceStatistics); Console.WriteLine(); for (int i = 0; i < 100; i++) { var s = p.Solve(); Console.WriteLine(p.PerformanceStatistics); void PrintTree(int who, int depth) { for (int j = 0; j < depth; j++) { Console.Write(" "); } Console.WriteLine($"{Gender(who)} {who}: + {Mate(who)}"); foreach (var child in kids.Where(k => s[parent(k, who)])) { PrintTree(child, depth + 1); } } string Gender(int who) { return(s[female(who)] ? "female" : "male"); } PrintTree(matriarch, 0); } }