From 758458121eda330b960731d044adeac8a6661a85 Mon Sep 17 00:00:00 2001 From: alondria Date: Sun, 10 Feb 2008 21:28:41 +0000 Subject: [PATCH] Implements llListStatistics() and a bunch-o-LSL_Types.list statistical methods. Added LIST_STAT_HARMONIC_MEAN in addition to LL's LIST_STAT_* --- .../ScriptEngine/Common/LSL_BaseClass.cs | 13 +- .../Common/LSL_BuiltIn_Commands.cs | 44 +++- .../Region/ScriptEngine/Common/LSL_Types.cs | 229 ++++++++++++++++++ 3 files changed, 282 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BaseClass.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BaseClass.cs index 905ba7f99a..3aea72ba9b 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_BaseClass.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_BaseClass.cs @@ -2186,9 +2186,20 @@ namespace OpenSim.Region.ScriptEngine.Common public const int STRING_TRIM_HEAD = 1; public const int STRING_TRIM_TAIL = 2; public const int STRING_TRIM = 3; + public const int LIST_STAT_RANGE = 0; + public const int LIST_STAT_MIN = 1; + public const int LIST_STAT_MAX = 2; + public const int LIST_STAT_MEAN = 3; + public const int LIST_STAT_MEDIAN = 4; + public const int LIST_STAT_STD_DEV = 5; + public const int LIST_STAT_SUM = 6; + public const int LIST_STAT_SUM_SQUARES = 7; + public const int LIST_STAT_NUM_COUNT = 8; + public const int LIST_STAT_GEOMETRIC_MEAN = 9; + public const int LIST_STAT_HARMONIC_MEAN = 100; // Can not be public const? public vector ZERO_VECTOR = new vector(0.0, 0.0, 0.0); public rotation ZERO_ROTATION = new rotation(0.0, 0, 0.0, 1.0); - + } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs index fee36f0743..441d2fdb1a 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs @@ -2134,7 +2134,7 @@ namespace OpenSim.Region.ScriptEngine.Common string ret = String.Empty; foreach (object o in src.Data) { - ret = ret + o.ToString() + ","; + ret = ret + o.ToString() + ", "; } ret = ret.Substring(0, ret.Length - 2); return ret; @@ -3376,8 +3376,46 @@ namespace OpenSim.Region.ScriptEngine.Common public double llListStatistics(int operation, LSL_Types.list src) { m_host.AddScriptLPS(1); - NotImplemented("llListStatistics"); - return 0; + LSL_Types.list nums = LSL_Types.list.ToDoubleList(src); + switch (operation) + { + case LSL_BaseClass.LIST_STAT_RANGE: + return nums.Range(); + break; + case LSL_BaseClass.LIST_STAT_MIN: + return nums.Min(); + break; + case LSL_BaseClass.LIST_STAT_MAX: + return nums.Max(); + break; + case LSL_BaseClass.LIST_STAT_MEAN: + return nums.Mean(); + break; + case LSL_BaseClass.LIST_STAT_MEDIAN: + return nums.Median(); + break; + case LSL_BaseClass.LIST_STAT_NUM_COUNT: + return nums.NumericLength(); + break; + case LSL_BaseClass.LIST_STAT_STD_DEV: + return nums.StdDev(); + break; + case LSL_BaseClass.LIST_STAT_SUM: + return nums.Sum(); + break; + case LSL_BaseClass.LIST_STAT_SUM_SQUARES: + return nums.SumSqrs(); + break; + case LSL_BaseClass.LIST_STAT_GEOMETRIC_MEAN: + return nums.GeometricMean(); + break; + case LSL_BaseClass.LIST_STAT_HARMONIC_MEAN: + return nums.HarmonicMean(); + break; + default: + return 0.0; + break; + } } public int llGetUnixTime() diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Common/LSL_Types.cs index 77ca769ac8..3cc45bad35 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_Types.cs @@ -28,6 +28,7 @@ using System; using System.Text.RegularExpressions; +using System.Collections; namespace OpenSim.Region.ScriptEngine.Common { @@ -435,6 +436,199 @@ namespace OpenSim.Region.ScriptEngine.Common } } + #region CSV Methods + + public static list FromCSV(string csv) + { + return new list(csv.Split(',')); + } + + public string ToCSV() + { + string ret = ""; + foreach(object o in this.Data) + { + if(ret == "") + { + ret = o.ToString(); + } + else + { + ret = ret + ", " + o.ToString(); + } + } + return ret; + } + #endregion + + #region Statistic Methods + + public double Min() + { + double minimum = double.PositiveInfinity; + double entry; + for (int i = 0; i < Data.Length; i++) + { + if (double.TryParse(Data[i].ToString(), out entry)) + { + if (entry < minimum) minimum = entry; + } + } + return minimum; + } + + public double Max() + { + double maximum = double.NegativeInfinity; + double entry; + for (int i = 0; i < Data.Length; i++) + { + if (double.TryParse(Data[i].ToString(), out entry)) + { + if (entry > maximum) maximum = entry; + } + } + return maximum; + } + + public double Range() + { + return (this.Max() / this.Min()); + } + + public int NumericLength() + { + int count = 0; + double entry; + for (int i = 0; i < Data.Length; i++) + { + if (double.TryParse(Data[i].ToString(), out entry)) + { + count++; + } + } + return count; + } + + public static list ToDoubleList(list src) + { + list ret = new list(); + double entry; + for (int i = 0; i < src.Data.Length - 1; i++) + { + if (double.TryParse(src.Data[i].ToString(), out entry)) + { + ret.Add(entry); + } + } + return ret; + } + + public double Sum() + { + double sum = 0; + double entry; + for (int i = 0; i < Data.Length; i++) + { + if (double.TryParse(Data[i].ToString(), out entry)) + { + sum = sum + entry; + } + } + return sum; + } + + public double SumSqrs() + { + double sum = 0; + double entry; + for (int i = 0; i < Data.Length; i++) + { + if (double.TryParse(Data[i].ToString(), out entry)) + { + sum = sum + Math.Pow(entry, 2); + } + } + return sum; + } + + public double Mean() + { + return (this.Sum() / this.NumericLength()); + } + + public void NumericSort() + { + IComparer Numeric = new NumericComparer(); + Array.Sort(Data, Numeric); + } + + public void AlphaSort() + { + IComparer Alpha = new AlphaCompare(); + Array.Sort(Data, Alpha); + } + + public double Median() + { + return Qi(0.5); + } + + public double GeometricMean() + { + double ret = 1.0; + list nums = list.ToDoubleList(this); + for (int i = 0; i < nums.Data.Length; i++) + { + ret *= (double)nums.Data[i]; + } + return Math.Exp(Math.Log(ret) / (double)nums.Data.Length); + } + + public double HarmonicMean() + { + double ret = 0.0; + list nums = list.ToDoubleList(this); + for (int i = 0; i < nums.Data.Length; i++) + { + ret += 1.0 / (double)nums.Data[i]; + } + return ((double)nums.Data.Length / ret); + } + + public double Variance() + { + double s = 0; + list num = list.ToDoubleList(this); + for (int i = 0; i < num.Data.Length; i++) + { + s += Math.Pow((double)num.Data[i], 2); + } + return (s - num.Data.Length * Math.Pow(num.Mean(), 2)) / (num.Data.Length - 1); + } + + public double StdDev() + { + return Math.Sqrt(this.Variance()); + } + + public double Qi(double i) + { + list j = this; + j.NumericSort(); + double ret; + if (Math.Ceiling(this.Length * i) == this.Length * i) + { + return (double)((double)j.Data[(int)(this.Length * i - 1)] + (double)j.Data[(int)(this.Length * i)]) / 2; + } + else + { + return (double)j.Data[((int)(Math.Ceiling(this.Length * i))) - 1]; + } + } + + #endregion + public string ToPrettyString() { string output; @@ -459,7 +653,42 @@ namespace OpenSim.Region.ScriptEngine.Common return output; } + public class AlphaCompare : IComparer + { + int IComparer.Compare(object x, object y) + { + return string.Compare(x.ToString(), y.ToString()); + } + } + public class NumericComparer : IComparer + { + int IComparer.Compare(object x, object y) + { + double a; + double b; + if (!double.TryParse(x.ToString(), out a)) + { + a = 0.0; + } + if (!double.TryParse(y.ToString(), out b)) + { + b = 0.0; + } + if (a < b) + { + return -1; + } + else if (a == b) + { + return 0; + } + else + { + return 1; + } + } + } public override string ToString() {