autoTableOfReal FormantTier_downto_TableOfReal (FormantTier me, int includeFormants, int includeBandwidths) { try { int maximumNumberOfFormants = FormantTier_getMaxNumFormants (me); autoTableOfReal thee = TableOfReal_create (my points -> size, 1 + ( includeFormants ? maximumNumberOfFormants : 0 ) + ( includeBandwidths ? maximumNumberOfFormants : 0 )); TableOfReal_setColumnLabel (thee.peek(), 1, U"Time"); for (long icol = 1, iformant = 1; iformant <= maximumNumberOfFormants; iformant ++) { char32 label [4]; if (includeFormants) { Melder_sprint (label,4, U"F", iformant); TableOfReal_setColumnLabel (thee.peek(), ++ icol, label); } if (includeBandwidths) { Melder_sprint (label,4, U"B", iformant); TableOfReal_setColumnLabel (thee.peek(), ++ icol, label); } } for (long ipoint = 1; ipoint <= my points -> size; ipoint ++) { FormantPoint point = (FormantPoint) my points -> item [ipoint]; thy data [ipoint] [1] = point -> time; for (long icol = 1, iformant = 1; iformant <= maximumNumberOfFormants; iformant ++) { if (includeFormants) thy data [ipoint] [++ icol] = point -> formant [iformant-1]; if (includeBandwidths) thy data [ipoint] [++ icol] = point -> bandwidth [iformant-1]; } } return thee; } catch (MelderError) { Melder_throw (me, U": not converted to TableOfReal."); } }
autoConfusion Confusion_groupResponses (Confusion me, const char32 *labels, const char32 *newLabel, long newpos) { try { long ncondense = Melder_countTokens (labels); autoNUMvector<long> icol (1, my numberOfColumns); for (long i = 1; i <= my numberOfColumns; i++) { icol[i] = i; } for (char32 *token = Melder_firstToken (labels); token != 0; token = Melder_nextToken ()) { for (long i = 1; i <= my numberOfColumns; i++) { if (Melder_equ (token, my columnLabels[i])) { icol[i] = 0; break; } } } long nfound = 0; for (long i = 1; i <= my numberOfColumns; i++) { if (icol[i] == 0) { nfound ++; } } if (nfound == 0) { Melder_throw (U"Invalid response labels."); } if (nfound != ncondense) { Melder_warning (U"One or more of the given response labels are suspect."); } long newnresp = my numberOfColumns - nfound + 1; if (newpos < 1) { newpos = 1; } if (newpos > newnresp) { newpos = newnresp; } autoConfusion thee = Confusion_create (my numberOfRows, newnresp); NUMstrings_copyElements (my rowLabels, thy rowLabels, 1, my numberOfRows); TableOfReal_setColumnLabel (thee.get(), newpos, newLabel); long inewcol = 1; for (long i = 1; i <= my numberOfColumns; i++) { long colpos = newpos; if (icol[i] > 0) { if (inewcol == newpos) { inewcol++; } colpos = inewcol; inewcol++; TableOfReal_setColumnLabel (thee.get(), colpos, my columnLabels[i]); } for (long j = 1; j <= my numberOfRows; j++) { thy data[j][colpos] += my data[j][i]; } } return thee; } catch (MelderError) { Melder_throw (me, U": responses not grouped."); } }
TableOfReal RealTier_downto_TableOfReal (I, const wchar_t *timeLabel, const wchar_t *valueLabel) { iam (RealTier); TableOfReal thee = TableOfReal_create (my points -> size, 2); cherror TableOfReal_setColumnLabel (thee, 1, timeLabel); cherror TableOfReal_setColumnLabel (thee, 2, valueLabel); cherror for (long i = 1; i <= my points -> size; i ++) { RealPoint point = (structRealPoint *)my points -> item [i]; thy data [i] [1] = point -> time; thy data [i] [2] = point -> value; } end: iferror forget (thee); return thee; }
autoTableOfReal RealTier_downto_TableOfReal (RealTier me, const char32 *timeLabel, const char32 *valueLabel) { try { autoTableOfReal thee = TableOfReal_create (my points.size, 2); TableOfReal_setColumnLabel (thee.get(), 1, timeLabel); TableOfReal_setColumnLabel (thee.get(), 2, valueLabel); for (long i = 1; i <= my points.size; i ++) { RealPoint point = my points.at [i]; thy data [i] [1] = point -> number; thy data [i] [2] = point -> value; } return thee; } catch (MelderError) { Melder_throw (me, U": not converted to TableOfReal."); } }
CrossCorrelationTable EEG_to_CrossCorrelationTable (EEG me, double startTime, double endTime, double lagTime, const wchar_t *channelRanges) { try { // autowindow if (startTime == endTime) { startTime = my xmin; endTime = my xmax; } // don't allow times outside domain if (startTime < my xmin) { startTime = my xmin; } if (endTime > my xmax) { endTime = my xmax; } autoEEG thee = my f_extractPart (startTime, endTime, true); long numberOfChannels; autoNUMvector <long> channels (NUMstring_getElementsOfRanges (channelRanges, thy d_numberOfChannels, & numberOfChannels, NULL, L"channel", true), 1); autoSound soundPart = Sound_copyChannelRanges (thy d_sound, channelRanges); autoCrossCorrelationTable him = Sound_to_CrossCorrelationTable (soundPart.peek(), startTime, endTime, lagTime); // assign channel names for (long i = 1; i <= numberOfChannels; i++) { long ichannel = channels[i]; wchar_t *label = my d_channelNames[ichannel]; TableOfReal_setRowLabel (him.peek(), i, label); TableOfReal_setColumnLabel (him.peek(), i, label); } return him.transfer(); } catch (MelderError) { Melder_throw (me, ": no CrossCorrelationTable calculated."); } }
autoTableOfReal FFNet_extractWeights (FFNet me, long layer) { try { FFNet_checkLayerNumber (me, layer); long numberOfUnitsFrom = my nUnitsInLayer[layer - 1] + 1; long numberOfUnitsTo = my nUnitsInLayer[layer]; autoTableOfReal thee = TableOfReal_create (numberOfUnitsFrom, numberOfUnitsTo); char32 label[40]; for (long i = 1; i <= numberOfUnitsFrom - 1; i++) { Melder_sprint (label,40, U"L", layer - 1, U"-", i); TableOfReal_setRowLabel (thee.peek(), i, label); } TableOfReal_setRowLabel (thee.peek(), numberOfUnitsFrom, U"Bias"); for (long i = 1; i <= numberOfUnitsTo; i++) { Melder_sprint (label,40, U"L", layer, U"-", i); TableOfReal_setColumnLabel (thee.peek(), i, label); } long node = 1; for (long i = 0; i < layer; i++) { node += my nUnitsInLayer[i] + 1; } for (long i = 1; i <= numberOfUnitsTo; i++, node++) { long k = 1; for (long j = my wFirst[node]; j <= my wLast[node]; j++) { thy data[k++][i] = my w[j]; } } return thee; } catch (MelderError) { Melder_throw (me, U": no TableOfReal created."); } }
Correlation ClassificationTable_to_Correlation_columns (ClassificationTable me) { try { autoCorrelation thee = Correlation_create (my numberOfColumns); for (long icol = 1; icol <= thy numberOfColumns; icol++) { char32 *label = my columnLabels[icol]; TableOfReal_setRowLabel (thee.peek(), icol, label); TableOfReal_setColumnLabel (thee.peek(), icol, label); } for (long irow = 1; irow <= thy numberOfColumns; irow++) { thy data[irow][irow] = 1.0; for (long icol = irow + 1; icol <= thy numberOfColumns; icol++) { double n11 = 0.0, n22 = 0.0, n12 = 0.0; for (long i = 1; i <= my numberOfRows; i++) { n12 += my data[i][irow] * my data[i][icol]; n11 += my data[i][irow] * my data[i][irow]; n22 += my data[i][icol] * my data[i][icol]; } // probabilities might be very low! if (n12 > 0.0 && n22 > 0.0) { thy data[irow][icol] = thy data[icol][irow] = n12 / sqrt (n11 * n22); } } } thy numberOfObservations = my numberOfRows; return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": no correlation created."); } }
autoConfusion Categories_to_Confusion (Categories me, Categories thee) { try { if (my size != thy size) { Melder_throw (U"Categories_to_Confusion: dimensions do not agree."); } autoCategories ul1 = Categories_selectUniqueItems (me); autoCategories ul2 = Categories_selectUniqueItems (thee); autoConfusion him = Confusion_create (ul1->size, ul2->size); for (long i = 1; i <= ul1->size; i ++) { SimpleString s = ul1->at [i]; TableOfReal_setRowLabel (him.get(), i, s -> string); } for (long i = 1; i <= ul2->size; i ++) { SimpleString s = ul2->at [i]; TableOfReal_setColumnLabel (him.get(), i, s -> string); } for (long i = 1; i <= my size; i ++) { SimpleString myi = my at [i], thyi = thy at [i]; Confusion_increase (him.get(), SimpleString_c (myi), SimpleString_c (thyi)); } return him; } catch (MelderError) { Melder_throw (me, U": no Confusion created."); } }
/* raw r[j]: eigenvec[i][j] unstandardized u[j]: sqrt(N-g) * r[j] standardized s[j]: u[j] sqrt (w[i][i] / (N-g)) */ autoTableOfReal Discriminant_extractCoefficients (Discriminant me, int choice) { try { int raw = choice == 0, standardized = choice == 2; long nx = my eigen -> dimension, ny = my eigen -> numberOfEigenvalues; SSCP total = my total.get(); autoTableOfReal thee = TableOfReal_create (ny, nx + 1); NUMstrings_copyElements (my total -> columnLabels, thy columnLabels, 1, nx); autoSSCP within; if (standardized) { within = Discriminant_extractPooledWithinGroupsSSCP (me); } TableOfReal_setColumnLabel (thee.get(), nx + 1, U"constant"); TableOfReal_setSequentialRowLabels (thee.get(), 1, ny, U"function_", 1, 1); double scale = sqrt (total -> numberOfObservations - my numberOfGroups); double *centroid = my total -> centroid; for (long i = 1; i <= ny; i++) { double u0 = 0.0, ui; for (long j = 1; j <= nx; j++) { if (standardized) { scale = sqrt (within -> data[j][j]); } thy data[i][j] = ui = scale * my eigen -> eigenvectors[i][j];; u0 += ui * centroid[j]; } thy data[i][nx + 1] = raw ? 0.0 : -u0; } return thee; } catch (MelderError) { Melder_throw (me, U": coefficients not extracted."); } }
Any TablesOfReal_appendMany (Collection me) { try { if (my size == 0) Melder_throw ("Cannot add zero tables."); TableOfReal thee = static_cast <TableOfReal> (my item [1]); long totalNumberOfRows = thy numberOfRows; long numberOfColumns = thy numberOfColumns; for (long itab = 2; itab <= my size; itab ++) { thee = static_cast <TableOfReal> (my item [itab]); totalNumberOfRows += thy numberOfRows; if (thy numberOfColumns != numberOfColumns) Melder_throw ("Numbers of columns do not match."); } autoTableOfReal him = static_cast <TableOfReal> (_Thing_new (thy classInfo)); TableOfReal_init (him.peek(), totalNumberOfRows, numberOfColumns); /* Unsafe: new attributes not initialized. */ for (long icol = 1; icol <= numberOfColumns; icol ++) { TableOfReal_setColumnLabel (him.peek(), icol, thy columnLabels [icol]); } totalNumberOfRows = 0; for (long itab = 1; itab <= my size; itab ++) { thee = static_cast <TableOfReal> (my item [itab]); for (long irow = 1; irow <= thy numberOfRows; irow ++) { totalNumberOfRows ++; TableOfReal_setRowLabel (him.peek(), totalNumberOfRows, thy rowLabels [irow]); for (long icol = 1; icol <= numberOfColumns; icol ++) his data [totalNumberOfRows] [icol] = thy data [irow] [icol]; } } Melder_assert (totalNumberOfRows == his numberOfRows); return him.transfer(); } catch (MelderError) { Melder_throw ("TableOfReal objects not appended."); } }
Any TablesOfReal_append (TableOfReal me, TableOfReal thee) { try { if (thy numberOfColumns != my numberOfColumns) Melder_throw (L"Numbers of columns are ", my numberOfColumns, " and ", thy numberOfColumns, " but should be equal."); autoTableOfReal him = static_cast <TableOfReal> (_Thing_new (my classInfo)); TableOfReal_init (him.peek(), my numberOfRows + thy numberOfRows, my numberOfColumns); /* Unsafe: new attributes not initialized. */ for (long icol = 1; icol <= my numberOfColumns; icol ++) { TableOfReal_setColumnLabel (him.peek(), icol, my columnLabels [icol]); } for (long irow = 1; irow <= my numberOfRows; irow ++) { TableOfReal_setRowLabel (him.peek(), irow, my rowLabels [irow]); for (long icol = 1; icol <= my numberOfColumns; icol ++) his data [irow] [icol] = my data [irow] [icol]; } for (long irow = 1; irow <= thy numberOfRows; irow ++) { long hisRow = irow + my numberOfRows; TableOfReal_setRowLabel (him.peek(), hisRow, thy rowLabels [irow]); for (long icol = 1; icol <= my numberOfColumns; icol ++) his data [hisRow] [icol] = thy data [irow] [icol]; } return him.transfer(); } catch (MelderError) { Melder_throw ("TableOfReal objects not appended."); } }
TableOfReal Table_to_TableOfReal (Table me, long labelColumn) { try { if (labelColumn < 1 || labelColumn > my numberOfColumns) labelColumn = 0; autoTableOfReal thee = TableOfReal_create (my rows -> size, labelColumn ? my numberOfColumns - 1 : my numberOfColumns); for (long icol = 1; icol <= my numberOfColumns; icol ++) { Table_numericize_Assert (me, icol); } if (labelColumn) { for (long icol = 1; icol < labelColumn; icol ++) { TableOfReal_setColumnLabel (thee.peek(), icol, my columnHeaders [icol]. label); } for (long icol = labelColumn + 1; icol <= my numberOfColumns; icol ++) { TableOfReal_setColumnLabel (thee.peek(), icol - 1, my columnHeaders [icol]. label); } for (long irow = 1; irow <= my rows -> size; irow ++) { TableRow row = static_cast <TableRow> (my rows -> item [irow]); wchar_t *string = row -> cells [labelColumn]. string; TableOfReal_setRowLabel (thee.peek(), irow, string ? string : L""); for (long icol = 1; icol < labelColumn; icol ++) { thy data [irow] [icol] = row -> cells [icol]. number; // Optimization. //thy data [irow] [icol] = Table_getNumericValue_Assert (me, irow, icol); } for (long icol = labelColumn + 1; icol <= my numberOfColumns; icol ++) { thy data [irow] [icol - 1] = row -> cells [icol]. number; // Optimization. //thy data [irow] [icol - 1] = Table_getNumericValue_Assert (me, irow, icol); } } } else { for (long icol = 1; icol <= my numberOfColumns; icol ++) { TableOfReal_setColumnLabel (thee.peek(), icol, my columnHeaders [icol]. label); } for (long irow = 1; irow <= my rows -> size; irow ++) { TableRow row = static_cast <TableRow> (my rows -> item [irow]); for (long icol = 1; icol <= my numberOfColumns; icol ++) { thy data [irow] [icol] = row -> cells [icol]. number; // Optimization. //thy data [irow] [icol] = Table_getNumericValue_Assert (me, irow, icol); } } } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": not converted to TableOfReal."); } }
TableOfReal AffineTransform_extractMatrix (I) { iam (AffineTransform); try { autoTableOfReal thee = TableOfReal_create (my n, my n); NUMmatrix_copyElements (my r, thy data, 1, my n, 1, my n); for (long i = 1; i <= my n; i++) { wchar_t label[20]; (void) swprintf (label, 20, L"%ld", i); TableOfReal_setRowLabel (thee.peek(), i, label); TableOfReal_setColumnLabel (thee.peek(), i, label); } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": transformation matrix not extracted."); } }
autoConfusion Confusion_createFromStringses (Strings me, Strings thee) { try { if (my numberOfStrings < 1 || thy numberOfStrings < 1) { Melder_throw (U"Empty Strings."); } autoConfusion him = Confusion_create (my numberOfStrings, thy numberOfStrings); for (long irow = 1; irow <= my numberOfStrings; irow++) { const char32 *label = my strings[irow]; TableOfReal_setRowLabel (him.get(), irow, label); } for (long icol = 1; icol <= thy numberOfStrings; icol++) { const char32 *label = thy strings[icol]; TableOfReal_setColumnLabel (him.get(), icol, label); } return him; } catch (MelderError) { Melder_throw (me, U": could not create Confusion with ", thee); } }
EditDistanceTable EditDistanceTable_create (Strings target, Strings source) { try { autoEditDistanceTable me = Thing_new (EditDistanceTable); long numberOfSourceSymbols = source -> numberOfStrings, numberOfTargetSymbols = target -> numberOfStrings; TableOfReal_init (me.peek(), numberOfTargetSymbols + 1, numberOfSourceSymbols + 1); TableOfReal_setColumnLabel (me.peek(), 1, U""); for (long j = 1; j <= numberOfSourceSymbols; j++) { my columnLabels[j + 1] = Melder_dup (source -> strings[j]); } TableOfReal_setRowLabel (me.peek(), 1, U""); for (long i = 1; i <= numberOfTargetSymbols; i++) { my rowLabels[i + 1] = Melder_dup (target -> strings[i]); } my warpingPath = WarpingPath_create (numberOfTargetSymbols + numberOfSourceSymbols + 1); my editCostsTable = EditCostsTable_createDefault (); EditDistanceTable_findPath (me.peek(), 0); return me.transfer(); } catch (MelderError) { Melder_throw (U"EditDistanceTable not created."); } }
autoConfusion Confusion_createSimple (const char32 *labels) { try { long numberOfLabels = Melder_countTokens (labels); if (numberOfLabels < 1) { Melder_throw (U"Not enough labels."); } autoConfusion me = Confusion_create (numberOfLabels, numberOfLabels); long ilabel = 1; for (char32 *token = Melder_firstToken (labels); token != 0; token = Melder_nextToken ()) { for (long i = 1; i <= ilabel - 1; i++) { if (Melder_cmp (token, my rowLabels[i]) == 0) { Melder_throw (U"Label ", i, U"and ", ilabel, U"may not be equal."); } } TableOfReal_setRowLabel (me.get(), ilabel, token); TableOfReal_setColumnLabel (me.get(), ilabel, token); ilabel++; } return me; } catch (MelderError) { Melder_throw (U"Simple Confusion not created."); } }
TableOfReal FFNet_extractWeights (FFNet me, long layer) { TableOfReal thee = NULL; long i, node = 1, numberOfUnitsFrom, numberOfUnitsTo; wchar_t label[20]; if (! FFNet_checkLayerNumber (me, layer)) return NULL; numberOfUnitsFrom = my nUnitsInLayer[layer-1] + 1; numberOfUnitsTo = my nUnitsInLayer[layer]; thee = TableOfReal_create (numberOfUnitsFrom, numberOfUnitsTo); if (thee == NULL) return NULL; for (i = 1; i <= numberOfUnitsFrom - 1; i++) { swprintf (label,20,L"L%ld-%ld", layer-1, i); TableOfReal_setRowLabel (thee, i, label); } TableOfReal_setRowLabel (thee, numberOfUnitsFrom, L"Bias"); for (i = 1; i <= numberOfUnitsTo; i++) { swprintf (label,20,L"L%ld-%ld", layer, i); TableOfReal_setColumnLabel (thee, i, label); } for (i = 0; i < layer; i++) node += my nUnitsInLayer[i] + 1; for (i = 1; i <= numberOfUnitsTo; i++, node++) { long j, k = 1; for (j = my wFirst[node]; j <= my wLast[node]; j++) { thy data[k++][i] = my w[j]; } } return thee; }
ClassificationTable Discriminant_and_TableOfReal_to_ClassificationTable (Discriminant me, TableOfReal thee, int poolCovarianceMatrices, int useAprioriProbabilities) { try { long g = Discriminant_getNumberOfGroups (me); long p = Eigen_getDimensionOfComponents (me); long m = thy numberOfRows; if (p != thy numberOfColumns) Melder_throw (U"The number of columns does not agree with the dimension of the discriminant."); autoNUMvector<double> log_p (1, g); autoNUMvector<double> log_apriori (1, g); autoNUMvector<double> ln_determinant (1, g); autoNUMvector<double> buf (1, p); autoNUMvector<SSCP> sscpvec (1, g); autoSSCP pool = SSCPs_to_SSCP_pool (my groups); autoClassificationTable him = ClassificationTable_create (m, g); NUMstrings_copyElements (thy rowLabels, his rowLabels, 1, m); // Scale the sscp to become a covariance matrix. for (long i = 1; i <= p; i++) { for (long k = i; k <= p; k++) { pool -> data[k][i] = (pool -> data[i][k] /= (pool -> numberOfObservations - g)); } } double lnd; autoSSCPs agroups = 0; SSCPs groups; if (poolCovarianceMatrices) { /* Covariance matrix S can be decomposed as S = L.L'. Calculate L^-1. L^-1 will be used later in the Mahalanobis distance calculation: v'.S^-1.v == v'.L^-1'.L^-1.v == (L^-1.v)'.(L^-1.v). */ NUMlowerCholeskyInverse (pool -> data, p, &lnd); for (long j = 1; j <= g; j++) { ln_determinant[j] = lnd; sscpvec[j] = pool.peek(); } groups = (SSCPs) my groups; } else { // Calculate the inverses of all group covariance matrices. // In case of a singular matrix, substitute inverse of pooled. agroups.reset (Data_copy ( (SSCPs) my groups)); groups = agroups.peek(); long npool = 0; for (long j = 1; j <= g; j++) { SSCP t = (SSCP) groups -> item[j]; long no = (long) floor (SSCP_getNumberOfObservations (t)); for (long i = 1; i <= p; i++) { for (long k = i; k <= p; k++) { t -> data[k][i] = (t -> data[i][k] /= (no - 1)); } } sscpvec[j] = (SSCP) groups -> item[j]; try { NUMlowerCholeskyInverse (t -> data, p, &ln_determinant[j]); } catch (MelderError) { // Try the alternative: the pooled covariance matrix. // Clear the error. Melder_clearError (); if (npool == 0) { NUMlowerCholeskyInverse (pool -> data, p, &lnd); } npool++; sscpvec[j] = pool.peek(); ln_determinant[j] = lnd; } } if (npool > 0) { Melder_warning (npool, U" groups use pooled covariance matrix."); } } // Labels for columns in ClassificationTable for (long j = 1; j <= g; j++) { const char32 *name = Thing_getName ( (Thing) my groups -> item[j]); if (! name) { name = U"?"; } TableOfReal_setColumnLabel (him.peek(), j, name); } // Normalize the sum of the apriori probabilities to 1. // Next take ln (p) because otherwise probabilities might be too small to represent. NUMvector_normalize1 (my aprioriProbabilities, g); double logg = log (g); for (long j = 1; j <= g; j++) { log_apriori[j] = useAprioriProbabilities ? log (my aprioriProbabilities[j]) : - logg; } // Generalized squared distance function: // D^2(x) = (x - mu)' S^-1 (x - mu) + ln (determinant(S)) - 2 ln (apriori) for (long i = 1; i <= m; i++) { double norm = 0, pt_max = -1e38; for (long j = 1; j <= g; j++) { SSCP t = (SSCP) groups -> item[j]; double md = mahalanobisDistanceSq (sscpvec[j] -> data, p, thy data[i], t -> centroid, buf.peek()); double pt = log_apriori[j] - 0.5 * (ln_determinant[j] + md); if (pt > pt_max) { pt_max = pt; } log_p[j] = pt; } for (long j = 1; j <= g; j++) { norm += (log_p[j] = exp (log_p[j] - pt_max)); } for (long j = 1; j <= g; j++) { his data[i][j] = log_p[j] / norm; } } return him.transfer(); } catch (MelderError) { Melder_throw (U"ClassificationTable from Discriminant & TableOfReal not created."); } }
autoClassificationTable Discriminant_and_TableOfReal_to_ClassificationTable_dw (Discriminant me, TableOfReal thee, int poolCovarianceMatrices, int useAprioriProbabilities, double alpha, double minProb, autoTableOfReal *displacements) { try { long g = Discriminant_getNumberOfGroups (me); long p = Eigen_getDimensionOfComponents (my eigen.get()); long m = thy numberOfRows; if (p != thy numberOfColumns) Melder_throw (U"The number of columns does not agree with the dimension of the discriminant."); autoNUMvector<double> log_p (1, g); autoNUMvector<double> log_apriori (1, g); autoNUMvector<double> ln_determinant (1, g); autoNUMvector<double> buf (1, p); autoNUMvector<double> displacement (1, p); autoNUMvector<double> x (1, p); autoNUMvector<SSCP> sscpvec (1, g); autoSSCP pool = SSCPList_to_SSCP_pool (my groups.get()); autoClassificationTable him = ClassificationTable_create (m, g); NUMstrings_copyElements (thy rowLabels, his rowLabels, 1, m); autoTableOfReal adisplacements = Data_copy (thee); // Scale the sscp to become a covariance matrix. for (long i = 1; i <= p; i ++) { for (long k = i; k <= p; k ++) { pool -> data [k] [i] = pool -> data [i] [k] /= pool -> numberOfObservations - g; } } double lnd; autoSSCPList agroups; SSCPList groups; if (poolCovarianceMatrices) { // Covariance matrix S can be decomposed as S = L.L'. Calculate L^-1. // L^-1 will be used later in the Mahalanobis distance calculation: // v'.S^-1.v == v'.L^-1'.L^-1.v == (L^-1.v)'.(L^-1.v). NUMlowerCholeskyInverse (pool -> data, p, & lnd); for (long j = 1; j <= g; j ++) { ln_determinant [j] = lnd; sscpvec [j] = pool.get(); } groups = my groups.get(); } else { //Calculate the inverses of all group covariance matrices. // In case of a singular matrix, substitute inverse of pooled. agroups = Data_copy (my groups.get()); groups = agroups.get(); long npool = 0; for (long j = 1; j <= g; j ++) { SSCP t = groups->at [j]; long no = (long) floor (SSCP_getNumberOfObservations (t)); for (long i = 1; i <= p; i ++) { for (long k = i; k <= p; k ++) { t -> data [k] [i] = t -> data [i] [k] /= no - 1; } } sscpvec [j] = groups->at [j]; try { NUMlowerCholeskyInverse (t -> data, p, & ln_determinant [j]); } catch (MelderError) { // Try the alternative: the pooled covariance matrix. // Clear the error. Melder_clearError (); if (npool == 0) { NUMlowerCholeskyInverse (pool -> data, p, & lnd); } npool ++; sscpvec [j] = pool.get(); ln_determinant [j] = lnd; } } if (npool > 0) { Melder_warning (npool, U" groups use pooled covariance matrix."); } } // Labels for columns in ClassificationTable for (long j = 1; j <= g; j ++) { const char32 *name = Thing_getName (my groups->at [j]); if (! name) { name = U"?"; } TableOfReal_setColumnLabel (him.get(), j, name); } // Normalize the sum of the apriori probabilities to 1. // Next take ln (p) because otherwise probabilities might be too small to represent. double logg = log (g); NUMvector_normalize1 (my aprioriProbabilities, g); for (long j = 1; j <= g; j ++) { log_apriori[j] = ( useAprioriProbabilities ? log (my aprioriProbabilities[j]) : - logg ); } // Generalized squared distance function: // D^2(x) = (x - mu)' S^-1 (x - mu) + ln (determinant(S)) - 2 ln (apriori) for (long i = 1; i <= m; i ++) { SSCP winner; double norm = 0, pt_max = -1e308; long iwinner = 1; for (long k = 1; k <= p; k ++) { x [k] = thy data [i] [k] + displacement [k]; } for (long j = 1; j <= g; j ++) { SSCP t = groups->at [j]; double md = mahalanobisDistanceSq (sscpvec [j] -> data, p, x.peek(), t -> centroid, buf.peek()); double pt = log_apriori [j] - 0.5 * (ln_determinant [j] + md); if (pt > pt_max) { pt_max = pt; iwinner = j; } log_p [j] = pt; } for (long j = 1; j <= g; j ++) { norm += log_p [j] = exp (log_p [j] - pt_max); } for (long j = 1; j <= g; j ++) { his data [i] [j] = log_p [j] / norm; } // Save old displacement, calculate new displacement winner = groups->at [iwinner]; for (long k = 1; k <= p; k ++) { adisplacements -> data [i] [k] = displacement [k]; if (his data [i] [iwinner] > minProb) { double delta_k = winner -> centroid [k] - x [k]; displacement [k] += alpha * delta_k; } } } *displacements = adisplacements.move(); return him; } catch (MelderError) { Melder_throw (U"ClassificationTable for Weenink procedure not created."); } }
TableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file) { try { autostring string = MelderFile_readText (file); long nrow, ncol, nelements; /* * Count columns. */ ncol = 0; wchar_t *p = & string [0]; for (;;) { wchar_t kar = *p++; if (kar == '\n' || kar == '\0') break; if (kar == ' ' || kar == '\t') continue; ncol ++; do { kar = *p++; } while (kar != ' ' && kar != '\t' && kar != '\n' && kar != '\0'); if (kar == '\n' || kar == '\0') break; } ncol --; if (ncol < 1) Melder_throw ("No columns."); /* * Count elements. */ p = & string [0]; nelements = 0; for (;;) { wchar_t kar = *p++; if (kar == '\0') break; if (kar == ' ' || kar == '\t' || kar == '\n') continue; nelements ++; do { kar = *p++; } while (kar != ' ' && kar != '\t' && kar != '\n' && kar != '\0'); if (kar == '\0') break; } /* * Check if all columns are complete. */ if (nelements == 0 || nelements % (ncol + 1) != 0) Melder_throw ("The number of elements (", nelements, ") is not a multiple of the number of columns plus 1 (", ncol + 1, ")."); /* * Create empty table. */ nrow = nelements / (ncol + 1) - 1; autoTableOfReal me = TableOfReal_create (nrow, ncol); /* * Read elements. */ p = & string [0]; while (*p == ' ' || *p == '\t') { Melder_assert (*p != '\0'); p ++; } while (*p != ' ' && *p != '\t') { Melder_assert (*p != '\0'); p ++; } // ignore the header of the zeroth column ("rowLabel" perhaps) for (long icol = 1; icol <= ncol; icol ++) { while (*p == ' ' || *p == '\t') { Melder_assert (*p != '\0'); p ++; } static MelderString buffer = { 0 }; MelderString_empty (& buffer); while (*p != ' ' && *p != '\t' && *p != '\n') { MelderString_appendCharacter (& buffer, *p); p ++; } TableOfReal_setColumnLabel (me.peek(), icol, buffer.string); MelderString_empty (& buffer); } for (long irow = 1; irow <= nrow; irow ++) { while (*p == ' ' || *p == '\t' || *p == '\n') { Melder_assert (*p != '\0'); p ++; } static MelderString buffer = { 0 }; MelderString_empty (& buffer); while (*p != ' ' && *p != '\t') { MelderString_appendCharacter (& buffer, *p); p ++; } TableOfReal_setRowLabel (me.peek(), irow, buffer.string); MelderString_empty (& buffer); for (long icol = 1; icol <= ncol; icol ++) { while (*p == ' ' || *p == '\t' || *p == '\n') { Melder_assert (*p != '\0'); p ++; } MelderString_empty (& buffer); while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') { MelderString_appendCharacter (& buffer, *p); p ++; } my data [irow] [icol] = Melder_atof (buffer.string); /* If cell contains a string, this will be 0. */ MelderString_empty (& buffer); } } return me.transfer(); } catch (MelderError) { Melder_throw ("TableOfReal: tab-separated file ", file, " not read."); } }