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 SkipPropagationTest() { var p = new Problem("Skip last test's propagation during initialization"); p.AddClause("b", "c"); p.AddClause("a", "d"); p.AddClause("d", "c"); p.AddClause("e", "c"); p.AddClause("f", "g"); p.AddClause("g", "c"); p.AddClause("h", "k"); p.AddClause("i", "c"); p.AddClause("j", "g"); p.AddClause("k", "c"); p.AddClause("l", "c"); p.AddClause("m", "c"); p.AddClause("n", "r"); p.AddClause(1, 1, "e", "f"); p.AddClause("w"); p.QuantifyIf("a", 2, 2, "a", "c"); p.AddClause(1, 1, "b", "c"); p.PropagateConstraintsDuringInitialization = false; int[] flip = new int[1000]; for (int i = 0; i < 1000; i++) { var m = p.Solve(); flip[i] = m.Problem.BooleanSolver.SolveFlips; } int average = flip.Sum() / flip.Length; p.Assert(average == 4); }
public void LowTechCharacterGeneratorTest() { var prog = new Problem("Character generator"); prog.Assert("character"); // Races Partition("character", "human", "electroid", "insectoid"); // Classes Partition("character", "fighter", "magic user", "cleric", "thief"); prog.Inconsistent("electroid", "cleric"); // Nationalities of humans Partition("human", "landia", "placeville", "cityburgh"); // Religions of clerics Partition("cleric", "monotheist", "pantheist", "lovecraftian", "dawkinsian"); // Lovecraftianism is outlawed in Landia prog.Inconsistent("landia", "lovecraftian"); // Insectoids believe in strict hierarchies prog.Inconsistent("insectoid", "pantheist"); // Lovecraftianism is the state religion of cityburgh prog.Inconsistent("cityburgh", "cleric", Not("lovecraftian")); for (int i = 0; i < 100; i++) { Console.WriteLine(prog.Solve().Model); } }
public void NonstrictTest() { var n = 8; var p = new Problem("induction test"); var pred = Predicate <int>("pred"); for (var i = 1; i < n - 1; i++) // cell set iff neighbor is set. { p.Assert( pred(i) <= pred(i - 1), pred(i) <= pred(i + 1) ); } // Solve it. for (int t = 0; t < 100; t++) { var m = p.Solve(); // This has 3 solutions: all false, all true, all but one end true, all but either end true. var c = m.Count(Range(0, n).Select(pred)); Assert.IsTrue(c == 0 || c >= n - 2); } }
public void CompletionTest() { var p = new Problem("Completion test"); var s = (Proposition)"s"; var t = (Proposition)"t"; var u = (Proposition)"u"; var a = (Proposition)"a"; var b = (Proposition)"b"; var c = (Proposition)"c"; p.Assert( s <= (t & u), s <= (a & b), s <= c ); for (int i = 0; i < 100; i++) { var m = p.Solve(); Assert.AreEqual(m.IsTrue(s), (m.IsTrue(t) && m.IsTrue("u")) || (m.IsTrue(a) && m.IsTrue(b) || m.IsTrue(c))); } }
public void FloatTest() { var p = new Problem(nameof(FloatTest)); var dom = new FloatDomain("unit", 0, 1); var x = (FloatVariable)dom.Instantiate("x"); var y = (FloatVariable)dom.Instantiate("y"); var a = (Proposition)"a"; var b = (Proposition)"b"; var c = (Proposition)"c"; var d = (Proposition)"d"; var e = (Proposition)"e"; p.Assert(a > (x > .2f)); p.Assert(b > (x > .3f)); p.Assert(c > (x < .5f)); p.Assert(d > (x < .8f)); p.Assert(e > (x == y)); for (int i = 0; i < 100; i++) { var s = p.Solve(); Console.WriteLine(s.Model); var xVal = x.Value(s); var yVal = y.Value(s); if (s[a]) { Assert.IsTrue(xVal >= .2f); } if (s[b]) { Assert.IsTrue(xVal >= .3f); } if (s[c]) { Assert.IsTrue(xVal <= .5f); } if (s[d]) { Assert.IsTrue(xVal <= .8f); } if (s[e]) { Assert.AreEqual(xVal, yVal); } } }
public void InductionTest() { var n = 8; var p = new Problem("induction test"); var pred = Predicate <int>("pred"); p.Assert(pred(0)); for (var i = 0; i < n; i++) { p.Assert(pred(i) == pred(i - 1)); } for (int t = 0; t < 100; t++) { var m = p.Solve(); Assert.IsTrue(m.All(Range(0, n).Select(i => pred(i)))); } }
public void PredeterminedContradictionTest() { var p = new Problem(); p.Assert((Proposition)"a" > "b"); p["a"] = true; p["b"] = false; p.Solve(false); }
public void UndefinedFloatVarEquationHasNoEffectTest() { var p = new Problem("test"); var dom = new FloatDomain("signed unit", -1, 1); var prop = (Proposition)"prop"; var x = new FloatVariable("x", dom, prop, p); var y = (FloatVariable)dom.Instantiate("y"); p.Assert(Not(prop)); p.Assert(x == y); for (int i = 0; i < 100; i++) { var s = p.Solve(); Assert.IsFalse(x.IsDefinedInInternal(s)); Assert.IsTrue(y.IsDefinedInInternal(s)); Assert.IsFalse(ReferenceEquals(x.Representative, y.Representative)); } }
public void PartyGeneratorTest() { var prog = new Problem("Party generator"); var cast = new[] { "fred", "jenny", "sally" }; var character = Predicate <string>("character"); var human = Predicate <string>("human"); var electroid = Predicate <string>("electroid"); var insectoid = Predicate <string>("insectoid"); var fighter = Predicate <string>("fighter"); var magicUser = Predicate <string>("magic_user"); var cleric = Predicate <string>("cleric"); var thief = Predicate <string>("thief"); var landia = Predicate <string>("landia"); var placeville = Predicate <string>("placeville"); var cityburgh = Predicate <string>("cityburgh"); var monotheist = Predicate <string>("monotheist"); var pantheist = Predicate <string>("pantheist"); var lovecraftian = Predicate <string>("lovecraftian"); var dawkinsian = Predicate <string>("dawkinsian"); foreach (var who in cast) { prog.Assert(character(who)); // Races Partition(character(who), human(who), electroid(who), insectoid(who)); // Classes Partition(character(who), fighter(who), magicUser(who), cleric(who), thief(who)); prog.Inconsistent(electroid(who), cleric(who)); // Nationalities of humans Partition(human(who), landia(who), placeville(who), cityburgh(who)); // Religions of clerics Partition(cleric(who), monotheist(who), pantheist(who), lovecraftian(who), dawkinsian(who)); // Lovecraftianism is outlawed in Landia prog.Inconsistent(landia(who), lovecraftian(who)); // Insectoids believe in strict hierarchies prog.Inconsistent(insectoid(who), pantheist(who)); // Lovecraftianism is the state religion of cityburgh prog.Inconsistent(cityburgh(who), cleric(who), Not(lovecraftian(who))); } prog.AtMost(1, cast, fighter); prog.AtMost(1, cast, magicUser); prog.AtMost(1, cast, cleric); prog.AtMost(1, cast, thief); for (int i = 0; i < 100; i++) { Console.WriteLine(prog.Solve().Model); } }
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 FalseRuleTest() { var prog = new Problem("False rule test"); var p = (Proposition)"p"; prog.Assert(p <= false); prog.Solve(); // Force it to expand rule to completion // This should not generate any clauses Assert.AreEqual(0, prog.Constraints.Count); }
public void AntecedentTrackingTest() { var p = new Problem(nameof(AntecedentTrackingTest)); var x = (Proposition)"x"; var y = (Proposition)"y"; var z = (Proposition)"z"; var w = (Proposition)"w"; foreach (var prop in new[] { x, y, z, w }) { Assert.IsFalse(prop.IsImplicationConsequent); Assert.IsFalse(prop.IsRuleHead); Assert.IsFalse(prop.IsAntecedent); } p.Assert(w > x); Assert.IsTrue(x.IsImplicationConsequent); Assert.IsFalse(x.IsRuleHead); Assert.IsFalse(x.IsDependency); Assert.IsFalse(x.IsAntecedent); Assert.IsTrue(w.IsAntecedent); Assert.IsFalse(w.IsImplicationConsequent); Assert.IsFalse(w.IsRuleHead); Assert.IsTrue(w.IsDependency); p.Assert(x <= (y & z)); Assert.IsTrue(x.IsRuleHead); Assert.IsTrue(x.IsDependency); Assert.IsTrue(y.IsAntecedent); Assert.IsFalse(y.IsRuleHead); Assert.IsFalse(y.IsImplicationConsequent); Assert.IsTrue(y.IsDependency); Assert.IsTrue(z.IsAntecedent); Assert.IsFalse(z.IsRuleHead); Assert.IsFalse(z.IsImplicationConsequent); Assert.IsTrue(z.IsDependency); var a = (Proposition)"a"; p.Assert(Language.Not(x) > a); Assert.IsTrue(x.IsAntecedent); Assert.IsTrue(x.IsImplicationConsequent); Assert.IsTrue(x.IsRuleHead); }
public void ConnectedChainTest() { var n = 8; var p = new Problem("connected chain test"); Func <int, int, Proposition> adjacent = (i, j) => Math.Abs(i - j) < 2; var connected = Predicate <int, int>("connected"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) { p.Assert(connected(i, i)); } else { // i is connected to j if the node on either side is connected to j and i is adjacent to the neighbor. p.Assert( connected(i, j) <= adjacent(i, i - 1), connected(i - 1, j), connected(i, j) <= adjacent(i, i + 1), connected(i + 1, j) ); } } } var m = p.Solve(); for (int trial = 0; trial < 100; trial++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { Assert.IsTrue(m.IsTrue(connected(i, j))); } } } }
public void BiconditionalTest() { var p = new Problem("Biconditional test"); var s = (Proposition)"s"; var t = (Proposition)"t"; p.Assert(s == t); for (int i = 0; i < 100; i++) { var m = p.Solve(); Assert.AreEqual(m.IsTrue(s), m.IsTrue(t)); } }
public void BiconditionalTest2() { var p = new Problem("Biconditional test 2"); var s = (Proposition)"s"; var t = (Proposition)"t"; var u = (Proposition)"u"; p.Assert(s == (t & u)); for (int i = 0; i < 100; i++) { var m = p.Solve(); Assert.AreEqual(m[s], m[t] && m[u]); } }
public void ConstantBoundDependencyTest() { var p = new Problem(nameof(FloatTest)); var dom = new FloatDomain("unit", 0, 1); var x = (FloatVariable)dom.Instantiate("x"); var a = (Proposition)"a"; p.Assert((x > 0.1f) > a); for (int i = 0; i < 100; i++) { var s = p.Solve(); Assert.IsTrue(x.Value(s) <= 0.1f || s[a]); } }
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 SolveTwoDependent() { SMTVar.Reset(); var p = new Problem("SolveTwoDependent"); var x = new SMTVar("x", 0, 10); var y = new SMTVar("y", 0, 10); p.Assert(x < y); for (int i = 0; i < 100; i++) { Assert.IsTrue(SMTVar.Solve(p.Solve())); AssertValid(x); AssertValid(y); Assert.IsTrue(x.Value <= y.Value, $"Trial {i}: {x.Value} > {y.Value}"); } }
public void TrueRuleTest() { var prog = new Problem("True rule test"); var p = (Proposition)"p"; var q = (Proposition)"q"; prog.Assert( p <= true, p <= false, p <= q ); var s = prog.Solve(); // Force it to expand rule to completion // This should have compiled to zero clauses but p should still always be true Assert.AreEqual(0, prog.Constraints.Count); Assert.IsTrue(s[p]); }
public void ImplicationTest() { var p = new Problem("Implication test"); var s = (Proposition)"s"; var t = (Proposition)"t"; p.Assert( (t & (Proposition)true) > s, t ); for (int i = 0; i < 100; i++) { var m = p.Solve(); Assert.IsTrue(m.IsTrue(s)); Assert.IsTrue(m.IsTrue(t)); } }
public void UndefinedFloatVarTest() { var p = new Problem("test"); var dom = new FloatDomain("signed unit", -1, 1); var prop = (Proposition)"prop"; var x = new FloatVariable("x", dom, prop, p); p.Assert(Not(prop)); Solution s = null; for (int i = 0; i < 100; i++) { s = p.Solve(); Console.WriteLine(s.Model); Assert.IsFalse(s[prop]); Assert.IsFalse(x.IsDefinedInInternal(s)); } Console.WriteLine(x.Value(s)); }
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 ContrapositiveTest() { var prog = new Problem("Contrapositive test"); var p = (Proposition)"p"; var q = (Proposition)"q"; var r = (Proposition)"r"; prog.Assert( p <= q, p <= r, Not(p) ); for (int i = 0; i < 100; i++) { var m = prog.Solve(); // Under completion semantics, only model should be the empty model. Assert.IsFalse(m.IsTrue(p)); Assert.IsFalse(m.IsTrue(q)); Assert.IsFalse(m.IsTrue(r)); } }
public void PSMTNPCStatsTest() { SMTVar.Reset(); var p = new Problem("NPC stats"); var str = new SMTVar("str", 0, 10); var con = new SMTVar("con", 0, 10); var dex = new SMTVar("dex", 0, 10); var intel = new SMTVar("int", 0, 10); var wis = new SMTVar("wis", 0, 10); var charisma = new SMTVar("char", 0, 10); p.Unique("fighter", "magic user", "cleric", "thief"); p.Assert( ((Expression)(Proposition)"fighter") > (str > intel), ((Expression)(Proposition)"fighter") > (str > 5), ((Expression)(Proposition)"fighter") > (con > 5), ((Expression)(Proposition)"fighter") > (intel < 8), ((Expression)(Proposition)"magic") > (str < intel), ((Expression)(Proposition)"magic") > (intel > 5), ((Expression)(Proposition)"magic") > (str < 8), ((Expression)(Proposition)"cleric") > (wis > 5), ((Expression)(Proposition)"cleric") > (con < wis), ((Expression)(Proposition)"theif") > (dex > 5), ((Expression)(Proposition)"theif") > (charisma > 5), ((Expression)(Proposition)"theif") > (wis < 5), ((Expression)(Proposition)"theif") > (dex > str), ((Expression)(Proposition)"theif") > (charisma > intel) ); for (int i = 0; i < 100; i++) { Solution solution; do { solution = p.Solve(); } while (!SMTVar.Solve(solution)); } }
public void IgnoreFalseRuleTest() { var prog = new Problem("Ignore false rule test"); var p = (Proposition)"p"; var q = (Proposition)"q"; prog.Assert( p <= false, p <= q, p <= false ); prog.Solve(); // Force it to expand rule to completion // This should have compiled to two clauses Assert.AreEqual(2, prog.Constraints.Count); // First clause should be q => p Assert.AreEqual(2, prog.Constraints[0].Disjuncts.Length); Assert.AreEqual(1, prog.Constraints[0].Disjuncts[0]); Assert.AreEqual(-2, prog.Constraints[0].Disjuncts[1]); // Section clause should be p => q Assert.AreEqual(2, prog.Constraints[1].Disjuncts.Length); Assert.AreEqual(-1, prog.Constraints[1].Disjuncts[0]); Assert.AreEqual(2, prog.Constraints[1].Disjuncts[1]); }
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 MurderTest() { var p = new Problem("murder test") { TimeHorizon = 10 }; var cast = new[] { "fred", "lefty" }; // FLUENT // alive(a, t) iff a alive at time t var alive = Fluent("alive", cast); // ACTION // 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)); Deletes(kill, (a, b, t) => alive(b, t)); // AXIOMS // No suicide foreach (var t in ActionTimePoints) { foreach (var a in cast) { p.Assert(Not(kill(a, a, t))); } } // INITIAL CONDITIONS // Everyone is initially alive foreach (var c in cast) { p.Assert(alive(c, 0)); } // GOAL // At least one character has to die. p.AtMost(1, cast, who => alive(who, TimeHorizon - 1)); // SOLVE for (int i = 0; i < 100; i++) { var s = p.Solve(); var murders = new List <Proposition>(); // Find all the murders foreach (var t in ActionTimePoints) { foreach (var a in cast) { foreach (var b in cast) { if (s[kill(a, b, t)]) { murders.Add(kill(a, b, t)); } } } } // There should be one, and at most two Assert.IsTrue(murders.Count > 0 && murders.Count <= 2); // If there are two, then they'd better have been simultaneous. if (murders.Count == 2) { Assert.IsTrue(Equals(murders[0].Arg(2), murders[1].Arg(2))); } } }
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); } }
// ReSharper disable once IdentifierTypo // ReSharper disable once InconsistentNaming public void PSMTNPCStatTest() { var p = new Problem("NPC stats"); var str = new FloatVariable("str", 0, 10); var con = new FloatVariable("con", 0, 10); var dex = new FloatVariable("dex", 0, 10); var intel = new FloatVariable("int", 0, 10); var wis = new FloatVariable("wis", 0, 10); var charisma = new FloatVariable("char", 0, 10); var classDomain = new FDomain <string>("character class", "fighter", "magic user", "cleric", "thief"); var cClass = classDomain.Instantiate("class"); p.Assert( (cClass == "fighter") > (str > intel), (cClass == "fighter") > (str > 5), (cClass == "fighter") > (con > 5), (cClass == "fighter") > (intel < 8), (cClass == "magic user") > (str < intel), (cClass == "magic user") > (intel > 5), (cClass == "magic user") > (str < 8), (cClass == "cleric") > (wis > 5), (cClass == "cleric") > (con < wis), (cClass == "thief") > (dex > 5), (cClass == "thief") > (charisma > 5), (cClass == "thief") > (wis < 5), (cClass == "thief") > (dex > str), (cClass == "thief") > (charisma > intel) ); for (int i = 0; i < 100; i++) { var s = p.Solve(); if (s[(cClass == "fighter")]) { Assert.IsTrue(str.Value(s) >= intel.Value(s)); } if (s[(cClass == "fighter")]) { Assert.IsTrue(str.Value(s) >= 5); } if (s[(cClass == "fighter")]) { Assert.IsTrue(con.Value(s) >= 5); } if (s[(cClass == "fighter")]) { Assert.IsTrue(intel.Value(s) <= 8); } if (s[(cClass == "magic user")]) { Assert.IsTrue(str.Value(s) <= intel.Value(s)); } if (s[(cClass == "magic user")]) { Assert.IsTrue(intel.Value(s) >= 5); } if (s[(cClass == "magic user")]) { Assert.IsTrue(str.Value(s) <= 8); } if (s[(cClass == "cleric")]) { Assert.IsTrue(wis.Value(s) >= 5); } if (s[(cClass == "cleric")]) { Assert.IsTrue(con.Value(s) <= wis.Value(s)); } if (s[(cClass == "thief")]) { Assert.IsTrue(dex.Value(s) >= 5); } if (s[(cClass == "thief")]) { Assert.IsTrue(charisma.Value(s) >= 5); } if (s[(cClass == "thief")]) { Assert.IsTrue(wis.Value(s) <= 5); } if (s[(cClass == "thief")]) { Assert.IsTrue(dex.Value(s) >= str.Value(s)); } if (s[(cClass == "thief")]) { Assert.IsTrue(charisma.Value(s) >= intel.Value(s)); } Console.WriteLine(s.Model); } }