//****************************************************************************************************** // NumericalAnalysisExtensions.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 09/18/2008 - J. Ritchie Carroll // Generated original version of source code. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // 01/19/2017 - J. Ritchie Carroll // Added option to handle sample size calculations, i.e., n - 1 // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Linq; namespace GSF.NumericalAnalysis { /// /// Defines extension functions related to numerical analysis over a sequence of data. /// public static class NumericalAnalysisExtensions { /// /// Computes the standard deviation over a sequence of values. /// /// Source data sample. /// Set to true to calculate for estimated population size, or false for full population. /// The standard deviation of the sequence. /// is null. /// does not contain enough values to produce a result. public static double StandardDeviation(this IEnumerable source, bool calculateForSample = false) { if ((object)source == null) throw new ArgumentNullException(nameof(source), "source is null"); double[] values = source as double[] ?? source.ToArray(); int sampleCount = values.Length - (calculateForSample ? 1 : 0); if (sampleCount < 1) throw new ArgumentOutOfRangeException(nameof(source), "Not enough sample values provided to produce a result"); double sampleAverage = values.Average(); double totalVariance = values.Select(item => item - sampleAverage).Select(deviation => deviation * deviation).Sum(); return Math.Sqrt(totalVariance / sampleCount); } /// /// Computes the standard deviation over a sequence of values. /// /// Source data sample. /// Used to map value from enumerable of to enumerable of . /// Set to true to calculate for estimated population size, or false for full population. /// The standard deviation of the sequence. /// is null. /// does not contain enough values to produce a result. /// Type of source used to extract double. public static double StandardDeviation(this IEnumerable source, Func selector, bool calculateForSample = false) { if ((object)source == null) throw new ArgumentNullException(nameof(source), "source is null"); return source.Select(selector).StandardDeviation(calculateForSample); } /// /// Computes the standard deviation over a sequence of values. /// /// Source data sample. /// Set to true to calculate for estimated population size, or false for full population. /// The standard deviation of the sequence. /// is null. /// does not contain enough values to produce a result. public static decimal StandardDeviation(this IEnumerable source, bool calculateForSample = false) { if ((object)source == null) throw new ArgumentNullException(nameof(source), "source is null"); decimal[] values = source as decimal[] ?? source.ToArray(); int sampleCount = values.Length - (calculateForSample ? 1 : 0); if (sampleCount < 1) throw new ArgumentOutOfRangeException(nameof(source), "Not enough sample values provided to produce a result"); decimal sampleAverage = values.Average(); decimal totalVariance = values.Select(item => item - sampleAverage).Select(deviation => deviation * deviation).Sum(); return (decimal)Math.Sqrt((double)(totalVariance / sampleCount)); } /// /// Computes the standard deviation over a sequence of values. /// /// Source data sample. /// Used to map value from enumerable of to enumerable of . /// Set to true to calculate for estimated population size, or false for full population. /// The standard deviation of the sequence. /// is null. /// does not contain enough values to produce a result. /// Type of source used to extract decimal. public static decimal StandardDeviation(this IEnumerable source, Func selector, bool calculateForSample = false) { if ((object)source == null) throw new ArgumentNullException(nameof(source), "source is null"); return source.Select(selector).StandardDeviation(calculateForSample); } /// /// Computes the standard deviation over a sequence of values. /// /// Source data sample. /// Set to true to calculate for estimated population size, or false for full population. /// The standard deviation of the sequence. /// is null. /// does not contain enough values to produce a result. public static float StandardDeviation(this IEnumerable source, bool calculateForSample = false) { if ((object)source == null) throw new ArgumentNullException(nameof(source), "source is null"); float[] values = source as float[] ?? source.ToArray(); int sampleCount = values.Length - (calculateForSample ? 1 : 0); if (sampleCount < 1) throw new ArgumentOutOfRangeException(nameof(source), "Not enough sample values provided to produce a result"); float sampleAverage = values.Average(); float totalVariance = values.Select(item => item - sampleAverage).Select(deviation => deviation * deviation).Sum(); return (float)Math.Sqrt(totalVariance / sampleCount); } /// /// Computes the standard deviation over a sequence of values. /// /// Source data sample. /// Used to map value from enumerable of to enumerable of . /// Set to true to calculate for estimated population size, or false for full population. /// The standard deviation of the sequence. /// is null. /// does not contain enough values to produce a result. /// Type of source used to extract float. public static float StandardDeviation(this IEnumerable source, Func selector, bool calculateForSample = false) { if ((object)source == null) throw new ArgumentNullException(nameof(source), "source is null"); return source.Select(selector).StandardDeviation(calculateForSample); } } }