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 }