Exemple #1
0
        /// <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;
        }
        /// <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;
        }
        /// <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>
        /// Finds the Tset associated with a given Tnum value on a given date.
        /// </summary>
        private static Hval AssociatedTset(List<Tuple<Tset,Tnum>> setFcnVals, Tnum val, DateTime asOfDate)
        {
            foreach(Tuple<Tset,Tnum> t in setFcnVals)
            {
                // Handle uncertainty
                Hval s = t.Item2.AsOf(asOfDate).FirstValue;
                Hval v = val.AsOf(asOfDate).FirstValue;
                if (s.IsUncertain && v.IsUncertain)     return new Hval(null);  // Not hitting this for some reason...
                if (s.IsUnstated && v.IsUnstated)       return new Hval(null, Hstate.Unstated);
                if (s.IsStub && v.IsStub)               return new Hval(null, Hstate.Stub);

                // Compare numeric values
                if (t.Item2.AsOf(asOfDate) == val.AsOf(asOfDate))
                {
                    // Tsets created in Combos() are eternal, so FirstValue is ok here
                    return t.Item1.FirstValue;
                }
            }
            return new Hval(null, Hstate.Stub);
        }
Exemple #6
0
        /// <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>
        /// Finds the total of a Tnum, summed over the given intervals between two 
        /// dates (start and end).
        /// </summary>
        /// <example>
        ///   AnnualIncome2014 = MonthlyIncome.TotalSummedIntervals(TheMonth, 2014-01-01, 2014-12-31)
        /// </example>
        public Tnum TotalSummedIntervals(Tnum interval, Tdate start, Tdate end)
        {
            Tnum rsi = RunningSummedIntervals(interval);

            return rsi.AsOf(end) - rsi.AsOf(start);
        }
        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>
 /// Maps a function to a timeline, starting on a given date.
 /// </summary>
 //  TODO: Get rid of Time.IntervalType
 public static Tnum TemporalMap(Func<Tnum,Tnum> fcn, Tdate startDate, Tnum intervalCount, Time.IntervalType intervalType)
 {
     return fcn(Time.IntervalsSince(startDate, startDate.AddYears(intervalCount), intervalType));
 }
        /// <summary>
        /// Implements Tset.OptimalSubset(Tnum fcn).
        /// </summary>
        private static Tset OptimalSubsetCore(Tset theSet, Func<Tset,Tnum> fcn)
        {
            Tset result = new Tset();

            // For each time period in the Tset
            for (int i=0; i < theSet.IntervalValues.Count; i++)
            {
                // Get some useful values
                Hval thisSetVal = theSet.IntervalValues.Values[i];
                DateTime start = theSet.IntervalValues.Keys[i];

                // Handle uncertainty of theSet
                if (!thisSetVal.IsKnown)
                {
                    result.AddState(start, thisSetVal);
                }
                else
                {
                    // Date parameters and set members of that time interval
                    List<Thing> mems = (List<Thing>)thisSetVal.Val;
                    DateTime end = Time.EndOf;
                    try {end = theSet.IntervalValues.Keys[i+1];} catch {}

                    // For each combination of set members, get the associated fcn val
                    List<Tuple<Tset,Tnum>> setFcnVals = new List<Tuple<Tset,Tnum>>();
                    Tnum maxVal = new Tnum(Decimal.MinValue);
                    foreach (Tset s in Combos(mems))
                    {
                        // Invoke the fcn for that subset
                        Tnum val = fcn(s);

                        // Save the result of the fcn and the associated Tset
                        setFcnVals.Add(Tuple.Create(s, val));

                        // Update the running maximum value
                        maxVal = Max(maxVal, val);
                    }

                    // Foreach changepoint in maxVal, find the associated Tset
                    for (int j=0; j < maxVal.IntervalValues.Count; j++)
                    {
                        DateTime mDate = maxVal.IntervalValues.Keys[j];
                        if (mDate >= start && mDate < end)
                        {
                            // Get the associated Tset
                            Hval outSet = AssociatedTset(setFcnVals, maxVal, mDate);

                            // Add the change point
                            result.AddState(mDate, outSet);
                        }
                    }
                }
            }

            return result;
        }
Exemple #11
0
 /// <summary>
 /// Returns a Tbool in which the values are shifted in time relative to
 /// the dates.
 /// </summary>
 public Tbool Shift(int offset, Tnum temporalPeriod)
 {
     return this.Shift<Tbool>(offset, temporalPeriod);
 }
Exemple #12
0
 /// <summary>
 /// Cosine
 /// </summary>
 public static Tnum Cos(Tnum tn)    
 {
     return ApplyFcnToTimeline<Tnum>(x => CoreCos(x), tn);
 }
Exemple #13
0
 /// <summary>
 /// A raised to the B power
 /// </summary>
 public static Tnum Pow(Tnum tnA, Tnum tnB)
 {
     return(ApplyFcnToTimeline <Tnum>(x => CorePow(x), tnA, tnB));
 }
Exemple #14
0
 /// <summary>
 /// Adds a specified number of years to each DateTime in a Tdate.
 /// Negative values are subtracted.
 /// </summary>
 public Tdate AddYears(Tnum days)
 {
     return ApplyFcnToTimeline<Tdate>(x => CoreAddYears(x), this, days);
 }    
Exemple #15
0
 /// <summary>
 /// Returns a Tset in which the values are shifted in time relative to
 /// the dates.
 /// </summary>
 public Tset Shift(int offset, Tnum temporalPeriod)
 {
     return this.Shift<Tset>(offset, temporalPeriod);
 }
Exemple #16
0
 /// <summary>
 /// Returns a Tdate in which the last value in a time period is the
 /// final value.
 /// </summary>
 public Tdate PeriodEndVal(Tnum temporalPeriod)
 {
     return(this.PeriodEndVal <Tdate>(temporalPeriod).Lean);
 }
Exemple #17
0
        /// <summary>
        /// Returns true in the period during which a given date falls
        /// Example: (2013-04-15).IsInPeriod(TheYear) is true for all of 2013, and otherwise false
        /// </summary>
        public Tbool IsInPeriod(Tnum interval)
        {
            // The event + 1 tick (temporal)
            Tbool theEvent = Time.IsBetween(this, new Tdate(this.ToDateTime.AddTicks(1)));

            // True during the interval when the event occurs
            return theEvent.EverPer(interval);
        }
Exemple #18
0
 /// <summary>
 /// Returns a Tdate in which the values are shifted in time relative to
 /// the dates.
 /// </summary>
 public Tdate Shift(int offset, Tnum temporalPeriod)
 {
     return(this.Shift <Tdate>(offset, temporalPeriod));
 }
Exemple #19
0
 /// <summary>
 /// ArcTan
 /// </summary>
 public static Tnum ArcTan(Tnum tn)
 {
     return(ApplyFcnToTimeline <Tnum>(x => CoreArcTan(x), tn));
 }
Exemple #20
0
 /// <summary>
 /// Cosine
 /// </summary>
 public static Tnum Cos(Tnum tn)
 {
     return(ApplyFcnToTimeline <Tnum>(x => CoreCos(x), tn));
 }
Exemple #21
0
 /// <summary>
 /// Logarithm of n to base b
 /// </summary>
 public static Tnum Log(Tnum b, Tnum n)
 {
     return(ApplyFcnToTimeline <Tnum>(x => CoreLog(x), b, n));
 }
Exemple #22
0
 /// <summary>
 /// Returns a Tset in which the last value in a time period is the
 /// final value.
 /// </summary>
 public Tset PeriodEndVal(Tnum temporalPeriod)
 {
     return this.PeriodEndVal<Tset>(temporalPeriod).Lean;
 }
Exemple #23
0
 /// <summary>
 /// Logarithm of n to base b
 /// </summary>
 public static Tnum Log(Tnum b, Tnum n)    
 {
     return ApplyFcnToTimeline<Tnum>(x => CoreLog(x), b, n);
 }
Exemple #24
0
 /// <summary>
 /// Square root
 /// </summary>
 public static Tnum Sqrt(Tnum tn)
 {
     return(ApplyFcnToTimeline <Tnum>(x => CoreSqrt(x), tn));
 }
Exemple #25
0
 /// <summary>
 /// ArcTan
 /// </summary>
 public static Tnum ArcTan(Tnum tn)    
 {
     return ApplyFcnToTimeline<Tnum>(x => CoreArcTan(x), tn);
 }
Exemple #26
0
 // ********************************************************************
 // ROUNDING FUNCTIONS
 // ********************************************************************
 
 /// <summary>
 /// Rounds a value to the nearest multiple of a given number.  By default, 
 /// it rounds up in case of a tie.
 /// </summary>
 public Tnum RoundToNearest(Tnum multiple)
 {
     return RoundToNearest(multiple,false);
 }
Exemple #27
0
        /// <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;
        }
Exemple #28
0
 public Tnum RoundToNearest(Tnum multiple, Tbool breakTieByRoundingDown)
 {
     Tnum diff = this % multiple;
     return Switch<Tnum>(() => diff > multiple / 2, () => this - diff + multiple,
                         ()=> diff < multiple / 2 || breakTieByRoundingDown, ()=> this - diff,
                         () => true, () => this - diff + multiple);
 }
Exemple #29
0
 /// <summary>
 /// Rounds a value down to the next multiple of a given number.
 /// </summary>
 public Tnum RoundDown(Tnum multiple)
 {
     return(Switch <Tnum>(() => this % multiple != 0, () => this - (this % multiple),
                          () => true, () => this));
 }
        /// <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;
        }
Exemple #31
0
 /// <summary>
 /// Returns a Tbool in which the last value in a time period is the
 /// final value.
 /// </summary>
 public Tbool PeriodEndVal(Tnum temporalPeriod)
 {
     return this.PeriodEndVal<Tbool>(temporalPeriod).Lean;
 }
Exemple #32
0
        /// <summary>
        /// Returns the total number of elapsed intervals between two dates.
        /// </summary>
        public Tnum TotalElapsedIntervals(Tnum interval, Tdate start, Tdate end)
        {
            Tnum rei = RunningElapsedIntervals(interval);

            return rei.AsOf(end) - rei.AsOf(start);
        }
        //*********************************************************************
        // 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;
        }
Exemple #34
0
        /// <summary>
        /// Finds the total of a Tnum, summed over the given intervals between two
        /// dates (start and end).
        /// </summary>
        /// <example>
        ///   AnnualIncome2014 = MonthlyIncome.TotalSummedIntervals(TheMonth, 2014-01-01, 2014-12-31)
        /// </example>
        public Tnum TotalSummedIntervals(Tnum interval, Tdate start, Tdate end)
        {
            Tnum rsi = RunningSummedIntervals(interval);

            return(rsi.AsOf(end) - rsi.AsOf(start));
        }
Exemple #35
0
        // ********************************************************************
        // ROUNDING FUNCTIONS
        // ********************************************************************

        /// <summary>
        /// Rounds a value to the nearest multiple of a given number.  By default,
        /// it rounds up in case of a tie.
        /// </summary>
        public Tnum RoundToNearest(Tnum multiple)
        {
            return(RoundToNearest(multiple, false));
        }
Exemple #36
0
 /// <summary>
 /// Natural logarithm
 /// </summary>
 public static Tnum Log(Tnum tn)    
 {
     return ApplyFcnToTimeline<Tnum>(x => CoreNatLog(x), tn);
 }
Exemple #37
0
 /// <summary>
 /// Rounds a value down to the next multiple of a given number.
 /// </summary>
 public Tnum RoundDown(Tnum multiple)
 {
     return Switch<Tnum>(() => this % multiple != 0, () => this - (this % multiple),
                         () => true, () => this);
 }
Exemple #38
0
 /// <summary>
 /// Natural logarithm
 /// </summary>
 public static Tnum Log(Tnum tn)
 {
     return(ApplyFcnToTimeline <Tnum>(x => CoreNatLog(x), tn));
 }
Exemple #39
0
        /// <summary>
        /// Provides a running count of how many intervals (years, days, etc.) a Tbool 
        /// has been true within some sliding window of time.  At the end of that sliding 
        /// window, this function returns the amount of time that has elapsed within the 
        /// window during which the Tbool was true.
        /// </summary>
        /// <remarks>
        /// Example: For a given Tbool, at any given point in time, for how many days during the
        /// previous 3 days is the Tbool true?
        /// 
        ///                     tb = <FTTTFTTTFFFF>
        ///      tb.SEI(3, TheDay) = <001232223210>
        /// </remarks>
        public Tnum SlidingElapsedIntervals(Tnum interval, Tnum windowSize)
        {
            // If a Tbool is eternally true, return windowSize
            if (this.IsTrue)
            {
                return windowSize;
            }

            // The number of true intervals in a sliding window of time equals
            // the running count as of time1 minus the running count as of time0.
            Tnum r = this.RunningElapsedIntervals(interval);

            int size = Convert.ToInt32(windowSize.FirstValue.Val) * -1;

            // Counts the current inerval
            return r - r.Shift(size, interval);
        }
Exemple #40
0
 /// <summary>
 /// A raised to the B power
 /// </summary>
 public static Tnum Pow(Tnum tnA, Tnum tnB)    
 {
     return ApplyFcnToTimeline<Tnum>(x => CorePow(x), tnA, tnB);
 }
Exemple #41
0
 /// <summary>
 /// Square root
 /// </summary>
 public static Tnum Sqrt(Tnum tn)    
 {
     return ApplyFcnToTimeline<Tnum>(x => CoreSqrt(x), tn);
 }
Exemple #42
0
        /// <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);
        }