* This routine tests the specified cluster to see if ** * there is a statistically significant difference between * the sub-clusters that would be made if the cluster were to * be split. If not, then a new prototype is formed and * returned to the caller. If there is, then NULL is returned * to the caller. * @param Clusterer data struct containing samples being clustered * @param Config pro
| 1109 | * @return Pointer to new elliptical prototype or NULL. |
| 1110 | */ |
| 1111 | PROTOTYPE *TestEllipticalProto(CLUSTERER *Clusterer, |
| 1112 | CLUSTERCONFIG *Config, |
| 1113 | CLUSTER *Cluster, |
| 1114 | STATISTICS *Statistics) { |
| 1115 | // Fraction of the number of samples used as a range around 1 within |
| 1116 | // which a cluster has the magic size that allows a boost to the |
| 1117 | // FTable by kFTableBoostMargin, thus allowing clusters near the |
| 1118 | // magic size (equal to the number of sample characters) to be more |
| 1119 | // likely to stay together. |
| 1120 | const double kMagicSampleMargin = 0.0625; |
| 1121 | const double kFTableBoostMargin = 2.0; |
| 1122 | |
| 1123 | int N = Clusterer->SampleSize; |
| 1124 | CLUSTER* Left = Cluster->Left; |
| 1125 | CLUSTER* Right = Cluster->Right; |
| 1126 | if (Left == NULL || Right == NULL) |
| 1127 | return NULL; |
| 1128 | int TotalDims = Left->SampleCount + Right->SampleCount; |
| 1129 | if (TotalDims < N + 1 || TotalDims < 2) |
| 1130 | return NULL; |
| 1131 | const int kMatrixSize = N * N * sizeof(FLOAT32); |
| 1132 | FLOAT32* Covariance = reinterpret_cast<FLOAT32 *>(Emalloc(kMatrixSize)); |
| 1133 | FLOAT32* Inverse = reinterpret_cast<FLOAT32 *>(Emalloc(kMatrixSize)); |
| 1134 | FLOAT32* Delta = reinterpret_cast<FLOAT32*>(Emalloc(N * sizeof(FLOAT32))); |
| 1135 | // Compute a new covariance matrix that only uses essential features. |
| 1136 | for (int i = 0; i < N; ++i) { |
| 1137 | int row_offset = i * N; |
| 1138 | if (!Clusterer->ParamDesc[i].NonEssential) { |
| 1139 | for (int j = 0; j < N; ++j) { |
| 1140 | if (!Clusterer->ParamDesc[j].NonEssential) |
| 1141 | Covariance[j + row_offset] = Statistics->CoVariance[j + row_offset]; |
| 1142 | else |
| 1143 | Covariance[j + row_offset] = 0.0f; |
| 1144 | } |
| 1145 | } else { |
| 1146 | for (int j = 0; j < N; ++j) { |
| 1147 | if (i == j) |
| 1148 | Covariance[j + row_offset] = 1.0f; |
| 1149 | else |
| 1150 | Covariance[j + row_offset] = 0.0f; |
| 1151 | } |
| 1152 | } |
| 1153 | } |
| 1154 | double err = InvertMatrix(Covariance, N, Inverse); |
| 1155 | if (err > 1) { |
| 1156 | tprintf("Clustering error: Matrix inverse failed with error %g\n", err); |
| 1157 | } |
| 1158 | int EssentialN = 0; |
| 1159 | for (int dim = 0; dim < N; ++dim) { |
| 1160 | if (!Clusterer->ParamDesc[dim].NonEssential) { |
| 1161 | Delta[dim] = Left->Mean[dim] - Right->Mean[dim]; |
| 1162 | ++EssentialN; |
| 1163 | } else { |
| 1164 | Delta[dim] = 0.0f; |
| 1165 | } |
| 1166 | } |
| 1167 | // Compute Hotelling's T-squared. |
| 1168 | double Tsq = 0.0; |
no test coverage detected