TableOfReal.cpp 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. /* TableOfReal.cpp
  2. *
  3. * Copyright (C) 1992-2018 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <ctype.h>
  19. #include "TableOfReal.h"
  20. #include "NUM2.h"
  21. #include "Matrix.h"
  22. #include "Formula.h"
  23. #include "oo_DESTROY.h"
  24. #include "TableOfReal_def.h"
  25. #include "oo_COPY.h"
  26. #include "TableOfReal_def.h"
  27. #include "oo_EQUAL.h"
  28. #include "TableOfReal_def.h"
  29. #include "oo_CAN_WRITE_AS_ENCODING.h"
  30. #include "TableOfReal_def.h"
  31. #include "oo_WRITE_BINARY.h"
  32. #include "TableOfReal_def.h"
  33. #include "oo_READ_BINARY.h"
  34. #include "TableOfReal_def.h"
  35. #include "oo_DESCRIPTION.h"
  36. #include "TableOfReal_def.h"
  37. Thing_implement (TableOfReal, Daata, 0);
  38. Thing_implement (TableOfRealList, Ordered, 0);
  39. static void fprintquotedstring (MelderFile file, conststring32 s) {
  40. MelderFile_writeCharacter (file, U'\"');
  41. if (s) { char32 c; while ((c = *s ++) != U'\0') { MelderFile_writeCharacter (file, c); if (c == U'\"') MelderFile_writeCharacter (file, c); } }
  42. MelderFile_writeCharacter (file, U'\"');
  43. }
  44. void structTableOfReal :: v_writeText (MelderFile file) {
  45. texputi32 (file, our numberOfColumns, U"numberOfColumns");
  46. MelderFile_write (file, U"\ncolumnLabels []: ");
  47. if (our numberOfColumns < 1) MelderFile_write (file, U"(empty)");
  48. MelderFile_write (file, U"\n");
  49. for (integer i = 1; i <= our numberOfColumns; i ++) {
  50. fprintquotedstring (file, our columnLabels [i].get());
  51. MelderFile_writeCharacter (file, U'\t');
  52. }
  53. texputi32 (file, our numberOfRows, U"numberOfRows");
  54. for (integer i = 1; i <= our numberOfRows; i ++) {
  55. MelderFile_write (file, U"\nrow [", i, U"]: ");
  56. fprintquotedstring (file, our rowLabels [i].get());
  57. for (integer j = 1; j <= our numberOfColumns; j ++) {
  58. double x = our data [i] [j];
  59. MelderFile_write (file, U"\t", x);
  60. }
  61. }
  62. }
  63. void structTableOfReal :: v_readText (MelderReadText a_text, int /*formatVersion*/) {
  64. our numberOfColumns = texgeti32 (a_text);
  65. if (our numberOfColumns >= 1) {
  66. our columnLabels = autostring32vector (our numberOfColumns);
  67. for (integer i = 1; i <= our numberOfColumns; i ++)
  68. our columnLabels [i] = texgetw16 (a_text);
  69. }
  70. our numberOfRows = texgeti32 (a_text);
  71. if (our numberOfRows >= 1) {
  72. our rowLabels = autostring32vector (our numberOfRows);
  73. }
  74. if (our numberOfRows >= 1 && our numberOfColumns >= 1) {
  75. our data = MATzero (our numberOfRows, our numberOfColumns);
  76. for (integer i = 1; i <= our numberOfRows; i ++) {
  77. our rowLabels [i] = texgetw16 (a_text);
  78. for (integer j = 1; j <= our numberOfColumns; j ++)
  79. our data [i] [j] = texgetr64 (a_text);
  80. }
  81. }
  82. }
  83. void structTableOfReal :: v_info () {
  84. structDaata :: v_info ();
  85. MelderInfo_writeLine (U"Number of rows: ", our numberOfRows);
  86. MelderInfo_writeLine (U"Number of columns: ", our numberOfColumns);
  87. }
  88. conststring32 structTableOfReal :: v_getRowStr (integer irow) {
  89. if (irow < 1 || irow > our numberOfRows) return nullptr;
  90. return our rowLabels [irow] ? our rowLabels [irow].get() : U"";
  91. }
  92. conststring32 structTableOfReal :: v_getColStr (integer icol) {
  93. if (icol < 1 || icol > our numberOfColumns) return nullptr;
  94. return our columnLabels [icol] ? our columnLabels [icol].get() : U"";
  95. }
  96. double structTableOfReal :: v_getMatrix (integer irow, integer icol) {
  97. if (irow < 1 || irow > our numberOfRows) return undefined;
  98. if (icol < 1 || icol > our numberOfColumns) return undefined;
  99. return our data [irow] [icol];
  100. }
  101. double structTableOfReal :: v_getRowIndex (conststring32 rowLabel) {
  102. return TableOfReal_rowLabelToIndex (this, rowLabel);
  103. }
  104. double structTableOfReal :: v_getColIndex (conststring32 columnLabel) {
  105. return TableOfReal_columnLabelToIndex (this, columnLabel);
  106. }
  107. void TableOfReal_init (TableOfReal me, integer numberOfRows, integer numberOfColumns) {
  108. if (numberOfRows < 1 || numberOfColumns < 1)
  109. Melder_throw (U"Cannot create cell-less table.");
  110. my numberOfRows = numberOfRows;
  111. my numberOfColumns = numberOfColumns;
  112. my rowLabels = autostring32vector (numberOfRows);
  113. Melder_assert (my rowLabels. size == numberOfRows); // probably captured by test script
  114. my columnLabels = autostring32vector (numberOfColumns);
  115. my data = MATzero (my numberOfRows, my numberOfColumns);
  116. }
  117. autoTableOfReal TableOfReal_create (integer numberOfRows, integer numberOfColumns) {
  118. try {
  119. autoTableOfReal me = Thing_new (TableOfReal);
  120. TableOfReal_init (me.get(), numberOfRows, numberOfColumns);
  121. return me;
  122. } catch (MelderError) {
  123. Melder_throw (U"TableOfReal not created.");
  124. }
  125. }
  126. /***** QUERY *****/
  127. integer TableOfReal_rowLabelToIndex (TableOfReal me, conststring32 label) {
  128. for (integer irow = 1; irow <= my numberOfRows; irow ++)
  129. if (my rowLabels [irow] && str32equ (my rowLabels [irow].get(), label))
  130. return irow;
  131. return 0;
  132. }
  133. integer TableOfReal_columnLabelToIndex (TableOfReal me, conststring32 label) {
  134. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  135. if (my columnLabels [icol] && str32equ (my columnLabels [icol].get(), label))
  136. return icol;
  137. return 0;
  138. }
  139. double TableOfReal_getColumnMean (TableOfReal me, integer columnNumber) {
  140. if (columnNumber < 1 || columnNumber > my numberOfColumns) return undefined;
  141. if (my numberOfRows < 1) return undefined;
  142. longdouble sum = 0.0;
  143. for (integer irow = 1; irow <= my numberOfRows; irow ++)
  144. sum += my data [irow] [columnNumber];
  145. return (double) sum / my numberOfRows;
  146. }
  147. double TableOfReal_getColumnStdev (TableOfReal me, integer columnNumber) {
  148. if (columnNumber < 1 || columnNumber > my numberOfColumns) return undefined;
  149. if (my numberOfRows < 2) return undefined;
  150. double mean = TableOfReal_getColumnMean (me, columnNumber);
  151. longdouble sum = 0.0;
  152. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  153. double d = my data [irow] [columnNumber] - mean;
  154. sum += d * d;
  155. }
  156. return sqrt ((double) sum / (my numberOfRows - 1));
  157. }
  158. /***** MODIFY *****/
  159. void TableOfReal_removeRow (TableOfReal me, integer rowNumber) {
  160. try {
  161. Melder_require (my numberOfRows > 1,
  162. me, U" has only one row, and a TableOfReal without rows cannot exist.");
  163. Melder_require (rowNumber > 0 && rowNumber <= my numberOfRows,
  164. U"No row ", rowNumber, U".");
  165. autoMAT newData = MATraw (my numberOfRows - 1, my numberOfColumns);
  166. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  167. for (integer irow = 1; irow < rowNumber; irow ++)
  168. newData [irow] [icol] = my data [irow] [icol];
  169. for (integer irow = rowNumber; irow < my numberOfRows; irow ++)
  170. newData [irow] [icol] = my data [irow + 1] [icol];
  171. }
  172. /*
  173. Change without error.
  174. */
  175. for (integer irow = rowNumber; irow < my numberOfRows; irow ++)
  176. my rowLabels [irow] = my rowLabels [irow + 1]. move();
  177. my rowLabels [my numberOfRows]. reset();
  178. my data = newData.move();
  179. my numberOfRows --;
  180. } catch (MelderError) {
  181. Melder_throw (me, U": row ", rowNumber, U" not removed.");
  182. }
  183. }
  184. void TableOfReal_insertRow (TableOfReal me, integer rowNumber) {
  185. try {
  186. if (rowNumber < 1 || rowNumber > my numberOfRows + 1)
  187. Melder_throw (U"Cannot create row ", rowNumber, U".");
  188. /*
  189. Create without change.
  190. */
  191. autoMAT newData = MATzero (my numberOfRows + 1, my numberOfColumns);
  192. autostring32vector newRowLabels (my numberOfRows + 1);
  193. for (integer irow = 1; irow < rowNumber; irow ++) {
  194. newRowLabels [irow] = my rowLabels [irow]. move();
  195. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  196. newData [irow] [icol] = my data [irow] [icol];
  197. }
  198. for (integer irow = my numberOfRows + 1; irow > rowNumber; irow --) {
  199. newRowLabels [irow] = my rowLabels [irow - 1]. move();
  200. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  201. newData [irow] [icol] = my data [irow - 1] [icol];
  202. }
  203. /*
  204. Change without error.
  205. */
  206. my rowLabels = std::move (newRowLabels);
  207. my data = newData.move();
  208. my numberOfRows ++;
  209. } catch (MelderError) {
  210. Melder_throw (me, U": row at position ", rowNumber, U" not inserted.");
  211. }
  212. }
  213. void TableOfReal_removeColumn (TableOfReal me, integer columnNumber) {
  214. try {
  215. if (my numberOfColumns == 1)
  216. Melder_throw (U"Cannot remove the only column.");
  217. if (columnNumber < 1 || columnNumber > my numberOfColumns)
  218. Melder_throw (U"No column ", columnNumber, U".");
  219. /*
  220. Create without change.
  221. */
  222. autoMAT newData = MATraw (my numberOfRows, my numberOfColumns - 1);
  223. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  224. for (integer icol = 1; icol < columnNumber; icol ++)
  225. newData [irow] [icol] = my data [irow] [icol];
  226. for (integer icol = columnNumber; icol < my numberOfColumns; icol ++)
  227. newData [irow] [icol] = my data [irow] [icol + 1];
  228. }
  229. /*
  230. Change without error.
  231. */
  232. for (integer icol = columnNumber; icol < my numberOfColumns; icol ++)
  233. my columnLabels [icol] = my columnLabels [icol + 1]. move();
  234. my columnLabels [my numberOfColumns]. reset();
  235. my data = newData.move();
  236. my numberOfColumns --;
  237. } catch (MelderError) {
  238. Melder_throw (me, U": column at position ", columnNumber, U" not inserted.");
  239. }
  240. }
  241. void TableOfReal_insertColumn (TableOfReal me, integer columnNumber) {
  242. try {
  243. if (columnNumber < 1 || columnNumber > my numberOfColumns + 1)
  244. Melder_throw (U"Cannot create column ", columnNumber, U".");
  245. /*
  246. Create without change.
  247. */
  248. autoMAT newData = MATzero (my numberOfRows, my numberOfColumns + 1);
  249. autostring32vector newColumnLabels (my numberOfColumns + 1);
  250. for (integer j = 1; j < columnNumber; j ++) {
  251. newColumnLabels [j] = my columnLabels [j]. move();
  252. for (integer i = 1; i <= my numberOfRows; i ++)
  253. newData [i] [j] = my data [i] [j];
  254. }
  255. for (integer j = my numberOfColumns + 1; j > columnNumber; j --) {
  256. newColumnLabels [j] = my columnLabels [j - 1]. move();
  257. for (integer i = 1; i <= my numberOfRows; i ++)
  258. newData [i] [j] = my data [i] [j - 1];
  259. }
  260. /*
  261. Change without error.
  262. */
  263. my columnLabels = std::move (newColumnLabels);
  264. my data = newData.move();
  265. my numberOfColumns ++;
  266. } catch (MelderError) {
  267. Melder_throw (me, U": column at position ", columnNumber, U" not inserted.");
  268. }
  269. }
  270. void TableOfReal_setRowLabel (TableOfReal me, integer rowNumber, conststring32 label) {
  271. try {
  272. if (rowNumber < 1 || rowNumber > my numberOfRows) return;
  273. my rowLabels [rowNumber] = Melder_dup (label);
  274. } catch (MelderError) {
  275. Melder_throw (me, U": label of row ", rowNumber, U" not set.");
  276. }
  277. }
  278. void TableOfReal_setColumnLabel (TableOfReal me, integer columnNumber, conststring32 label) {
  279. try {
  280. if (columnNumber < 1 || columnNumber > my numberOfColumns)
  281. return;
  282. my columnLabels [columnNumber] = Melder_dup (label);
  283. } catch (MelderError) {
  284. Melder_throw (me, U": label of column ", columnNumber, U" not set.");
  285. }
  286. }
  287. void TableOfReal_formula (TableOfReal me, conststring32 expression, Interpreter interpreter, TableOfReal thee) {
  288. try {
  289. Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
  290. Formula_Result result;
  291. if (! thee)
  292. thee = me;
  293. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  294. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  295. Formula_run (irow, icol, & result);
  296. thy data [irow] [icol] = result. numericResult;
  297. }
  298. }
  299. } catch (MelderError) {
  300. Melder_throw (me, U": formula not completed.");
  301. }
  302. }
  303. /***** EXTRACT PART *****/
  304. static void copyRowLabels (TableOfReal me, TableOfReal thee) {
  305. Melder_assert (me != thee);
  306. Melder_assert (my numberOfRows == thy numberOfRows);
  307. for (integer irow = 1; irow <= my numberOfRows; irow ++)
  308. thy rowLabels [irow] = Melder_dup (my rowLabels [irow].get());
  309. }
  310. static void copyColumnLabels (TableOfReal me, TableOfReal thee) {
  311. Melder_assert (me != thee);
  312. Melder_assert (my numberOfColumns == thy numberOfColumns);
  313. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  314. thy columnLabels [icol] = Melder_dup (my columnLabels [icol].get());
  315. }
  316. static void copyRow (TableOfReal me, integer myRow, TableOfReal thee, integer thyRow) {
  317. Melder_assert (me != thee);
  318. Melder_assert (my numberOfColumns == thy numberOfColumns);
  319. thy rowLabels [thyRow] = Melder_dup (my rowLabels [myRow].get());
  320. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  321. thy data [thyRow] [icol] = my data [myRow] [icol];
  322. }
  323. static void copyColumn (TableOfReal me, integer myCol, TableOfReal thee, integer thyCol) {
  324. Melder_assert (me != thee);
  325. Melder_assert (my numberOfRows == thy numberOfRows);
  326. thy columnLabels [thyCol] = Melder_dup (my columnLabels [myCol].get());
  327. for (integer irow = 1; irow <= my numberOfRows; irow ++)
  328. thy data [irow] [thyCol] = my data [irow] [myCol];
  329. }
  330. autoTableOfReal TableOfReal_extractRowsWhereColumn (TableOfReal me, integer column, kMelder_number which, double criterion) {
  331. try {
  332. if (column < 1 || column > my numberOfColumns)
  333. Melder_throw (U"No such column: ", column, U".");
  334. integer n = 0;
  335. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  336. if (Melder_numberMatchesCriterion (my data [irow] [column], which, criterion)) {
  337. n ++;
  338. }
  339. }
  340. if (n == 0) Melder_throw (U"No row matches this criterion.");
  341. autoTableOfReal thee = TableOfReal_create (n, my numberOfColumns);
  342. copyColumnLabels (me, thee.get());
  343. n = 0;
  344. for (integer irow = 1; irow <= my numberOfRows; irow ++)
  345. if (Melder_numberMatchesCriterion (my data [irow] [column], which, criterion))
  346. copyRow (me, irow, thee.get(), ++ n);
  347. return thee;
  348. } catch (MelderError) {
  349. Melder_throw (me, U": rows not extracted.");
  350. }
  351. }
  352. autoTableOfReal TableOfReal_extractRowsWhereLabel (TableOfReal me, kMelder_string which, conststring32 criterion) {
  353. try {
  354. integer n = 0;
  355. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  356. if (Melder_stringMatchesCriterion (my rowLabels [irow].get(), which, criterion, true)) {
  357. n ++;
  358. }
  359. }
  360. if (n == 0)
  361. Melder_throw (U"No row matches this criterion.");
  362. autoTableOfReal thee = TableOfReal_create (n, my numberOfColumns);
  363. copyColumnLabels (me, thee.get());
  364. n = 0;
  365. for (integer irow = 1; irow <= my numberOfRows; irow ++)
  366. if (Melder_stringMatchesCriterion (my rowLabels [irow].get(), which, criterion, true))
  367. copyRow (me, irow, thee.get(), ++ n);
  368. return thee;
  369. } catch (MelderError) {
  370. Melder_throw (me, U": rows not extracted.");
  371. }
  372. }
  373. autoTableOfReal TableOfReal_extractColumnsWhereRow (TableOfReal me, integer row, kMelder_number which, double criterion) {
  374. try {
  375. if (row < 1 || row > my numberOfRows)
  376. Melder_throw (U"No such row: ", row, U".");
  377. integer n = 0;
  378. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  379. if (Melder_numberMatchesCriterion (my data [row] [icol], which, criterion)) {
  380. n ++;
  381. }
  382. }
  383. if (n == 0) Melder_throw (U"No column matches this criterion.");
  384. autoTableOfReal thee = TableOfReal_create (my numberOfRows, n);
  385. copyRowLabels (me, thee.get());
  386. n = 0;
  387. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  388. if (Melder_numberMatchesCriterion (my data [row] [icol], which, criterion))
  389. copyColumn (me, icol, thee.get(), ++ n);
  390. return thee;
  391. } catch (MelderError) {
  392. Melder_throw (me, U": columns not extracted.");
  393. }
  394. }
  395. autoTableOfReal TableOfReal_extractColumnsWhereLabel (TableOfReal me, kMelder_string which, conststring32 criterion) {
  396. try {
  397. integer n = 0;
  398. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  399. if (Melder_stringMatchesCriterion (my columnLabels [icol].get(), which, criterion, true)) {
  400. n ++;
  401. }
  402. }
  403. if (n == 0) Melder_throw (U"No column matches this criterion.");
  404. autoTableOfReal thee = TableOfReal_create (my numberOfRows, n);
  405. copyRowLabels (me, thee.get());
  406. n = 0;
  407. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  408. if (Melder_stringMatchesCriterion (my columnLabels [icol].get(), which, criterion, true)) {
  409. copyColumn (me, icol, thee.get(), ++ n);
  410. }
  411. }
  412. return thee;
  413. } catch (MelderError) {
  414. Melder_throw (me, U": columns not extracted.");
  415. }
  416. }
  417. /*
  418. * Acceptable ranges e.g. "1 4 2 3:7 4:3 3:5:2" -->
  419. * 1, 4, 2, 3, 4, 5, 6, 7, 4, 3, 3, 4, 5, 4, 3, 2
  420. * Overlap is allowed. Ranges can go up and down.
  421. */
  422. static integer *getElementsOfRanges (conststring32 ranges, integer maximumElement, integer *numberOfElements, conststring32 elementType) {
  423. /*
  424. Count the elements.
  425. */
  426. integer previousElement = 0;
  427. *numberOfElements = 0;
  428. const char32 *p = & ranges [0];
  429. for (;;) {
  430. while (*p == U' ' || *p == U'\t') p ++;
  431. if (*p == U'\0') break;
  432. if (Melder_isAsciiDecimalNumber (*p)) {
  433. integer currentElement = Melder_atoi (p);
  434. if (currentElement == 0)
  435. Melder_throw (U"No such ", elementType, U": 0 (minimum is 1).");
  436. if (currentElement > maximumElement)
  437. Melder_throw (U"No such ", elementType, U": ", currentElement, U" (maximum is ", maximumElement, U").");
  438. *numberOfElements += 1;
  439. previousElement = currentElement;
  440. do { p ++; } while (Melder_isAsciiDecimalNumber (*p));
  441. } else if (*p == ':') {
  442. if (previousElement == 0)
  443. Melder_throw (U"Cannot start range with colon.");
  444. do { p ++; } while (*p == U' ' || *p == U'\t');
  445. if (*p == U'\0')
  446. Melder_throw (U"Cannot end range with colon.");
  447. Melder_require (Melder_isAsciiDecimalNumber (*p), U"End of range should be a positive whole number.");
  448. integer currentElement = Melder_atoi (p);
  449. if (currentElement == 0)
  450. Melder_throw (U"No such ", elementType, U": 0 (minimum is 1).");
  451. if (currentElement > maximumElement)
  452. Melder_throw (U"No such ", elementType, U": ", currentElement, U" (maximum is ", maximumElement, U").");
  453. if (currentElement > previousElement) {
  454. *numberOfElements += currentElement - previousElement;
  455. } else {
  456. *numberOfElements += previousElement - currentElement;
  457. }
  458. previousElement = currentElement;
  459. do { p ++; } while (Melder_isAsciiDecimalNumber (*p));
  460. } else {
  461. Melder_throw (U"Start of range should be a positive whole number.");
  462. }
  463. }
  464. /*
  465. Create room for the elements.
  466. */
  467. autoNUMvector <integer> elements (1, *numberOfElements);
  468. /*
  469. Store the elements.
  470. */
  471. previousElement = 0;
  472. *numberOfElements = 0;
  473. p = & ranges [0];
  474. for (;;) {
  475. while (*p == U' ' || *p == U'\t') p ++;
  476. if (*p == U'\0') break;
  477. if (Melder_isAsciiDecimalNumber (*p)) {
  478. integer currentElement = Melder_atoi (p);
  479. elements [++ *numberOfElements] = currentElement;
  480. previousElement = currentElement;
  481. do { p ++; } while (Melder_isAsciiDecimalNumber (*p));
  482. } else if (*p == ':') {
  483. do { p ++; } while (*p == U' ' || *p == U'\t');
  484. integer currentElement = Melder_atoi (p);
  485. if (currentElement > previousElement) {
  486. for (integer ielement = previousElement + 1; ielement <= currentElement; ielement ++) {
  487. elements [++ *numberOfElements] = ielement;
  488. }
  489. } else {
  490. for (integer ielement = previousElement - 1; ielement >= currentElement; ielement --) {
  491. elements [++ *numberOfElements] = ielement;
  492. }
  493. }
  494. previousElement = currentElement;
  495. do { p ++; } while (Melder_isAsciiDecimalNumber (*p));
  496. }
  497. }
  498. return elements.transfer();
  499. }
  500. autoTableOfReal TableOfReal_extractRowRanges (TableOfReal me, conststring32 ranges) {
  501. try {
  502. integer numberOfElements;
  503. autoNUMvector <integer> elements (getElementsOfRanges (ranges, my numberOfRows, & numberOfElements, U"row"), 1);
  504. autoTableOfReal thee = TableOfReal_create (numberOfElements, my numberOfColumns);
  505. copyColumnLabels (me, thee.get());
  506. for (integer ielement = 1; ielement <= numberOfElements; ielement ++)
  507. copyRow (me, elements [ielement], thee.get(), ielement);
  508. return thee;
  509. } catch (MelderError) {
  510. Melder_throw (me, U": row ranges not extracted.");
  511. }
  512. }
  513. autoTableOfReal TableOfReal_extractColumnRanges (TableOfReal me, conststring32 ranges) {
  514. try {
  515. integer numberOfElements;
  516. autoNUMvector <integer> elements (getElementsOfRanges (ranges, my numberOfColumns, & numberOfElements, U"column"), 1);
  517. autoTableOfReal thee = TableOfReal_create (my numberOfRows, numberOfElements);
  518. copyRowLabels (me, thee.get());
  519. for (integer ielement = 1; ielement <= numberOfElements; ielement ++)
  520. copyColumn (me, elements [ielement], thee.get(), ielement);
  521. return thee;
  522. } catch (MelderError) {
  523. Melder_throw (me, U": column ranges not extracted.");
  524. }
  525. }
  526. autoTableOfReal TableOfReal_extractRowsWhere (TableOfReal me, conststring32 condition, Interpreter interpreter) {
  527. try {
  528. Formula_compile (interpreter, me, condition, kFormula_EXPRESSION_TYPE_NUMERIC, true);
  529. Formula_Result result;
  530. /*
  531. Count the new number of rows.
  532. */
  533. integer numberOfElements = 0;
  534. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  535. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  536. Formula_run (irow, icol, & result);
  537. if (result. numericResult != 0.0) {
  538. numberOfElements ++;
  539. break;
  540. }
  541. }
  542. }
  543. if (numberOfElements < 1)
  544. Melder_throw (U"No rows match this condition.");
  545. /*
  546. Create room for the result.
  547. */
  548. autoTableOfReal thee = TableOfReal_create (numberOfElements, my numberOfColumns);
  549. copyColumnLabels (me, thee.get());
  550. /*
  551. Store the result.
  552. */
  553. numberOfElements = 0;
  554. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  555. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  556. Formula_run (irow, icol, & result);
  557. if (result. numericResult != 0.0) {
  558. copyRow (me, irow, thee.get(), ++ numberOfElements);
  559. break;
  560. }
  561. }
  562. }
  563. return thee;
  564. } catch (MelderError) {
  565. Melder_throw (me, U": rows not extracted.");
  566. }
  567. }
  568. autoTableOfReal TableOfReal_extractColumnsWhere (TableOfReal me, conststring32 condition, Interpreter interpreter) {
  569. try {
  570. Formula_compile (interpreter, me, condition, kFormula_EXPRESSION_TYPE_NUMERIC, true);
  571. Formula_Result result;
  572. /*
  573. Count the new number of columns.
  574. */
  575. integer numberOfElements = 0;
  576. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  577. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  578. Formula_run (irow, icol, & result);
  579. if (result. numericResult != 0.0) {
  580. numberOfElements ++;
  581. break;
  582. }
  583. }
  584. }
  585. if (numberOfElements < 1)
  586. Melder_throw (U"No columns match this condition.");
  587. /*
  588. Create room for the result.
  589. */
  590. autoTableOfReal thee = TableOfReal_create (my numberOfRows, numberOfElements);
  591. copyRowLabels (me, thee.get());
  592. /*
  593. Store the result.
  594. */
  595. numberOfElements = 0;
  596. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  597. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  598. Formula_run (irow, icol, & result);
  599. if (result. numericResult != 0.0) {
  600. copyColumn (me, icol, thee.get(), ++ numberOfElements);
  601. break;
  602. }
  603. }
  604. }
  605. return thee;
  606. } catch (MelderError) {
  607. Melder_throw (me, U": columns not extracted.");
  608. }
  609. }
  610. /***** EXTRACT *****/
  611. autoStrings TableOfReal_extractRowLabelsAsStrings (TableOfReal me) {
  612. try {
  613. autoStrings thee = Thing_new (Strings);
  614. thy strings = autostring32vector (my numberOfRows);
  615. thy numberOfStrings = my numberOfRows;
  616. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  617. thy strings [irow] = Melder_dup (my rowLabels [irow] ? my rowLabels [irow].get() : U"");
  618. }
  619. return thee;
  620. } catch (MelderError) {
  621. Melder_throw (me, U": row labels not extracted.");
  622. }
  623. }
  624. autoStrings TableOfReal_extractColumnLabelsAsStrings (TableOfReal me) {
  625. try {
  626. autoStrings thee = Thing_new (Strings);
  627. thy strings = autostring32vector (my numberOfColumns);
  628. thy numberOfStrings = my numberOfColumns;
  629. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  630. thy strings [icol] = Melder_dup (my columnLabels [icol] ? my columnLabels [icol].get() : U"");
  631. }
  632. return thee;
  633. } catch (MelderError) {
  634. Melder_throw (me, U": column labels not extracted.");
  635. }
  636. }
  637. /***** DRAW *****/
  638. static void NUMrationalize (double x, integer *numerator, integer *denominator) {
  639. double epsilon = 1e-6;
  640. *numerator = 1;
  641. for (*denominator = 1; *denominator <= 100000; (*denominator) ++) {
  642. double numerator_d = x * *denominator;
  643. integer rounded = Melder_iround (numerator_d);
  644. if (fabs (rounded - numerator_d) < epsilon) {
  645. *numerator = rounded;
  646. return;
  647. }
  648. }
  649. *denominator = 0; /* Failure. */
  650. }
  651. static void print4 (char *buffer, double value, int iformat, int width, int precision) {
  652. char formatString [40];
  653. if (iformat == 4) {
  654. integer numerator, denominator;
  655. NUMrationalize (value, & numerator, & denominator);
  656. if (numerator == 0)
  657. snprintf (buffer, 40, "0");
  658. else if (denominator > 1)
  659. snprintf (buffer, 40, "%s/%s", Melder8_integer (numerator), Melder8_integer (denominator));
  660. else
  661. snprintf (buffer, 40, "%.7g", value);
  662. } else {
  663. snprintf (formatString, 40, "%%%d.%d%c", width, precision, iformat == 1 ? 'f' : iformat == 2 ? 'e' : 'g');
  664. snprintf (buffer, 40, formatString, value);
  665. }
  666. }
  667. static void fixRows (TableOfReal me, integer *rowmin, integer *rowmax) {
  668. if (*rowmax < *rowmin) { *rowmin = 1; *rowmax = my numberOfRows; }
  669. else if (*rowmin < 1) *rowmin = 1;
  670. else if (*rowmax > my numberOfRows) *rowmax = my numberOfRows;
  671. }
  672. static void fixColumns (TableOfReal me, integer *colmin, integer *colmax) {
  673. if (*colmax < *colmin) { *colmin = 1; *colmax = my numberOfColumns; }
  674. else if (*colmin < 1) *colmin = 1;
  675. else if (*colmax > my numberOfColumns) *colmax = my numberOfColumns;
  676. }
  677. static double getMaxRowLabelWidth (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
  678. double maxWidth = 0.0;
  679. if (! my rowLabels) return 0.0;
  680. fixRows (me, & rowmin, & rowmax);
  681. for (integer irow = rowmin; irow <= rowmax; irow ++) if (my rowLabels [irow] && my rowLabels [irow] [0]) {
  682. double textWidth = Graphics_textWidth_ps (graphics, my rowLabels [irow].get(), true); // SILIPA is bigger than XIPA
  683. if (textWidth > maxWidth) maxWidth = textWidth;
  684. }
  685. return maxWidth;
  686. }
  687. static double getLeftMargin (Graphics graphics) {
  688. return Graphics_dxMMtoWC (graphics, 1.0);
  689. }
  690. static double getLineSpacing (Graphics graphics) {
  691. return Graphics_dyMMtoWC (graphics, 1.5 * Graphics_inqFontSize (graphics) * 25.4 / 72.0);
  692. }
  693. static double getMaxColumnLabelHeight (TableOfReal me, Graphics graphics, integer colmin, integer colmax) {
  694. double maxHeight = 0.0, lineSpacing = getLineSpacing (graphics);
  695. if (! my columnLabels) return 0.0;
  696. fixRows (me, & colmin, & colmax);
  697. for (integer icol = colmin; icol <= colmax; icol ++) if (my columnLabels [icol] && my columnLabels [icol] [0]) {
  698. if (maxHeight == 0.0) maxHeight = lineSpacing;
  699. }
  700. return maxHeight;
  701. }
  702. void TableOfReal_drawAsNumbers (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax, int iformat, int precision) {
  703. fixRows (me, & rowmin, & rowmax);
  704. Graphics_setInner (graphics);
  705. Graphics_setWindow (graphics, 0.5, my numberOfColumns + 0.5, 0.0, 1.0);
  706. double leftMargin = getLeftMargin (graphics); // not earlier!
  707. double lineSpacing = getLineSpacing (graphics); // not earlier!
  708. double maxTextWidth = getMaxRowLabelWidth (me, graphics, rowmin, rowmax);
  709. double maxTextHeight = getMaxColumnLabelHeight (me, graphics, 1, my numberOfColumns);
  710. Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_BOTTOM);
  711. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  712. if (my columnLabels && my columnLabels [icol] && my columnLabels [icol] [0])
  713. Graphics_text (graphics, icol, 1, my columnLabels [icol].get());
  714. }
  715. for (integer irow = rowmin; irow <= rowmax; irow ++) {
  716. double y = 1.0 - lineSpacing * (irow - rowmin + 0.6);
  717. Graphics_setTextAlignment (graphics, Graphics_RIGHT, Graphics_HALF);
  718. if (my rowLabels && my rowLabels [irow] && my rowLabels [irow] [0])
  719. Graphics_text (graphics, 0.5 - leftMargin, y, my rowLabels [irow].get());
  720. Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_HALF);
  721. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  722. char text [40];
  723. print4 (text, my data [irow] [icol], iformat, 0, precision);
  724. Graphics_text (graphics, icol, y, Melder_peek8to32 (text));
  725. }
  726. }
  727. if (maxTextHeight != 0.0) {
  728. double left = 0.5;
  729. if (maxTextWidth > 0.0) left -= maxTextWidth + 2 * leftMargin;
  730. Graphics_line (graphics, left, 1.0, my numberOfColumns + 0.5, 1.0);
  731. }
  732. Graphics_unsetInner (graphics);
  733. }
  734. void TableOfReal_drawAsNumbers_if (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax, int iformat, int precision,
  735. conststring32 conditionFormula, Interpreter interpreter)
  736. {
  737. try {
  738. autoMatrix original = TableOfReal_to_Matrix (me);
  739. autoMatrix conditions = Data_copy (original.get());
  740. fixRows (me, & rowmin, & rowmax);
  741. Graphics_setInner (graphics);
  742. Graphics_setWindow (graphics, 0.5, my numberOfColumns + 0.5, 0.0, 1.0);
  743. double leftMargin = getLeftMargin (graphics); // not earlier!
  744. double lineSpacing = getLineSpacing (graphics); // not earlier!
  745. double maxTextWidth = getMaxRowLabelWidth (me, graphics, rowmin, rowmax);
  746. double maxTextHeight = getMaxColumnLabelHeight (me, graphics, 1, my numberOfColumns);
  747. Matrix_formula (original.get(), conditionFormula, interpreter, conditions.get());
  748. Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_BOTTOM);
  749. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  750. if (my columnLabels && my columnLabels [icol] && my columnLabels [icol] [0])
  751. Graphics_text (graphics, icol, 1, my columnLabels [icol].get());
  752. }
  753. for (integer irow = rowmin; irow <= rowmax; irow ++) {
  754. double y = 1.0 - lineSpacing * (irow - rowmin + 0.6);
  755. Graphics_setTextAlignment (graphics, Graphics_RIGHT, Graphics_HALF);
  756. if (my rowLabels && my rowLabels [irow] && my rowLabels [irow] [0])
  757. Graphics_text (graphics, 0.5 - leftMargin, y, my rowLabels [irow].get());
  758. Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_HALF);
  759. for (integer icol = 1; icol <= my numberOfColumns; icol ++) if (conditions -> z [irow] [icol] != 0.0) {
  760. char text [40];
  761. print4 (text, my data [irow] [icol], iformat, 0, precision);
  762. Graphics_text (graphics, icol, y, Melder_peek8to32 (text));
  763. }
  764. }
  765. if (maxTextHeight != 0.0) {
  766. double left = 0.5;
  767. if (maxTextWidth > 0.0) left -= maxTextWidth + 2 * leftMargin;
  768. Graphics_line (graphics, left, 1.0, my numberOfColumns + 0.5, 1.0);
  769. }
  770. Graphics_unsetInner (graphics);
  771. } catch (MelderError) {
  772. Melder_throw (me, U": numbers not drawn.");
  773. }
  774. }
  775. void TableOfReal_drawVerticalLines (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
  776. integer colmin = 1, colmax = my numberOfColumns;
  777. fixRows (me, & rowmin, & rowmax);
  778. Graphics_setInner (graphics);
  779. Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, 0, 1);
  780. double lineSpacing = getLineSpacing (graphics); // not earlier!
  781. double maxTextWidth = getMaxRowLabelWidth (me, graphics, rowmin, rowmax);
  782. double maxTextHeight = getMaxColumnLabelHeight (me, graphics, 1, my numberOfColumns);
  783. if (maxTextWidth > 0.0) colmin -= 1;
  784. for (integer col = colmin + 1; col <= colmax; col ++)
  785. Graphics_line (graphics, col - 0.5, 1.0 + maxTextHeight, col - 0.5, 1.0 - lineSpacing * (rowmax - rowmin + 1));
  786. Graphics_unsetInner (graphics);
  787. }
  788. void TableOfReal_drawLeftAndRightLines (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
  789. integer colmin = 1, colmax = my numberOfColumns;
  790. fixRows (me, & rowmin, & rowmax);
  791. Graphics_setInner (graphics);
  792. Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, 0.0, 1.0);
  793. double lineSpacing = getLineSpacing (graphics);
  794. double maxTextWidth = getMaxRowLabelWidth (me, graphics, rowmin, rowmax);
  795. double maxTextHeight = getMaxColumnLabelHeight (me, graphics, 1, my numberOfColumns);
  796. double left = 0.5;
  797. if (maxTextWidth > 0.0) left -= maxTextWidth + 2.0 * lineSpacing;
  798. double right = colmax + 0.5;
  799. double top = 1.0 + maxTextHeight;
  800. double bottom = 1.0 - lineSpacing * (rowmax - rowmin + 1);
  801. Graphics_line (graphics, left, top, left, bottom);
  802. Graphics_line (graphics, right, top, right, bottom);
  803. Graphics_unsetInner (graphics);
  804. }
  805. void TableOfReal_drawHorizontalLines (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
  806. integer colmin = 1, colmax = my numberOfColumns;
  807. fixRows (me, & rowmin, & rowmax);
  808. Graphics_setInner (graphics);
  809. Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, 0, 1);
  810. double lineSpacing = getLineSpacing (graphics);
  811. double maxTextWidth = getMaxRowLabelWidth (me, graphics, rowmin, rowmax);
  812. double maxTextHeight = getMaxColumnLabelHeight (me, graphics, 1, my numberOfColumns);
  813. double left = 0.5;
  814. double top = rowmin;
  815. if (maxTextWidth > 0.0) left -= maxTextWidth + 2.0 * lineSpacing;
  816. if (maxTextHeight > 0.0) rowmin -= 1;
  817. double right = colmax + 0.5;
  818. for (integer irow = rowmin; irow < rowmax; irow ++) {
  819. double y = 1.0 - lineSpacing * (irow - top + 1);
  820. Graphics_line (graphics, left, y, right, y);
  821. }
  822. Graphics_unsetInner (graphics);
  823. }
  824. void TableOfReal_drawTopAndBottomLines (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
  825. integer colmin = 1, colmax = my numberOfColumns;
  826. fixRows (me, & rowmin, & rowmax);
  827. Graphics_setInner (graphics);
  828. Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, 0.0, 1.0);
  829. double lineSpacing = getLineSpacing (graphics);
  830. double maxTextWidth = getMaxRowLabelWidth (me, graphics, rowmin, rowmax);
  831. double maxTextHeight = getMaxColumnLabelHeight (me, graphics, 1, my numberOfColumns);
  832. double left = 0.5;
  833. if (maxTextWidth > 0.0) left -= maxTextWidth + 2 * lineSpacing;
  834. double right = colmax + 0.5;
  835. double top = 1.0 + maxTextHeight;
  836. double bottom = 1.0 - lineSpacing * (rowmax - rowmin + 1);
  837. Graphics_line (graphics, left, top, right, top);
  838. Graphics_line (graphics, left, bottom, right, bottom);
  839. Graphics_unsetInner (graphics);
  840. }
  841. void TableOfReal_drawAsSquares (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax,
  842. integer colmin, integer colmax, bool garnish)
  843. {
  844. double dx = 1.0, dy = 1.0;
  845. Graphics_Colour colour = Graphics_inqColour (graphics);
  846. fixRows (me, & rowmin, & rowmax);
  847. fixColumns (me, & colmin, & colmax);
  848. Graphics_setInner (graphics);
  849. Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, rowmin - 0.5, rowmax + 0.5);
  850. double datamax = my data [rowmin] [colmin];
  851. for (integer irow = 1; irow <= my numberOfRows; irow ++)
  852. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  853. if (fabs (my data [irow] [icol]) > datamax) datamax = fabs (my data [irow] [icol]);
  854. for (integer irow = rowmin; irow <= rowmax; irow ++) {
  855. double y = rowmax + rowmin - irow;
  856. for (integer icol = colmin; icol <= colmax; icol ++) {
  857. double x = icol;
  858. /* two neighbouring squares should not touch -> 0.95 */
  859. double d = 0.95 * sqrt (fabs (my data [irow] [icol]) / datamax);
  860. double x1WC = x - d * dx / 2.0, x2WC = x + d * dx / 2.0;
  861. double y1WC = y - d * dy / 2.0, y2WC = y + d * dy / 2.0;
  862. if (my data [irow] [icol] > 0) Graphics_setColour (graphics, Graphics_WHITE);
  863. Graphics_fillRectangle (graphics, x1WC, x2WC, y1WC, y2WC);
  864. Graphics_setColour (graphics, colour);
  865. Graphics_rectangle (graphics, x1WC, x2WC , y1WC, y2WC);
  866. }
  867. }
  868. Graphics_setGrey (graphics, 0.0);
  869. Graphics_unsetInner (graphics);
  870. if (garnish) {
  871. for (integer irow = rowmin; irow <= rowmax; irow ++) if (my rowLabels [irow])
  872. Graphics_markLeft (graphics, rowmax + rowmin - irow, false, false, false, my rowLabels [irow].get());
  873. for (integer icol = colmin; icol <= colmax; icol ++) if (my columnLabels [icol])
  874. Graphics_markTop (graphics, icol, false, false, false, my columnLabels [icol].get());
  875. }
  876. }
  877. autoTableOfReal TablesOfReal_append (TableOfReal me, TableOfReal thee) {
  878. try {
  879. if (thy numberOfColumns != my numberOfColumns)
  880. Melder_throw (U"Numbers of columns are ", my numberOfColumns, U" and ", thy numberOfColumns, U" but should be equal.");
  881. autoTableOfReal him = Thing_newFromClass (my classInfo).static_cast_move <structTableOfReal> ();
  882. TableOfReal_init (him.get(), my numberOfRows + thy numberOfRows, my numberOfColumns);
  883. /* Unsafe: new attributes not initialized. */
  884. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  885. TableOfReal_setColumnLabel (him.get(), icol, my columnLabels [icol].get());
  886. }
  887. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  888. TableOfReal_setRowLabel (him.get(), irow, my rowLabels [irow].get());
  889. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  890. his data [irow] [icol] = my data [irow] [icol];
  891. }
  892. for (integer irow = 1; irow <= thy numberOfRows; irow ++) {
  893. integer hisRow = irow + my numberOfRows;
  894. TableOfReal_setRowLabel (him.get(), hisRow, thy rowLabels [irow].get());
  895. for (integer icol = 1; icol <= my numberOfColumns; icol ++)
  896. his data [hisRow] [icol] = thy data [irow] [icol];
  897. }
  898. return him;
  899. } catch (MelderError) {
  900. Melder_throw (U"TableOfReal objects not appended.");
  901. }
  902. }
  903. autoTableOfReal TablesOfReal_appendMany (OrderedOf<structTableOfReal>* me) {
  904. try {
  905. if (my size == 0) Melder_throw (U"Cannot add zero tables.");
  906. TableOfReal thee = my at [1];
  907. integer totalNumberOfRows = thy numberOfRows;
  908. integer numberOfColumns = thy numberOfColumns;
  909. for (integer itab = 2; itab <= my size; itab ++) {
  910. thee = my at [itab];
  911. totalNumberOfRows += thy numberOfRows;
  912. if (thy numberOfColumns != numberOfColumns) Melder_throw (U"Numbers of columns do not match.");
  913. }
  914. autoTableOfReal him = Thing_newFromClass (thy classInfo).static_cast_move <structTableOfReal> ();
  915. TableOfReal_init (him.get(), totalNumberOfRows, numberOfColumns);
  916. /* Unsafe: new attributes not initialized. */
  917. for (integer icol = 1; icol <= numberOfColumns; icol ++) {
  918. TableOfReal_setColumnLabel (him.get(), icol, thy columnLabels [icol].get());
  919. }
  920. totalNumberOfRows = 0;
  921. for (integer itab = 1; itab <= my size; itab ++) {
  922. thee = my at [itab];
  923. for (integer irow = 1; irow <= thy numberOfRows; irow ++) {
  924. totalNumberOfRows ++;
  925. TableOfReal_setRowLabel (him.get(), totalNumberOfRows, thy rowLabels [irow].get());
  926. for (integer icol = 1; icol <= numberOfColumns; icol ++)
  927. his data [totalNumberOfRows] [icol] = thy data [irow] [icol];
  928. }
  929. }
  930. Melder_assert (totalNumberOfRows == his numberOfRows);
  931. return him;
  932. } catch (MelderError) {
  933. Melder_throw (U"TableOfReal objects not appended.");
  934. }
  935. }
  936. static void TableOfReal_sort (TableOfReal me, bool useLabels, integer column1, integer column2) {
  937. for (integer irow = 1; irow < my numberOfRows; irow ++) for (integer jrow = irow + 1; jrow <= my numberOfRows; jrow ++) {
  938. if (useLabels) {
  939. if (my rowLabels [irow]) {
  940. if (my rowLabels [jrow]) {
  941. int compare = str32cmp (my rowLabels [irow].get(), my rowLabels [jrow].get());
  942. if (compare < 0)
  943. continue;
  944. if (compare > 0)
  945. goto swap;
  946. } else {
  947. goto swap;
  948. }
  949. } else if (my rowLabels [jrow]) continue;
  950. }
  951. /*
  952. * If we arrive here, the two labels are equal or both null (or useLabels is `false`).
  953. */
  954. if (column1 > 0 && column1 <= my numberOfColumns) {
  955. if (my data [irow] [column1] < my data [jrow] [column1])
  956. continue;
  957. if (my data [irow] [column1] > my data [jrow] [column1])
  958. goto swap;
  959. }
  960. if (column2 > 0 && column2 <= my numberOfColumns) {
  961. if (my data [irow] [column2] < my data [jrow] [column2])
  962. continue;
  963. if (my data [irow] [column2] > my data [jrow] [column2])
  964. goto swap;
  965. }
  966. /*
  967. * If we arrive here, everything is equal.
  968. */
  969. continue;
  970. swap:
  971. std::swap (my rowLabels [irow], my rowLabels [jrow]);
  972. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  973. double tmpValue = my data [irow] [icol];
  974. my data [irow] [icol] = my data [jrow] [icol];
  975. my data [jrow] [icol] = tmpValue;
  976. }
  977. }
  978. }
  979. void TableOfReal_sortByLabel (TableOfReal me, integer column1, integer column2) {
  980. TableOfReal_sort (me, true, column1, column2);
  981. }
  982. void TableOfReal_sortByColumn (TableOfReal me, integer column1, integer column2) {
  983. TableOfReal_sort (me, false, column1, column2);
  984. }
  985. autoTableOfReal Table_to_TableOfReal (Table me, integer labelColumn) {
  986. try {
  987. if (labelColumn < 1 || labelColumn > my numberOfColumns) labelColumn = 0;
  988. autoTableOfReal thee = TableOfReal_create (my rows.size, labelColumn ? my numberOfColumns - 1 : my numberOfColumns);
  989. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  990. Table_numericize_Assert (me, icol);
  991. }
  992. if (labelColumn) {
  993. for (integer icol = 1; icol < labelColumn; icol ++) {
  994. TableOfReal_setColumnLabel (thee.get(), icol, my columnHeaders [icol]. label.get());
  995. }
  996. for (integer icol = labelColumn + 1; icol <= my numberOfColumns; icol ++) {
  997. TableOfReal_setColumnLabel (thee.get(), icol - 1, my columnHeaders [icol]. label.get());
  998. }
  999. for (integer irow = 1; irow <= my rows.size; irow ++) {
  1000. TableRow row = my rows.at [irow];
  1001. char32 *string = row -> cells [labelColumn]. string.get();
  1002. TableOfReal_setRowLabel (thee.get(), irow, string ? string : U"");
  1003. for (integer icol = 1; icol < labelColumn; icol ++) {
  1004. thy data [irow] [icol] = row -> cells [icol]. number; // Optimization.
  1005. //thy data [irow] [icol] = Table_getNumericValue_Assert (me, irow, icol);
  1006. }
  1007. for (integer icol = labelColumn + 1; icol <= my numberOfColumns; icol ++) {
  1008. thy data [irow] [icol - 1] = row -> cells [icol]. number; // Optimization.
  1009. //thy data [irow] [icol - 1] = Table_getNumericValue_Assert (me, irow, icol);
  1010. }
  1011. }
  1012. } else {
  1013. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  1014. TableOfReal_setColumnLabel (thee.get(), icol, my columnHeaders [icol]. label.get());
  1015. }
  1016. for (integer irow = 1; irow <= my rows.size; irow ++) {
  1017. TableRow row = my rows.at [irow];
  1018. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  1019. thy data [irow] [icol] = row -> cells [icol]. number; // Optimization.
  1020. //thy data [irow] [icol] = Table_getNumericValue_Assert (me, irow, icol);
  1021. }
  1022. }
  1023. }
  1024. return thee;
  1025. } catch (MelderError) {
  1026. Melder_throw (me, U": not converted to TableOfReal.");
  1027. }
  1028. }
  1029. autoTable TableOfReal_to_Table (TableOfReal me, conststring32 labelOfFirstColumn) {
  1030. try {
  1031. autoTable thee = Table_createWithoutColumnNames (my numberOfRows, my numberOfColumns + 1);
  1032. Table_setColumnLabel (thee.get(), 1, labelOfFirstColumn);
  1033. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  1034. conststring32 columnLabel = my columnLabels [icol].get();
  1035. thy columnHeaders [icol + 1]. label = Melder_dup (columnLabel && columnLabel [0] ? columnLabel : U"?");
  1036. }
  1037. for (integer irow = 1; irow <= thy rows.size; irow ++) {
  1038. conststring32 stringValue = my rowLabels [irow].get();
  1039. TableRow row = thy rows.at [irow];
  1040. row -> cells [1]. string = Melder_dup (stringValue && stringValue [0] ? stringValue : U"?");
  1041. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  1042. double numericValue = my data [irow] [icol];
  1043. row -> cells [icol + 1]. string = Melder_dup (Melder_double (numericValue));
  1044. }
  1045. }
  1046. return thee;
  1047. } catch (MelderError) {
  1048. Melder_throw (me, U": not converted to Table.");
  1049. }
  1050. }
  1051. void TableOfReal_writeToHeaderlessSpreadsheetFile (TableOfReal me, MelderFile file) {
  1052. try {
  1053. autoMelderString buffer;
  1054. MelderString_copy (& buffer, U"rowLabel");
  1055. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  1056. MelderString_appendCharacter (& buffer, U'\t');
  1057. conststring32 s = my columnLabels [icol].get();
  1058. MelderString_append (& buffer, ( s && s [0] != U'\0' ? s : U"?" ));
  1059. }
  1060. MelderString_appendCharacter (& buffer, U'\n');
  1061. for (integer irow = 1; irow <= my numberOfRows; irow ++) {
  1062. conststring32 s = my rowLabels [irow].get();
  1063. MelderString_append (& buffer, ( s && s [0] != U'\0' ? s : U"?" ));
  1064. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  1065. MelderString_appendCharacter (& buffer, U'\t');
  1066. double x = my data [irow] [icol];
  1067. MelderString_append (& buffer, x);
  1068. }
  1069. MelderString_appendCharacter (& buffer, U'\n');
  1070. }
  1071. MelderFile_writeText (file, buffer.string, Melder_getOutputEncoding ());
  1072. } catch (MelderError) {
  1073. Melder_throw (me, U": not saved to tab-separated file.");
  1074. }
  1075. }
  1076. autoTableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file) {
  1077. try {
  1078. autostring32 string = MelderFile_readText (file);
  1079. /*
  1080. Count columns.
  1081. */
  1082. integer ncol = 0;
  1083. char32 *p = & string [0];
  1084. for (;;) {
  1085. char32 kar = *p++;
  1086. if (kar == U'\n' || kar == U'\0') break;
  1087. if (kar == U' ' || kar == U'\t') continue;
  1088. ncol ++;
  1089. do { kar = *p++; } while (kar != U' ' && kar != U'\t' && kar != U'\n' && kar != U'\0');
  1090. if (kar == U'\n' || kar == U'\0') break;
  1091. }
  1092. ncol --;
  1093. if (ncol < 1) Melder_throw (U"No columns.");
  1094. /*
  1095. Count elements.
  1096. */
  1097. p = & string [0];
  1098. integer nelements = 0;
  1099. for (;;) {
  1100. char32 kar = *p++;
  1101. if (kar == U'\0') break;
  1102. if (kar == U' ' || kar == U'\t' || kar == U'\n') continue;
  1103. nelements ++;
  1104. do { kar = *p++; } while (kar != U' ' && kar != U'\t' && kar != U'\n' && kar != U'\0');
  1105. if (kar == U'\0') break;
  1106. }
  1107. /*
  1108. Check if all columns are complete.
  1109. */
  1110. if (nelements == 0 || nelements % (ncol + 1) != 0)
  1111. Melder_throw (U"The number of elements (", nelements, U") is not a multiple of the number of columns plus 1 (", ncol + 1, U").");
  1112. /*
  1113. Create empty table.
  1114. */
  1115. integer nrow = nelements / (ncol + 1) - 1;
  1116. autoTableOfReal me = TableOfReal_create (nrow, ncol);
  1117. /*
  1118. Read elements.
  1119. */
  1120. autoMelderString buffer;
  1121. p = & string [0];
  1122. while (*p == U' ' || *p == U'\t') { Melder_assert (*p != U'\0'); p ++; }
  1123. while (*p != U' ' && *p != U'\t') { Melder_assert (*p != U'\0'); p ++; } // ignore the header of the zeroth column ("rowLabel" perhaps)
  1124. for (integer icol = 1; icol <= ncol; icol ++) {
  1125. while (*p == U' ' || *p == U'\t') { Melder_assert (*p != U'\0'); p ++; }
  1126. MelderString_empty (& buffer);
  1127. while (*p != U' ' && *p != U'\t' && *p != U'\n') {
  1128. MelderString_appendCharacter (& buffer, *p);
  1129. p ++;
  1130. }
  1131. TableOfReal_setColumnLabel (me.get(), icol, buffer.string);
  1132. }
  1133. for (integer irow = 1; irow <= nrow; irow ++) {
  1134. while (*p == U' ' || *p == U'\t' || *p == U'\n') { Melder_assert (*p != U'\0'); p ++; }
  1135. MelderString_empty (& buffer);
  1136. while (*p != U' ' && *p != U'\t') {
  1137. MelderString_appendCharacter (& buffer, *p);
  1138. p ++;
  1139. }
  1140. TableOfReal_setRowLabel (me.get(), irow, buffer.string);
  1141. for (integer icol = 1; icol <= ncol; icol ++) {
  1142. while (*p == U' ' || *p == U'\t' || *p == U'\n') { Melder_assert (*p != U'\0'); p ++; }
  1143. MelderString_empty (& buffer);
  1144. while (*p != U' ' && *p != U'\t' && *p != U'\n' && *p != U'\0') {
  1145. MelderString_appendCharacter (& buffer, *p);
  1146. p ++;
  1147. }
  1148. my data [irow] [icol] = Melder_atof (buffer.string); // if cell contains a string, this will be 0
  1149. }
  1150. }
  1151. return me;
  1152. } catch (MelderError) {
  1153. Melder_throw (U"TableOfReal: tab-separated file ", file, U" not read.");
  1154. }
  1155. }
  1156. /* End of file TableOfReal.cpp */