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.");
	}
}
Пример #2
0
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.");
	}
}
Пример #3
0
autoConfusion Confusion_groupStimuli (Confusion me, const char32 *labels, const char32 *newLabel, long newpos) {
	try {
		long ncondense = Melder_countTokens (labels);
		autoNUMvector<long> irow (1, my numberOfRows);

		for (long i = 1; i <= my numberOfRows; i++) {
			irow[i] = i;
		}

		for (char32 *token = Melder_firstToken (labels); token != nullptr; token = Melder_nextToken ()) {
			for (long i = 1; i <= my numberOfRows; i++) {
				if (Melder_equ (token, my rowLabels[i])) {
					irow[i] = 0;
					break;
				}
			}
		}
		long nfound = 0;
		for (long i = 1; i <= my numberOfRows; i++) {
			if (irow[i] == 0) {
				nfound ++;
			}
		}
		if (nfound == 0) {
			Melder_throw (U"Invalid stimulus labels.");
		}
		if (nfound != ncondense) {
			Melder_warning (U"One or more of the given stimulus labels are suspect.");
		}
		long newnstim = my numberOfRows - nfound + 1;
		if (newpos < 1) {
			newpos = 1;
		}
		if (newpos > newnstim) {
			newpos = newnstim;
		}
		autoConfusion thee = Confusion_create (newnstim, my numberOfColumns);
		NUMstrings_copyElements (my columnLabels, thy columnLabels, 1, my numberOfColumns);

		TableOfReal_setRowLabel (thee.get(), newpos, newLabel);
		long inewrow = 1;
		for (long i = 1; i <= my numberOfRows; i++) {
			long rowpos = newpos;
			if (irow[i] > 0) {
				if (inewrow == newpos) {
					inewrow++;
				}
				rowpos = inewrow;
				inewrow++;
				TableOfReal_setRowLabel (thee.get(), rowpos, my rowLabels[i]);
			}
			for (long j = 1; j <= my numberOfColumns; j++) {
				thy data[rowpos][j] += my data[i][j];
			}
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": stimuli not grouped.");
	}
}
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.");
	}
}
Пример #5
0
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.");
	}
}
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.");
	}
}
Пример #7
0
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.");
	}
}
Пример #8
0
Configuration Configuration_createLetterRExample (int choice) {
	double x1[33] = { 0,
	                  -5, -5, -5, -5, -5, -5, -5,   -5, -5, -5,
	                  -5, -4, -3, -2, -1,  0,  1, 2.25,  3,  3,
	                  2.25,  1,  0, -1, -2, -3, -4,   -1,  0,  1, 2, 3
	                };
	double y1[33] = { 0,
	                  -6, -5, -4, -3, -2, -1, 0,   1,  2,  3,
	                  4,  4,  4,  4,  4,  4, 4, 3.5,  2,  1,
	                  -0.5, -1, -1, -1, -1, -1, -1, -2, -3, -4, -5, -6
	                };
	double x2[33] = {0, 0.94756043346272423, 0.73504466902509913,
	                 0.4528453515175927,    0.46311499024105723,   0.30345454816993439,
	                 0.075184942115601547, -0.090010071904764719, -0.19630977381424003,
	                 -0.36341509807865086,  -0.54216996409132612,  -0.68704678013309872,
	                 -0.67370169194623086,  -0.69336494336440502,  -0.67809065144478664,
	                 -0.61382610572366281,  -0.68656530656078996,  -0.57704879646736551,
	                 -0.63417502349009069,  -0.37153350651419026,  -0.091809666009009777,
	                 0.054833807442559397,  0.1445593164362155,    0.055587230806920782,
	                 0.18201798315035453,   0.048445620192953162,  0.081595930742961439,
	                 0.20063623749033621,   0.28546520751183313,   0.39384438699721991,
	                 0.62832258520372286,   0.78548335015622228,   1.0610707888793069
	                };
	double y2[33] = {0, 0.49630791172076621, 0.53320347382055022,
	                 0.62384637225470441,  0.47592708487655661,  0.50364353255684202,
	                 0.55311720162084443,  0.55118713773007066,  0.50007736370068601,
	                 0.40432332354648709,  0.49817059660482677,  0.49803436631629411,
	                 0.33213829258059019,  0.14585700576425648, -0.022110500334692869,
	                 -0.1752555003289698,  -0.29448744336706828, -0.45639468287493545,
	                 -0.59177815505008013, -0.74980550818568981, -0.78095916436791279,
	                 -0.64447562732895125, -0.49526830813007033, -0.22443396573313243,
	                 -0.066378148077667398, -0.03498490725857361,  0.16196028200653381,
	                 0.30633527000982519, -0.14894460651161745, -0.30808798640907431,
	                 -0.35920781945385832, -0.62766325578928184, -0.60389363590825562
	                };
	try {
		double *x, *y;
		autoConfiguration me = Configuration_create (32, 2);

		if (choice == 2) {
			x = x2; y = y2;
			Thing_setName (me.peek(), U"R_fit");
		} else {
			x = x1; y = y1;
			Thing_setName (me.peek(), U"R");
		}

		for (long i = 1; i <= 32; i++) {
			char32 s[20];
			Melder_sprint (s,20, i);
			TableOfReal_setRowLabel (me.peek(), i, s);
			my data [i][1] = x[i];
			my data [i][2] = y[i];
		}
		return me.transfer();
	} catch (MelderError) {
		Melder_throw (U"Letter R Configuration not created.");
	}
}
Пример #9
0
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;	
}
Пример #10
0
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.");
	}
}
Пример #11
0
autoTableOfReal Discriminant_extractGroupCentroids (Discriminant me) {
    try {
        long m = my groups -> size, n = my eigen -> dimension;
        autoTableOfReal thee = TableOfReal_create (m, n);

        for (long i = 1; i <= m; i ++) {
            SSCP sscp = my groups->at [i];
            TableOfReal_setRowLabel (thee.get(), i, Thing_getName (sscp));
            NUMvector_copyElements (sscp -> centroid, thy data [i], 1, n);
        }
        NUMstrings_copyElements (my groups->at [m] -> columnLabels, thy columnLabels, 1, n);
        return thee;
    } catch (MelderError) {
        Melder_throw (me, U": group centroids not extracted.");
    }
}
Пример #12
0
autoConfiguration Configuration_createCarrollWishExample () {
	double  x[10] = {0.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, -1.0,  0.0,  1.0};
	double  y[10] = {0.0,  1.0, 1.0, 1.0,  0.0, 0.0, 0.0, -1.0, -1.0, -1.0};
	char32 const *label[] = { U"", U"A", U"B", U"C", U"D", U"E", U"F", U"G", U"H", U"I"};
	try {
		long nObjects = 9;
		autoConfiguration me = Configuration_create (nObjects, 2);
		for (long i = 1; i <= nObjects; i++) {
			my data[i][1] = x[i];
			my data[i][2] = y[i];
			TableOfReal_setRowLabel (me.peek(), i, label[i]);
		}
		return me;
	} catch (MelderError) {
		Melder_throw (U"Carroll Wish Configuration not created.");
	}
}
Пример #13
0
Configuration Configuration_createCarrollWishExample () {
	double  x[10] = {0, -1, 0, 1, -1, 0, 1, -1,  0,  1};
	double  y[10] = {0,  1, 1, 1,  0, 0, 0, -1, -1, -1};
	wchar_t const *label[] = { L"", L"A", L"B", L"C", L"D", L"E", L"F", L"G", L"H", L"I"};
	try {
		long nObjects = 9;
		autoConfiguration me = Configuration_create (nObjects, 2);
		for (long i = 1; i <= nObjects; i++) {
			my data[i][1] = x[i];
			my data[i][2] = y[i];
			TableOfReal_setRowLabel (me.peek(), i, label[i]);
		}
		return me.transfer();
	} catch (MelderError) {
		Melder_throw ("Carroll Wish Configuration not created.");
	}
}
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.");
	}
}
Пример #15
0
autoTableOfReal Discriminant_extractGroupStandardDeviations (Discriminant me) {
    try {
        long m = my groups->size, n = my eigen -> dimension;
        autoTableOfReal thee = TableOfReal_create (m, n);

        for (long i = 1; i <= m; i ++) {
            SSCP sscp = my groups->at [i];
            TableOfReal_setRowLabel (thee.get(), i, Thing_getName (sscp));
            long numberOfObservationsm1 = (long) floor (sscp -> numberOfObservations) - 1;
            for (long j = 1; j <= n; j ++) {
                thy data [i] [j] = numberOfObservationsm1 > 0 ? sqrt (sscp -> data [j] [j] / numberOfObservationsm1) : NUMundefined;
            }
        }
        NUMstrings_copyElements (my groups->at [m] -> columnLabels, thy columnLabels, 1, n);
        return thee;
    } catch (MelderError) {
        Melder_throw (me, U": group standard deviations not extracted.");
    }
}
Пример #16
0
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);
	}
}
Пример #17
0
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.");
    }
}
Пример #18
0
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 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.");
	}
}