00001 using System;
00002
00003 namespace StephenAshley.Biostatistics
00004 {
00005 using NUMBER = Decimal;
00012 public class FisherExactArray : ChiSquaredArray
00013 {
00017 public FisherExactArray() : base(2, 2) { }
00018
00023 public override NUMBER p()
00024 {
00025 return FisherProbability((UInt16)outcomesArray[0, 0].iObserved,
00026 (UInt16)outcomesArray[0, 1].iObserved, (UInt16)outcomesArray[1, 0].iObserved,
00027 (UInt16)outcomesArray[1, 1].iObserved);
00028 }
00029
00030 private NUMBER FisherProbability(UInt16 uA1, UInt16 uB1, UInt16 uA2, UInt16 uB2)
00031 {
00032 Int32[,] f = new Int32[2, 2];
00033 Int32[,] a = new Int32[2, 2];
00034 Int32[] iRowSums = new Int32[2];
00035 Int32[] iColumnSums = new Int32[2];
00036
00037 int ntotal,
00038 i, j,
00039 ismall, jsmall;
00040 NUMBER ptable, poriginal_table, ptotal;
00041 NUMBER numerator;
00042 UInt16[,] data = new UInt16[2, 2];
00043
00044 poriginal_table = 0.0m;
00045 data[0, 0] = uA1;
00046 data[0, 1] = uB1;
00047 data[1, 0] = uA2;
00048 data[1, 1] = uB2;
00049
00050
00051
00052 ntotal = 0;
00053 for (i = 0; i < 2; i++)
00054 for (j = 0; j < 2; j++)
00055 {
00056 f[i, j] = data[i, j];
00057 ntotal = ntotal + f[i, j];
00058 }
00059
00060
00061 if (f[0, 0] * f[1, 1] <= f[0, 1] * f[1, 0])
00062 {
00063 if (f[0, 0] < f[1, 1])
00064 {
00065 ismall = 1;
00066 jsmall = 1;
00067 }
00068 else
00069 {
00070 ismall = 2;
00071 jsmall = 2;
00072 }
00073 }
00074 else
00075 {
00076 if (f[0, 1] < f[1, 0])
00077 {
00078 ismall = 1;
00079 jsmall = 2;
00080 }
00081 else
00082 {
00083 ismall = 2;
00084 jsmall = 1;
00085 }
00086 }
00087
00088
00089 if ((ismall == 1) && (jsmall == 1))
00090 {
00091 a[0, 0] = f[0, 0];
00092 a[0, 1] = f[0, 1];
00093 a[1, 0] = f[1, 0];
00094 a[1, 1] = f[1, 1];
00095 }
00096 else if ((ismall == 1) && (jsmall == 2))
00097 {
00098 a[0, 0] = f[0, 1];
00099 a[0, 1] = f[0, 0];
00100 a[1, 0] = f[1, 1];
00101 a[1, 1] = f[1, 0];
00102 }
00103 else if ((ismall == 2) && (jsmall == 1))
00104 {
00105 a[0, 0] = f[1, 0];
00106 a[0, 1] = f[1, 1];
00107 a[1, 0] = f[0, 0];
00108 a[1, 1] = f[0, 1];
00109 }
00110 else if ((ismall == 2) && (jsmall == 2))
00111 {
00112 a[0, 0] = f[1, 1];
00113 a[0, 1] = f[1, 0];
00114 a[1, 0] = f[0, 1];
00115 a[1, 1] = f[0, 0];
00116 }
00117
00118 for (i = 0; i < 2; i++)
00119 {
00120 iRowSums[i] = a[i, 0] + a[i, 1];
00121 iColumnSums[i] = a[0, i] + a[1, i];
00122 }
00123
00124
00125 numerator = DecMath.Exp(LogFactorial(iRowSums[0]) + LogFactorial(iRowSums[1]) +
00126 LogFactorial(iColumnSums[0]) + LogFactorial(iColumnSums[1]) -
00127 LogFactorial(ntotal));
00128
00129 ptotal = 0.0m;
00130 ptable = 0.0m;
00131 for (i = 0; i <= a[0, 0]; i++)
00132 {
00133 ptable = numerator / DecMath.Exp(LogFactorial(a[0, 0] - i) +
00134 LogFactorial(a[0, 1] + i) + LogFactorial(a[1, 0] + i)
00135 + LogFactorial(a[1, 1] - i));
00136
00137 if (i == 0)
00138 poriginal_table = ptable;
00139
00140 ptotal = ptotal + ptable;
00141 }
00142
00143
00144 if (a[0, 1] > a[1, 0])
00145 i = a[1, 0];
00146 else
00147 i = a[0, 1];
00148
00149 while ((i != 0) && (ptable <= poriginal_table))
00150 {
00151 ptable = numerator / DecMath.Exp(LogFactorial(a[0, 0] + i) +
00152 LogFactorial(a[0, 1] - i) + LogFactorial(a[1, 0] - i) +
00153 LogFactorial(a[1, 1] + i));
00154
00155 if (ptable <= poriginal_table)
00156 ptotal = ptotal + ptable;
00157
00158 i = i - 1;
00159 }
00160
00161 return ptotal;
00162 }
00163
00164
00165
00166 private NUMBER LogFactorial(Int32 f)
00167 {
00168 NUMBER rtempd;
00169
00170 rtempd = 0.0m;
00171 for (int i = 1; i <= f; i++)
00172 rtempd += DecMath.Log((NUMBER)i);
00173
00174 return rtempd;
00175 }
00176 }
00177 }