/// <summary> /// Divides one Tnum by another. /// </summary> public static Tnum operator /(Tnum tn1, Tnum tn2) { Tnum result = new Tnum(); foreach (KeyValuePair <DateTime, List <Hval> > slice in TimePointValues(tn1, tn2)) { Hstate top = PrecedingState(slice.Value); decimal denominator = Convert.ToDecimal(slice.Value[1].Val); if (denominator == 0) // Short circuit 1: Div-by-zero { result.AddState(slice.Key, new Hval(null)); } else if (top != Hstate.Known) // Short circuit 2: Hstates { result.AddState(slice.Key, new Hval(null, top)); } else // Do the math { decimal r = Convert.ToDecimal(slice.Value[0].Val) / denominator; result.AddState(slice.Key, new Hval(r)); } } return(result.Lean); }
/// <summary> /// Unstated Things. /// </summary> public Thing(Hstate h) { if (h == Hstate.Unstated) Id = "#Unstated#"; else if (h == Hstate.Uncertain) Id = "#Uncertain#"; else if (h == Hstate.Stub) Id = "#Stub#"; else Id = ""; }
/// <summary> /// Multiplies two Tnums together. /// </summary> public static Tnum operator *(Tnum tn1, Tnum tn2) { Tnum result = new Tnum(); foreach (KeyValuePair <DateTime, List <Hval> > slice in TimePointValues(tn1, tn2)) { Hstate top = PrecedingState(slice.Value); decimal val1 = Convert.ToDecimal(slice.Value [0].Val); decimal val2 = Convert.ToDecimal(slice.Value [1].Val); // Short circuit 1 if (val1 == 0 || val2 == 0) { result.AddState(slice.Key, new Hval(0)); } else if (top != Hstate.Known) // Short circuit 2 { result.AddState(slice.Key, new Hval(null, top)); } else // Do the math { decimal prod = val1 * val2; result.AddState(slice.Key, new Hval(prod)); } } return(result.Lean); }
public static Tnum IntervalsUntil(Tdate startDate, Tdate endDate, IntervalType interval, int startAt) { // Handle unknowns Hstate top = PrecedingState(startDate.FirstValue, endDate.FirstValue); if (top != Hstate.Known) { return(new Tnum(new Hval(null, top))); } DateTime start = startDate.ToDateTime; DateTime end = endDate.ToDateTime; Tnum result = new Tnum(); DateTime indexDate = end; int indexNumber = startAt - 1; while (indexDate > start) { if (indexNumber != startAt - 1) { result.AddState(indexDate, Convert.ToString(indexNumber)); } indexNumber++; indexDate = indexDate.SubtractInterval(interval); } result.AddState(Time.DawnOf, 0); result.AddState(start, Convert.ToString(indexNumber)); result.AddState(end, 0); return(result); }
/// <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> /// Known object values and null values. /// </summary> public Hval(object val) { if (val == null) { Obj = null; State = Hstate.Uncertain; } else { Obj = val; State = Hstate.Known; } }
/// <summary> /// States. /// </summary> public Hval(object ignored, Hstate state) { if (state == Hstate.Known) { // Should not happen? Obj = null; State = Hstate.Known; } else { Obj = null; State = state; } }
/// <summary> /// Provides a running count of how many whole intervals a Tbool /// has been continuously true. /// </summary> /// <remarks> /// Example: /// tb = <--FTFTTF--> /// tb.ICT = <--010120--> /// /// Use judiciously with TheDay and TheCalendarWeek, as they have thousands of time intervals. /// </remarks> public Tnum ContinuousElapsedIntervals(Tnum interval) { // If base Tnum is ever unknown during the time period, return // the state with the proper precedence Hstate baseState = PrecedenceForMissingTimePeriods(this); if (baseState != Hstate.Known) { return(new Tnum(baseState)); } int intervalCount = 0; DateTime dateNextTrue = this.DateNextTrue(Time.DawnOf); DateTime dateNextTrueIntervalEnds = this.NextChangeDate(dateNextTrue.AddTicks(1)); Tnum result = new Tnum(0); // Iterate through the time intervals in the input Tnum for (int i = 0; i < interval.IntervalValues.Count - 1; i++) { DateTime start = interval.IntervalValues.Keys[i]; DateTime end = interval.IntervalValues.Keys[i + 1]; // If base Tbool is always true during the interval, increment the count if (end <= dateNextTrueIntervalEnds) { if (start >= dateNextTrue) { intervalCount++; result.AddState(end, intervalCount); continue; } } else { // Otherwise, skip to next true interval intervalCount = 0; result.AddState(end, intervalCount); dateNextTrue = this.DateNextTrue(end); dateNextTrueIntervalEnds = this.NextChangeDate(dateNextTrue.AddTicks(1)); } } return(result); }
/// <summary> /// Apply a function to all values in a list of zipped Tvar values. /// </summary> public static T ApplyFcnToTimeline <T>(Func <List <Hval>, Hval> fcn, params Tvar[] list) where T : Tvar { T result = (T)Util.ReturnProperTvar <T>(); foreach (KeyValuePair <DateTime, List <Hval> > slice in TimePointValues(list)) { 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> /// 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> /// Unstated Things. /// </summary> public Thing(Hstate h) { if (h == Hstate.Unstated) { Id = "#Unstated#"; } else if (h == Hstate.Uncertain) { Id = "#Uncertain#"; } else if (h == Hstate.Stub) { Id = "#Stub#"; } else { Id = ""; } }
/// <summary> /// Takes a Tnum representing some value per unit time, and sums or /// accumulates it over a given type of time interval to obtain a /// running total. /// </summary> /// <example> /// Calculate lifetime accrued income, given a person's annual income: /// /// AccruedIncome = AnnualIncome.RunningSummedIntervals(TheYear) /// /// The time units cancel: [$/year] * [year] yields [$]. /// </example> public Tnum RunningSummedIntervals(Tnum interval) { // TODO: Review how uncertainty is handled here: // Handle unknowns Hstate top = PrecedingState(this.FirstValue, interval.FirstValue); if (top != Hstate.Known) { return(new Tnum(new Hval(null, top))); } // If base Tnum is ever unknown during the time period, return // the state with the proper precedence Hstate baseState = PrecedenceForMissingTimePeriods(this); if (baseState != Hstate.Known) { return(new Tnum(baseState)); } // Start accumulating... Tnum result = new Tnum(0); decimal total = 0; decimal previousVal = 0; // Iterate through the intervals, totaling for (int i = 1; i < interval.TimeLine.Count - 1; i++) { total += Convert.ToDecimal(this.ObjectAsOf(interval.TimeLine.Keys[i]).Val); // Only add changepoint if value actually changes if (total != previousVal) { result.AddState(interval.TimeLine.Keys[i + 1], total); } // Set for next iteration previousVal = total; } return(result); }
/// <summary> /// Determines whether the Tvar is ever the specified boolean val. /// </summary> private Tbool IsEver(Hval val) { // If val is unknown and base Tvar is eternally unknown, // return the typical precedence state if (!val.IsKnown && this.TimeLine.Count == 1) { if (!this.FirstValue.IsKnown) { Hstate s = PrecedingState(this.FirstValue, val); return(new Tbool(s)); } } // If val is unknown, return its state if (!val.IsKnown) { return(new Tbool(val)); } // If the base Tvar is ever val, return true foreach (Hval h in this.TimeLine.Values) { if (h.IsEqualTo(val)) { return(true); } } // If base Tvar has a time period of unknownness, return // the state with the proper precedence Hstate returnState = PrecedenceForMissingTimePeriods(this); if (returnState != Hstate.Known) { return(new Tbool(returnState)); } return(false); }
/// <summary> /// Returns the all-time minimum value of the Tnum. /// </summary> public Tnum Min() { // Deal with unknowns Hstate state = PrecedenceForMissingTimePeriods(this); if (state != Hstate.Known) { return(new Tnum(state)); } // Determine the maximum value decimal min = Convert.ToDecimal(this.FirstValue.Val); foreach (Hval s in TimeLine.Values) { if (Convert.ToDecimal(s.Val) < min) { min = Convert.ToDecimal(s.Val); } } return(new Tnum(min)); }
//********************************************************************* // TEMPORAL "RECURRENCE" FUNCTIONS //********************************************************************* /// <summary> /// Loops (cycles) through numbers over time (e.g. 1 2 3 4 1 2 3 4 ...) /// </summary> public static Tnum Recurrence(Tdate startDate, Tdate endDate, IntervalType interval, int min, int max) { // Handle unknowns Hstate top = PrecedingState(startDate.FirstValue, endDate.FirstValue); if (top != Hstate.Known) { return(new Tnum(new Hval(null, top))); } DateTime start = startDate.ToDateTime; DateTime end = endDate.ToDateTime; Tnum result = new Tnum(); if (start != Time.DawnOf) { result.AddState(Time.DawnOf, 0); } DateTime indexDate = start; int indexNumber = min; while (indexDate < end) { result.AddState(indexDate, Convert.ToString(indexNumber)); indexDate = indexDate.AddInterval(interval, 1); // Reset sequence indexNumber++; if (indexNumber > max) { indexNumber = min; } } result.AddState(end, 0); return(result); }
/// <summary> /// Private non-temporal AND function /// </summary> private static Hval CoreAnd(List <Hval> list) { // One false falsifies the conclusion foreach (Hval h in list) { if (h.IsFalse) { return(new Hval(false)); } } // Any higher-precedence states go next Hstate top = PrecedingStateForLogic(list); if (top != Hstate.Known) { return(new Hval(null, top)); } // Otherwise, true return(new Hval(true)); }
/// <summary> /// Returns the value of a Tvar at a specified point in time. /// </summary> /// <remarks> /// If the Tdate varies over time, only the first value is used. /// </remarks> public T AsOf <T>(Tdate date) where T : Tvar { Hval result; // If base Tvar has eternal, known value, return that. // (In these cases, the Tdate is irrelevant.) if (this.IsEternal && !this.IsEternallyUnknown) { result = this.FirstValue; } // If either the base Tvar or Tdate are unknown... else if (!date.FirstValue.IsKnown || this.IsEternallyUnknown) { Hstate top = PrecedingState(this.FirstValue, date.FirstValue); result = new Hval(null, top); } else { result = this.ObjectAsOf(date.ToDateTime); } return((T)Util.ReturnProperTvar <T>(result)); }
/// <summary> /// Returns the total elapsed days that a Tvar has a given value, /// for each of a given set of intervals. /// Example: meetsAnnualTest = var.ElapsedDaysPerInterval(theYear) > 183; /// </summary> public Tnum TotalElapsedDaysPer(Tnum period) { // If base Tnum is ever unknown during the time period, return // the state with the proper precedence Hstate baseState = PrecedenceForMissingTimePeriods(this); Hstate periodState = PrecedenceForMissingTimePeriods(period); Hstate top = PrecedingState(baseState, periodState); if (top != Hstate.Known) { return(new Tnum(top)); } Tnum result = new Tnum(); int count = period.IntervalValues.Count; for (int i = 0; i < count; i++) { DateTime spanEnd = Time.EndOf; if (i < count - 1) { spanEnd = period.IntervalValues.Keys[i + 1]; } TimeSpan time = this.TotalElapsedTime(period.IntervalValues.Keys[i], spanEnd); // Add the state, but not if it's at the end of time if (period.IntervalValues.Keys[i] < Time.EndOf) { result.AddState(period.IntervalValues.Keys[i], time.TotalDays); } } return(result.Lean); }
public static Tnum IntervalsSince(Tdate startDate, Tdate endDate, IntervalType interval, int?startAt) { // Handle unknowns Hstate top = PrecedingState(startDate.FirstValue, endDate.FirstValue); if (top != Hstate.Known) { return(new Tnum(new Hval(null, top))); } DateTime start = startDate.ToDateTime; DateTime end = endDate.ToDateTime; Tnum result = new Tnum(); if (start != Time.DawnOf) { result.AddState(Time.DawnOf, 0); } DateTime indexDate = start; int? indexNumber = startAt; while (indexDate < end) { result.AddState(indexDate, Convert.ToDecimal(indexNumber)); indexNumber++; indexDate = indexDate.AddInterval(interval, 1); } if (end < Time.EndOf) { result.AddState(end, 0); } return(result); }
public Tdate(Hstate state) { this.SetEternally(state); }
public Tnum(Hstate state) { this.SetEternally(state); }
/// <summary> /// Determines whether the rule should short-circuit before firing the actual rule logic. /// </summary> public static RulePreCheckResponse ShortCircuitValue <T>(string rel, string symIndicator, string questionIndicator, params object[] argList) where T : Tvar { // First, determine whether any of the Things are unknown. Hstate h = EntityArgIsUnknown(argList); if (h != Hstate.Known) { T scv = (T)Util.ReturnProperTvar <T>(new Hval(null, h)); return(new RulePreCheckResponse(scv, true)); } // Extract argument parameters from argList object param1 = argList[0]; object param2 = argList.Length > 1 ? argList[1] : null; object param3 = argList.Length > 2 ? argList[2] : null; // Adds the function node to the proof tree Engine.AddToProofTree(new Facts.Fact(rel, param1, param2, param3, "?")); // Handle symmetrical facts if (symIndicator == "Sym") { // If the fact has not been asserted, add it to the list of unknown facts, so it gets asked. if (!Facts.HasBeenAssertedSym(param1, rel, param2)) { // EXPERIMENTAL: First, ask any assumed facts if (Facts.GetUnknowns) { // if (Facts.Sym(param1, rel, param2).IsEternallyUncertain) // { // Assumptions.AskAssumedFacts(rel, param1, param2, param3); // Assumptions.AskAssumedFacts(rel, param2, param1, param3); // } // "?" indicates that this node is a question to be asked of the user if (questionIndicator == "?") { Facts.AddUnknown(rel, param1, param2, null); } } } // If the fact has been asserted and is not "uncertain", return the asserted value. else { Tbool f = Facts.Sym(param1, rel, param2); if (!f.IsEternallyUncertain) { return(new RulePreCheckResponse(f, true)); } } } // Handle non-symmetrical facts (same code pattern as above) else { if (!Facts.HasBeenAsserted(rel, param1, param2, param3)) { if (Facts.GetUnknowns) { // EXPERIMENTAL: First, ask any assumed facts // Assumptions.AskAssumedFacts(rel, param1, param2, param3, false); if (questionIndicator == "?") { Facts.AddUnknown(rel, param1, param2, param3); } } } else { T f = Facts.QueryTvar <T>(rel, param1, param2, param3); if (!f.IsEternallyUncertain) { return(new RulePreCheckResponse(f, true)); } } } // Otherwise, proceed to examine the rule conditions and sub-rules. return(new RulePreCheckResponse(null, false)); }
public Tbool(Hstate state) { this.SetEternally(state); }
} // State of knowledge of the object. /// <summary> /// Empty or unstated values. /// </summary> public Hval() { Obj = null; State = Hstate.Unstated; }
public Tset(Hstate state) { this.SetEternally(state); }
/// <summary> /// Takes a Tnum representing some value per unit time, and accumulates it /// over a given number of successive time intervals. /// </summary> /// <example> /// Calculate income accumulated over a three month period, where the /// person earned $3,000/month: /// /// Income = MonthlyIncome.SlidingSummedIntervals(TheMonth, 3) /// /// The time units cancel: [$/mo.] * [mo.] yields [$]. /// </example> public Tnum SlidingSummedIntervals(Tnum interval, Tnum windowSize) { // TODO: Review how uncertainty is handled here: // Handle unknowns Hstate top = PrecedingState(this.FirstValue, interval.FirstValue, windowSize.FirstValue); if (top != Hstate.Known) { return(new Tnum(new Hval(null, top))); } // If base Tnum is ever unknown during the time period, return // the state with the proper precedence Hstate baseState = PrecedenceForMissingTimePeriods(this); if (baseState != Hstate.Known) { return(new Tnum(baseState)); } // Handle eternal values if (this.IsEternal) { return(this * windowSize); } // Start accumulating... int num = windowSize.ToHardInt; // Get first accumulated value decimal firstVal = 0; for (int j = 0; j < num; j++) { // Don't walk off the end of the timeline if (j < interval.TimeLine.Count) { firstVal += this.AsOf(interval.TimeLine.Keys [j]).ToHardDecimal; } } Tnum result = new Tnum(firstVal); // Iterate through the subsequent intervals decimal previousVal = firstVal; for (int i = 1; i < interval.TimeLine.Count - num; i++) { // Take the value from the last iteration, and slide it the time window to the right, // subtracting the left interval and adding the new right one. decimal lastOldInterval = Convert.ToDecimal(this.ObjectAsOf(interval.TimeLine.Keys[i - 1]).Val); decimal nextNewInterval = Convert.ToDecimal(this.ObjectAsOf(interval.TimeLine.Keys[i + num - 1]).Val); decimal newVal = previousVal - lastOldInterval + nextNewInterval; // Only add changepoint if value actually changes if (newVal != previousVal) { // The value of an interval is counted after it has elapsed result.AddState(interval.TimeLine.Keys[i + num], newVal); } // Set for next iteration previousVal = newVal; } return(result); }