/// <summary> /// HELPER: Finds the IDW lambda denominator. /// </summary> /// <returns></returns> private double calcLambdaDenominator(List<Measurement> nearest, Measurement missing) { double sum = 0; foreach (Measurement currNearest in nearest) { sum += this.calcLambdaNumerator(currNearest, missing); } return sum; }
/// <summary> /// HELPER: Finds disatances... used to find di (and dk) values. /// /// NOTE: This is currently the least optimized function according to the profiler... I wonder if theres a better 3rd party math library for .NET? /// </summary> /// <returns></returns> private double calcD(Measurement nearest, Measurement missing) { return Math.Sqrt( Math.Pow(nearest.X - missing.X, 2) + Math.Pow(nearest.Y - missing.Y, 2) + // Notice the TVal is multipled by a scale factor... to allow us control over the range. // IE 1-365 or 0.01 - 3.65. Math.Pow(this.timeCoefficient * nearest.Time.TVal - this.timeCoefficient * missing.Time.TVal, 2) ); }
private Measurement parseLine(string text) { // Tokenize the string. string[] tokens = text.Split(new string[] {this.delimiter}, StringSplitOptions.RemoveEmptyEntries); // Populate the measurement. Measurement measurement = new Measurement(); measurement.Time = (ITimeDomain)Activator.CreateInstance(this.timeDomain.GetType()); for (int i = 0; i < tokens.Length; i++) { switch (this.columns[i]) { case Columns.ID: measurement.ID = long.Parse(tokens[i]); break; case Columns.X: measurement.X = float.Parse(tokens[i]); break; case Columns.Y: measurement.Y = float.Parse(tokens[i]); break; case Columns.Value: measurement.Value = float.Parse(tokens[i]); break; case Columns.Year: measurement.Time.SetProperty("year", int.Parse(tokens[i])); break; case Columns.Quarter: measurement.Time.SetProperty("quarter", int.Parse(tokens[i])); break; case Columns.Month: measurement.Time.SetProperty("month", int.Parse(tokens[i])); break; case Columns.Day: measurement.Time.SetProperty("day", int.Parse(tokens[i])); break; } } return measurement; }
/// <summary> /// HELPER: Finds the IDW lambda coefficient for element i. /// </summary> /// <returns></returns> private double calcLambdaNumerator(Measurement nearest, Measurement missing) { double distance = this.calcD(nearest, missing); return Math.Pow(1 / distance, this.exponent); }
private void InnerLoop(object state) { // Need to extract state values from the state package object. InnerLoopState openState = (InnerLoopState)state; Measurement currMissing = openState.currMissing; List<Measurement> results = openState.results; // This is the time domain of the KNOWN values. // We are trying to calculate every unknown element for every value bewteen t=0 and tmax of this time domain. ITimeDomain t = (ITimeDomain)Activator.CreateInstance(this.known[0].Time.GetType()); t.SetProperty("year", this.known[0].Time.DateTime.Year); // Set the year to the year of the first known item. // No example data sets span multiple years. This is kindof undefined behavior. // Iterate over all t values in this time domain. for (int i = 0; i < t.TMax; i++) { currMissing.Time = t; // Use the known time domain as the time domain of the missing data set. List<Measurement> nearest = this.calcNearest(currMissing); // Get the n nearest known values. // Iterate over the nearset known values and sum up their lambdas. double sum = 0.0d; foreach (Measurement currNearest in nearest) { double numerator = this.calcLambdaNumerator(currNearest, currMissing); double denominator = this.calcLambdaDenominator(nearest, currMissing); double lambda = numerator / denominator; double value = lambda * currNearest.Value; sum += value; } // We can build a single output model now. Measurement output = new Measurement(); output.ID = currMissing.ID; output.X = currMissing.X; output.Y = currMissing.Y; output.Time = (ITimeDomain)Activator.CreateInstance(this.known[0].Time.GetType()); output.Time.SetT(t.TVal); output.Time.SetProperty("year", t.DateTime.Year); output.Value = (float)sum; results.Add(output); // We now store this model in a new list. t.IncrementT(); // Increment the time domain value. this.Current++; // Report row increment... this is how the progressbar knows. } }
/// <summary> /// Finds the n known measurements with the smallest euclidian distance to x, y, t in nearly O(n) time. /// </summary> private List<Measurement> calcNearest(Measurement measure) { DistanceMeasurement[] results = new DistanceMeasurement[this.nearest]; foreach (Measurement curr in this.known) { double distance = this.calcD(curr, measure); // Test if this is a new smallest value. bool shift = false; DistanceMeasurement shifted = null; for (int i = 0; i < results.Length; i++) { // A smaller value was found continue shifting the array. if (shift) { DistanceMeasurement temp = results[i]; results[i] = shifted; shifted = temp; } // Test if this is one of the first n elements. else if (results[i] == null) { // Build a DistanceMeasurement for this value. DistanceMeasurement dm = new DistanceMeasurement(); dm.Measurement = curr; dm.Distance = distance; results[i] = dm; } // Test if value smaller than current element. else if (distance < results[i].Distance) { // Build a DistanceMeasurement for this value. DistanceMeasurement dm = new DistanceMeasurement(); dm.Measurement = curr; dm.Distance = distance; // Swap in this value. shifted = results[i]; results[i] = dm; // Enter shift mode. shift = true; } } } // Convert from DistanceMeasurement to Measurement. List<Measurement> nearest = new List<Measurement>(); foreach (DistanceMeasurement curr in results) { nearest.Add(curr.Measurement); } return nearest; }