00001 using System;
00002 using System.Collections;
00003 using System.Collections.Generic;
00004 using System.Linq;
00005 using System.Windows.Forms;
00006
00007 [assembly: CLSCompliant(true)]
00008 namespace StephenAshley.Biostatistics
00009 {
00010 using NUMBER = Decimal;
00011
00012 #region ***delegates***
00023 public delegate ColumnData GroupValidatorDelegateClass(TextBox[] textBoxesArray,
00024 Int32 columnIndex);
00025 #endregion
00026
00027 #region *********enums**********
00032 public enum Status
00033 {
00037 OneElement,
00041 TwoElements,
00045 MoreThanTwoElements,
00049 Empty,
00053 FewerThanThree,
00058 OK,
00062 Undetermined
00063 }
00064 #endregion
00065
00072 public class Group : IEnumerable
00073 {
00074 #region ******** fields ********
00078 protected List<NUMBER> dataList;
00079 private readonly Int32 iSize;
00080 private readonly bool isFixedSize;
00081 private readonly bool isReadOnly;
00082 private ColumnData columnData;
00086 protected Int16 iIdentificationNumber;
00087 #endregion
00088 #region ***** constructors *****
00089
00093 public Group() : this(0) { }
00094
00099 public Group(Int16 IDNumber)
00100 {
00101 iIdentificationNumber = IDNumber;
00102 isFixedSize =
00103 isReadOnly = false;
00104 dataList = new List<NUMBER>();
00105 columnData = new ColumnData(false, Status.Undetermined);
00106 }
00107
00116 public Group(Int16 IDNumber, IList data)
00117 : this(IDNumber)
00118 {
00119 if (data == null)
00120 throw new BiostatisticsException(
00121 "groups parameter in contructor in Group is a null reference.");
00122
00123 foreach (object obj in data)
00124 Add(obj);
00125 }
00126
00140 public Group(Int16 IDNumber, IList data,
00141 bool fixedSize, bool readOnly)
00142 : this(IDNumber, data)
00143 {
00144 if (readOnly && !fixedSize)
00145 throw new BiostatisticsException(
00146 "Parameter fixedSize must be set to True if parameter readOnly is set to True.");
00147
00148 isFixedSize = fixedSize;
00149 isReadOnly = readOnly;
00150 iSize = dataList.Count();
00151 }
00152
00162 public Group(Group group)
00163 : this(group.Number())
00164 {
00165 if (group == null)
00166 throw new BiostatisticsException(
00167 "group parameter in Group constructor is a null reference.");
00168
00169 foreach (NUMBER value in group)
00170 {
00171 dataList.Add(value);
00172 }
00173 }
00174
00187 public Group(Group group,
00188 bool fixedSize, bool readOnly)
00189 : this(group)
00190 {
00191 isFixedSize = fixedSize;
00192 isReadOnly = readOnly;
00193 }
00194
00213 public Group(Int16 IDNumber, TextBox[] textBoxesArray,
00214 GroupValidatorDelegateClass groupValidator, Int32 index)
00215 : this(IDNumber)
00216 {
00217 if (textBoxesArray == null)
00218 throw new BiostatisticsException(
00219 "textBoxesArray in Group constructor is null.");
00220 if (groupValidator == null)
00221 throw new BiostatisticsException(
00222 "groupValidator parameter in Group constructor is null.");
00223
00224 columnData = groupValidator(textBoxesArray, index);
00225 if (columnData.IsValid())
00226 {
00227 foreach (TextBox textbox in textBoxesArray)
00228 {
00229 NUMBER decTemp;
00230 try
00231 {
00232 decTemp = Convert.ToDecimal(textbox.Text);
00233 }
00234 catch (Exception)
00235 {
00236 throw new BiostatisticsException("textbox.Text is not a Decimal.");
00237 }
00238 dataList.Add(decTemp);
00239 }
00240 }
00241 }
00242 #endregion
00243 #region ******* methods ********
00253 public void Add(Object item)
00254 {
00255 if (isReadOnly)
00256 throw new BiostatisticsException(
00257 "Addition of item to a read-only Group.");
00258
00259 if (isFixedSize && n() >= iSize)
00260 throw new BiostatisticsException(
00261 "Addition of item to a full fixed-size Group.");
00262 Type type = item.GetType();
00263 try
00264 {
00265 if (type == typeof(NUMBER))
00266 dataList.Add((NUMBER)item);
00267 else if (type == typeof(double))
00268 dataList.Add(new NUMBER((double)item));
00269 else if (type == typeof(float))
00270 dataList.Add(new NUMBER((float)item));
00271 else if (type == typeof(int))
00272 dataList.Add(new NUMBER((int)item));
00273 else if (type == typeof(int[]))
00274 dataList.Add(new NUMBER((int[])item));
00275 else if (type == typeof(long))
00276 dataList.Add(new NUMBER((long)item));
00277 else if (type == typeof(uint))
00278 dataList.Add(new NUMBER((uint)item));
00279 else if (type == typeof(ulong))
00280 dataList.Add(new NUMBER((ulong)item));
00281 else if (type == typeof(byte))
00282 dataList.Add(new NUMBER((byte)item));
00283 else if (type == typeof(sbyte))
00284 dataList.Add(new NUMBER((sbyte)item));
00285 else
00286 {
00287 throw new BiostatisticsException(
00288 "Item to be added to Group cannot be converted to a Decimal.");
00289 }
00290 }
00291 catch
00292 {
00293 throw new BiostatisticsException(
00294 "Item to be added to Group cannot be converted to a Decimal.");
00295 }
00296 }
00297
00311 public void AddRange(IList data)
00312 {
00313 if (isReadOnly)
00314 throw new BiostatisticsException(
00315 "Addition of items to a read-only Group.");
00316 if (isFixedSize && data.Count + n() >= iSize)
00317 throw new BiostatisticsException(
00318 "Addition of items would exceed the size of a fixed-size Group.");
00319
00320 List<NUMBER> lstItems = new List<NUMBER>();
00321 foreach (Object item in data)
00322 {
00323 Type type = item.GetType();
00324 try
00325 {
00326 if (type == typeof(NUMBER))
00327 lstItems.Add((NUMBER)item);
00328 else if (type == typeof(double))
00329 lstItems.Add(new NUMBER((double)item));
00330 else if (type == typeof(float))
00331 lstItems.Add(new NUMBER((float)item));
00332 else if (type == typeof(int))
00333 lstItems.Add(new NUMBER((int)item));
00334 else if (type == typeof(int[]))
00335 lstItems.Add(new NUMBER((int[])item));
00336 else if (type == typeof(long))
00337 lstItems.Add(new NUMBER((long)item));
00338 else if (type == typeof(uint))
00339 lstItems.Add(new NUMBER((uint)item));
00340 else if (type == typeof(ulong))
00341 lstItems.Add(new NUMBER((ulong)item));
00342 else if (type == typeof(byte))
00343 lstItems.Add(new NUMBER((byte)item));
00344 else if (type == typeof(sbyte))
00345 lstItems.Add(new NUMBER((sbyte)item));
00346 else
00347 {
00348 throw new BiostatisticsException(
00349 "Parameter sourceCollection contains an element that cannot be converted to a Decimal.");
00350 }
00351 }
00352 catch
00353 {
00354 throw new BiostatisticsException(
00355 "Parameter sourceCollection contains an element that cannot be converted to a Decimal.");
00356 }
00357 }
00358 dataList.AddRange(lstItems);
00359 }
00360
00366 public Group AsFixedSize()
00367 {
00368 return new Group(this, true, false);
00369 }
00370
00376 public Group AsReadOnly()
00377 {
00378 return new Group(this, true, true);
00379 }
00380
00384 public void Clear()
00385 {
00386 dataList.Clear();
00387 }
00388
00398 public bool Contains(object value)
00399 {
00400 if (!IsNumericType(value))
00401 throw new BiostatisticsException(
00402 "value parameter in Contains method of Group is not a numeric type.");
00403 return dataList.Contains((NUMBER)value);
00404 }
00405
00416 public void CopyTo(NUMBER[] DecimalArray)
00417 {
00418 try
00419 {
00420 dataList.CopyTo(DecimalArray);
00421 }
00422 catch (Exception e)
00423 {
00424 throw new BiostatisticsException(e.Source + ": " + e.Message, e);
00425 }
00426 }
00427
00440 public void CopyTo(NUMBER[] DecimalArray, int index)
00441 {
00442 try
00443 {
00444 dataList.CopyTo(DecimalArray, index);
00445 }
00446 catch (Exception e)
00447 {
00448 throw new BiostatisticsException(e.Source + ": " + e.Message, e);
00449 }
00450 }
00451
00478 public void CopyTo(Int32 groupIndex, NUMBER[] DecimalArray, int arrayIndex, Int32 count)
00479 {
00480 try
00481 {
00482 dataList.CopyTo(groupIndex, DecimalArray, arrayIndex, count);
00483 }
00484 catch (Exception e)
00485 {
00486 throw new BiostatisticsException(e.Source + ": " + e.Message, e);
00487 }
00488 }
00489
00494 IEnumerator IEnumerable.GetEnumerator()
00495 {
00496 return dataList.GetEnumerator();
00497 }
00498
00507 public int IndexOf(NUMBER value)
00508 {
00509 return dataList.IndexOf(value);
00510 }
00511
00527 public Int32 IndexOf(NUMBER value, Int32 index)
00528 {
00529 return dataList.IndexOf(value, index);
00530 }
00531
00551 public Int32 IndexOf(NUMBER value, Int32 index, Int32 count)
00552 {
00553 return dataList.IndexOf(value, index, count);
00554 }
00555
00567 public void Insert(int index, NUMBER value)
00568 {
00569 try
00570 {
00571 dataList.Insert(index, value);
00572 }
00573 catch (Exception e)
00574 {
00575 throw new BiostatisticsException(e.Source + ": " + e.Message, e);
00576 }
00577 }
00578
00588 public bool Remove(NUMBER value)
00589 {
00590 return dataList.Remove(value);
00591 }
00592
00603 public void RemoveAt(int index)
00604 {
00605 dataList.RemoveAt(index);
00606 }
00607
00612 public NUMBER[] ToArray()
00613 {
00614 return dataList.ToArray();
00615 }
00616
00617 private static bool IsNumericType(object item)
00618 {
00619 Type type = item.GetType();
00620 if (type == typeof(Decimal) ||
00621 type == typeof(Double) ||
00622 type == typeof(Single) ||
00623 type == typeof(Int16) ||
00624 type == typeof(Int32) ||
00625 type == typeof(Int64) ||
00626 type == typeof(UInt16) ||
00627 type == typeof(UInt32) ||
00628 type == typeof(UInt64) ||
00629 type == typeof(Byte) ||
00630 type == typeof(SByte))
00631 return true;
00632 else return false;
00633 }
00634
00642 public NUMBER Average()
00643 { return Mean(); }
00644
00650 public Status GroupStatus()
00651 {
00652 return columnData.ColumnState();
00653 }
00654
00660 public Int16 IdentificationNumber()
00661 { return iIdentificationNumber; }
00662
00667 public void SetIndentificationNumber(Int16 value)
00668 {
00669 iIdentificationNumber = value;
00670 }
00671
00678 public bool IsFixedSize()
00679 {
00680 return isFixedSize;
00681 }
00682
00688 public bool IsNull()
00689 {
00690 if (dataList == null)
00691 return true;
00692 else
00693 return false;
00694 }
00695
00702 public bool IsReadOnly()
00703 {
00704 return isReadOnly;
00705 }
00706
00711 public bool IsValid()
00712 {
00713 return columnData.IsValid();
00714 }
00715
00720 public void SetIsValid(bool value)
00721 { columnData.SetIsValid(value); }
00722
00729 public NUMBER Maximum()
00730 {
00731 if (dataList.Count == 0)
00732 throw new BiostatisticsException(
00733 "Group contains no elements.");
00734 NUMBER decMinimum = dataList[0];
00735 for (Int32 i = 1; i < n(); i++)
00736 if (dataList[i] > decMinimum)
00737 decMinimum = dataList[i];
00738 return decMinimum;
00739 }
00740
00747 public NUMBER Minimum()
00748 {
00749 if (dataList.Count == 0)
00750 throw new BiostatisticsException(
00751 "Group contains no elements.");
00752
00753 NUMBER decMinimum = dataList[0];
00754 for (Int32 i = 1; i < n(); i++)
00755 if (dataList[i] < decMinimum)
00756 decMinimum = dataList[i];
00757 return decMinimum;
00758 }
00759
00767 public NUMBER Mean()
00768 {
00769 if (dataList.Count == 0)
00770 throw new BiostatisticsException(
00771 "Group contains no elements.");
00772 return Sum() / n(); }
00773
00780 public NUMBER Median()
00781 {
00782 if (dataList.Count == 0)
00783 throw new BiostatisticsException(
00784 "Group contains no elements.");
00785 List<NUMBER> lstElements = new List<NUMBER>(dataList);
00786 lstElements.Sort();
00787 if (DecMath.IsOdd(n()))
00788 {
00789 return lstElements[n() / 2];
00790 }
00791 else
00792 return (lstElements[n() / 2] + lstElements[(n() / 2) - 1]) / 2m;
00793 }
00794
00802 public Int32 n()
00803 { return dataList.Count(); }
00804
00809 public Int16 Number()
00810 { return iIdentificationNumber; }
00811
00820 public NUMBER PopulationStandardDeviation()
00821 {
00822 if (dataList.Count == 0)
00823 throw new BiostatisticsException(
00824 "Group contains no elements.");
00825 return DecMath.Sqrt(PopulationVariance()); }
00826
00834 public NUMBER PopulationVariance()
00835 {
00836 if (dataList.Count == 0)
00837 throw new BiostatisticsException(
00838 "Group contains no elements.");
00839 Group grpSumOfSquares = new Group(0);
00840 foreach (NUMBER value in dataList)
00841 {
00842 grpSumOfSquares.Add(value * value);
00843 }
00844 return (grpSumOfSquares.Sum() - n() * Mean() * Mean()) / n();
00845 }
00846
00855 public NUMBER SampleStandardDeviation()
00856 {
00857 if (n() < 2)
00858 throw new BiostatisticsException(
00859 "Group contains fewer than 2 elements.");
00860 return DecMath.Sqrt(SampleVariance()); }
00861
00870 public NUMBER SampleVariance()
00871 {
00872 if (dataList.Count == 0)
00873 throw new BiostatisticsException(
00874 "Group contains fewer than 2 elements.");
00875 return (SumOfSquares() - n() * Mean() * Mean()) /
00876 (n() - 1);
00877 }
00878
00887 public NUMBER StandardErrorOfMean()
00888 {
00889 if (n() < 1)
00890 throw new BiostatisticsException(
00891 "Group contains no elements.");
00892 return SampleStandardDeviation() / DecMath.Sqrt(n()); }
00893
00900 public NUMBER Sum()
00901 {
00902 if (n() == 0)
00903 return 0m;
00904 NUMBER decSum = dataList[0];
00905 NUMBER decCorrection = 0m;
00906 NUMBER decCorrectedNextTerm,
00907 decNewSum;
00908
00909 for (Int32 i = 1; i < n(); i++)
00910 {
00911 decCorrectedNextTerm = dataList[i] - decCorrection;
00912 decNewSum = decSum + decCorrectedNextTerm;
00913 decCorrection = decNewSum - decSum;
00914 decCorrection = decCorrection - decCorrectedNextTerm;
00915 decSum = decNewSum;
00916 }
00917 return decSum;
00918 }
00919
00926 public NUMBER SumOfSquaredDeviates()
00927 {
00928 if (dataList.Count == 0)
00929 throw new BiostatisticsException(
00930 "Group contains no elements.");
00931 NUMBER decTemp = Sum();
00932 return SumOfSquares() - (decTemp * decTemp / n());
00933 }
00934
00935
00940 public NUMBER SumOfSquares()
00941 {
00942 NUMBER decResult = 0m;
00943 foreach (NUMBER value in dataList)
00944 decResult += value * value;
00945 return decResult;
00946 }
00947
00956 public NUMBER this[int index]
00957 {
00958 get { return dataList[index]; }
00959 set
00960 {
00961 if (!isReadOnly)
00962 dataList[index] = value;
00963 }
00964 }
00965 #endregion
00966
00967 }
00968
00973 public class ColumnData
00974 {
00975 private bool isValid;
00976 private Status columnState;
00982 public ColumnData()
00983 {
00984 columnState = Status.Undetermined;
00985 }
00986
00993 public ColumnData(bool bValue)
00994 : this()
00995 {
00996 isValid = bValue;
00997 }
00998
01004 public ColumnData(Status column)
01005 : this()
01006 {
01007 columnState = column;
01008 }
01009
01016 public ColumnData(bool bValue, Status column)
01017 {
01018 isValid = bValue;
01019 columnState = column;
01020 }
01021
01025 public bool IsValid()
01026 { return isValid; }
01027
01032 public void SetIsValid(bool value)
01033 {
01034 isValid = value;
01035 }
01039 public Status ColumnState()
01040 {
01041 return columnState;
01042 }
01043
01048 public void SetColumnState(Status column)
01049 {
01050 columnState = column;
01051 }
01052 }
01053 }