/// <summary> /// Assert a fact to the FactBase. /// </summary> private static void CoreAssert(string rel, object e1, object e2, object e3, Tvar val) { // Don't assert a fact that's already been asserted if (!HasBeenAsserted(rel, e1, e2, e3)) { // Assert the fact Fact f = new Fact(rel, e1, e2, e3, val); FactBase.Add(f); // TODO: This breaks when the objects are not Things (hence the try-catch) try { // Add Things to the ThingBase AddThing((Thing)e1); AddThing((Thing)e2); AddThing((Thing)e3); // Look for additional inferences that can be drawn, based on assumptions. Assumptions.TriggerInferences(rel, (Thing)e1, (Thing)e2, (Thing)e3, val); } catch { } } }
/// <summary> /// Return a cached value of a function, if it has been cached. /// </summary> /// <example> /// Tbool t = (Tbool)Memo<Tbool>(()=> Fam.AreMarried(A,B) && H.IsMale(A), "1", A, B); /// </example> public static Tvar Memo <T> (Func <Tvar> fcn, string nodeID, params object[] args) where T : Tvar { Tvar result = default(Tvar); // Assemble the unique key for the function string key = nodeID + "_"; foreach (object o in args) { key += o.GetHashCode().ToString() + "_"; } // If fcn has been cached, return the cached value if (CacheBase.TryGetValue(key, out result)) { return((T)result); } // Evaluate fcn result = fcn.Invoke(); // If the result is never unstated, add it to the cache if (!result.IsEverUnstated) { CacheBase.Add(key, result); } return(result); }
public Fact(string rel, object arg1, object arg2, object arg3) { Relationship = rel; Arg1 = arg1; Arg2 = arg2; Arg3 = arg3; v = null; }
/// <summary> /// Sets a Tvar fact that establishes a relation between legal entities. /// </summary> public Fact(string rel, object arg1, object arg2, object arg3, Tvar val) { Relationship = rel; Arg1 = arg1; Arg2 = arg2; Arg3 = arg3; v = val; }
public Point(string rel, int arg1, int arg2, int arg3, Tvar val) { Relationship = rel; Arg1 = arg1; Arg2 = arg2; Arg3 = arg3; Value = val; }
/// <summary> /// Applies an aggregation function to a Tset and an argument function. /// </summary> private static T ApplyFcnToTset <T>(Tset theSet, Func <Thing, Tvar> argumentFcn, Func <List <Tuple <Thing, Hval> >, Hval> aggregationFcn) where T : Tvar { Dictionary <Thing, Tvar> fcnValues = new Dictionary <Thing, Tvar>(); List <Tvar> listOfTvars = new List <Tvar>(); // Get the temporal value of each distinct entity in the set foreach (Thing le in DistinctEntities(theSet)) { Tvar val = argumentFcn(le); fcnValues.Add(le, val); listOfTvars.Add(val); } // At each breakpoint, for each member of the set, // aggregate and analyze the values of the functions T result = (T)Util.ReturnProperTvar <T>(); foreach (DateTime dt in AggregatedTimePoints(theSet, listOfTvars)) { Hval membersOfSet = theSet.ObjectAsOf(dt); // If theSet is unknown... if (!membersOfSet.IsKnown) { result.AddState(dt, membersOfSet); } else { // Cube that gets sent to the aggregation function List <Tuple <Thing, Hval> > thingValPairs = new List <Tuple <Thing, Hval> >(); // Values to check for uncertainty List <Hval> values = new List <Hval>(); foreach (Thing le in (List <Thing>)membersOfSet.Val) { Tvar funcVal = (Tvar)fcnValues[le]; Hval funcValAt = funcVal.ObjectAsOf(dt); values.Add(funcValAt); thingValPairs.Add(new Tuple <Thing, Hval>(le, funcValAt)); } Hstate top = PrecedingState(values); if (top != Hstate.Known) { result.AddState(dt, new Hval(null, top)); } else { result.AddState(dt, aggregationFcn(thingValPairs)); } } } return(result.LeanTvar <T>()); }
/// <summary> /// Identifies intervals where a Tvar is Stub, Uncertain, or Unstated. /// </summary> public static Tbool HasUnknownState(Tvar tvar) { Tbool result = new Tbool(); foreach (KeyValuePair <DateTime, Hval> slice in tvar.IntervalValues) { result.AddState(slice.Key, slice.Value.IsStub || slice.Value.IsUncertain || slice.Value.IsUnstated); } return(result.Lean); }
/// <summary> /// Identifies intervals where a Tvar is Hstate.Null. /// </summary> public static Tbool IsNull(Tvar tvar) { Tbool result = new Tbool(); foreach (KeyValuePair <DateTime, Hval> slice in tvar.IntervalValues) { result.AddState(slice.Key, slice.Value.State == Hstate.Null); } return(result.Lean); }
/// <summary> /// Determines whether a Tvar ever has any undefined intervals (where Hstate = Null). /// </summary> public static bool HasUndefinedIntervals(Tvar tvar) { foreach (Hval h in tvar.IntervalValues.Values) { if (h.State == Hstate.Null) { return(true); } } return(false); }
/// <summary> /// Converts Tvar object to Timeline object. /// </summary> private static List <TemporalValue> TvarToTimeline(Akkadian.Tvar tv) { List <TemporalValue> result = new List <TemporalValue>(); for (int i = 0; i < tv.IntervalValues.Count; i++) { // TODO: This only handles strings right now...(b/c Unstated is an unrecognized object) result.Add(new TemporalValue(tv.IntervalValues.Keys[i], tv.IntervalValues.Values[i].Val.ToString())); } return(result); }
/// <summary> /// When a Tbool (tb) is true, get the value of one Tvar (val) and assign it to /// a second Tvar (result). /// </summary> /// <remarks> /// Example: tb = <--F--|--T--|--F--|--T--|--F--> /// val = <--------------4--------------> /// CA(tb,val) = <--n--|--4--|--n--|--4--|--n--> where n = Hstate.Null /// </remarks> public static T ConditionalAssignment <T>(Tbool tb, Tvar val) where T : Tvar { T result = (T)Util.ReturnProperTvar <T>(); foreach (KeyValuePair <DateTime, List <Hval> > pair in H.TimePointValues(tb, val)) { if (pair.Value[0].IsTrue) { result.AddState(pair.Key, pair.Value[1]); } else { result.AddState(pair.Key, new Hval(null, Hstate.Null)); } } return(result.LeanTvar <T>()); }
/// <summary> /// Apply a function to the values in a single Tvar. /// </summary> /// <remarks> /// This is used for unary functions (those that only operate on a single Tvar). /// </remarks> public static T ApplyFcnToTimeline <T>(Func <Hval, Hval> fcn, Tvar tv) where T : Tvar { T result = (T)Util.ReturnProperTvar <T>(); foreach (KeyValuePair <DateTime, Hval> slice in tv.IntervalValues) { Hstate top = PrecedingState(slice.Value); if (top != Hstate.Known) { result.AddState(slice.Key, new Hval(null, top)); } else { result.AddState(slice.Key, fcn(slice.Value)); } } return(result.LeanTvar <T>()); }
/// <summary> /// Hstate precedences for missing time periods. /// </summary> public static Hstate PrecedenceForMissingTimePeriods(Tvar t) { // If the base Tvar is ever unstated, return Unstated // b/c user could provide answer that resolves the question foreach (Hval h in t.TimeLine.Values) { if (h.IsUnstated) { return(Hstate.Unstated); } } // If the base Tvar is ever uncertain, return uncertain // b/c if user changes answer, this function might // resolve the question foreach (Hval h in t.TimeLine.Values) { if (h.IsUncertain) { return(Hstate.Uncertain); } } // If the base Tvar is ever uncertain, return uncertain // b/c if the rule logic were complete it might resolve // the question. foreach (Hval h in t.TimeLine.Values) { if (h.IsStub) { return(Hstate.Stub); } } return(Hstate.Known); }
// TODO: Implement data validation of some sort (e.g. consistency checking) /// <summary> /// Assert a temporal relation between legal entities (3) /// </summary> public static void Assert(object e1, string rel, object e2, object e3, Tvar val) { CoreAssert(rel, e1, e2, e3, val); }
public RulePreCheckResponse(Tvar theTvar, bool shortCircuit) { val = theTvar; shouldShortCircuit = shortCircuit; }
/// <summary> /// Returns true when two Tvar values are not equal. /// </summary> public static Tbool NotEqualTo(Tvar tv1, Tvar tv2) { return(ApplyFcnToTimeline <Tbool>(x => NotEq(x), tv1, tv2)); }
/// <summary> /// Scans the assumption table, looking for forward-chaining inferences. /// </summary> public static void TriggerInferences(string rel, Thing e1, Thing e2, Thing e3, Tvar val) { foreach (Pair p in Pairs) { // If A, then B if (p.LeftHandPoint.Relationship == rel) { // TODO: Currently only handles expressions that are eternally true if (Tvar.EqualTo(p.LeftHandPoint.Value, val)) { // For each rightPoint.Arg number, get the corresponding Thing Thing[] args = new Thing[3] { e1, e2, e3 }; int a1 = p.RightHandPoint.Arg1 - 1; // -1 b/c array is base-zero int a2 = p.RightHandPoint.Arg2 - 1; int a3 = p.RightHandPoint.Arg3 - 1; Thing t1 = a1 >= 0 ? args[a1] : null; Thing t2 = a2 >= 0 ? args[a2] : null; Thing t3 = a3 >= 0 ? args[a3] : null; Facts.Assert(t1, p.RightHandPoint.Relationship, t2, t3, p.RightHandPoint.Value); } } // If -B, then -A else if (p.RightHandPoint.Relationship == rel) { // If right-hand expression is always false... if (Tvar.EqualTo(p.RightHandPoint.Value, val).IsFalse) { // If the left-hand side is a boolean (non-booleans can't be negated)... if (Tvar.EqualTo(p.LeftHandPoint.Value, new Tbool(true)) || Tvar.EqualTo(p.LeftHandPoint.Value, new Tbool(false))) { // For each leftPoint.Arg number, get the corresponding Thing int r1 = p.RightHandPoint.Arg1; int r2 = p.RightHandPoint.Arg2; int r3 = p.RightHandPoint.Arg3; // I hope no one sees how ugly this is Thing t1, t2, t3; if (r1 == 1) { t1 = e1; } else if (r2 == 1) { t1 = e2; } else { t1 = e3; } if (r1 == 2) { t2 = e1; } else if (r2 == 2) { t2 = e2; } else { t2 = e3; } if (r1 == 3) { t3 = e1; } else if (r2 == 3) { t3 = e2; } else { t3 = e3; } // Assert -A Tbool leftVal = (Tbool)p.LeftHandPoint.Value; Facts.Assert(t1, p.LeftHandPoint.Relationship, t2, t3, !leftVal); } } } } }
/// <summary> /// Assert a temporal property of one legal entity /// </summary> public static void Assert(object e1, string rel, Tvar val) { CoreAssert(rel, e1, null, null, val); }