Matrix.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /* Matrix.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 "Matrix.h"
  19. #include "NUM2.h"
  20. #include "Formula.h"
  21. #include "Eigen.h"
  22. #include "oo_DESTROY.h"
  23. #include "Matrix_def.h"
  24. #include "oo_COPY.h"
  25. #include "Matrix_def.h"
  26. #include "oo_EQUAL.h"
  27. #include "Matrix_def.h"
  28. #include "oo_CAN_WRITE_AS_ENCODING.h"
  29. #include "Matrix_def.h"
  30. #include "oo_WRITE_TEXT.h"
  31. #include "Matrix_def.h"
  32. #include "oo_WRITE_BINARY.h"
  33. #include "Matrix_def.h"
  34. #include "oo_READ_BINARY.h"
  35. #include "Matrix_def.h"
  36. #include "oo_DESCRIPTION.h"
  37. #include "Matrix_def.h"
  38. Thing_implement (Matrix, SampledXY, 2);
  39. void structMatrix :: v_info () {
  40. structDaata :: v_info ();
  41. double minimum = 0.0, maximum = 0.0;
  42. Matrix_getWindowExtrema (this, 1, our nx, 1, our ny, & minimum, & maximum);
  43. MelderInfo_writeLine (U"xmin: ", our xmin);
  44. MelderInfo_writeLine (U"xmax: ", our xmax);
  45. MelderInfo_writeLine (U"Number of columns: ", our nx);
  46. MelderInfo_writeLine (U"dx: ", our dx, U" (-> sampling rate ", 1.0 / our dx, U" )");
  47. MelderInfo_writeLine (U"x1: ", our x1);
  48. MelderInfo_writeLine (U"ymin: ", our ymin);
  49. MelderInfo_writeLine (U"ymax: ", our ymax);
  50. MelderInfo_writeLine (U"Number of rows: ", our ny);
  51. MelderInfo_writeLine (U"dy: ", our dy, U" (-> sampling rate ", 1.0 / our dy, U" )");
  52. MelderInfo_writeLine (U"y1: ", our y1);
  53. MelderInfo_writeLine (U"Minimum value: ", minimum);
  54. MelderInfo_writeLine (U"Maximum value: ", maximum);
  55. }
  56. void structMatrix :: v_readText (MelderReadText text, int formatVersion) {
  57. if (formatVersion < 0) {
  58. our xmin = texgetr64 (text);
  59. our xmax = texgetr64 (text);
  60. our ymin = texgetr64 (text);
  61. our ymax = texgetr64 (text);
  62. our nx = texgeti32 (text);
  63. our ny = texgeti32 (text);
  64. our dx = texgetr64 (text);
  65. our dy = texgetr64 (text);
  66. our x1 = texgetr64 (text);
  67. our y1 = texgetr64 (text);
  68. } else {
  69. Matrix_Parent :: v_readText (text, formatVersion);
  70. }
  71. if (our xmin > our xmax)
  72. Melder_throw (U"xmin should be less than or equal to xmax.");
  73. if (our ymin > our ymax)
  74. Melder_throw (U"ymin should be less than or equal to ymax.");
  75. if (our nx < 1)
  76. Melder_throw (U"nx should be at least 1.");
  77. if (our ny < 1)
  78. Melder_throw (U"ny should be at least 1.");
  79. if (our dx <= 0.0)
  80. Melder_throw (U"dx should be greater than 0.0.");
  81. if (our dy <= 0.0)
  82. Melder_throw (U"dy should be greater than 0.0.");
  83. our z.at = NUMmatrix_readText_r64 (1, our ny, 1, our nx, text, "z");
  84. our z.nrow = our ny;
  85. our z.ncol = our nx;
  86. }
  87. double structMatrix :: v_getValueAtSample (integer isamp, integer ilevel, int unit) {
  88. double value = our z [ilevel] [isamp];
  89. return ( isdefined (value) ? our v_convertStandardToSpecialUnit (value, ilevel, unit) : undefined );
  90. }
  91. double structMatrix :: v_getMatrix (integer irow, integer icol) {
  92. if (irow < 1 || irow > our ny) return 0.0;
  93. if (icol < 1 || icol > our nx) return 0.0;
  94. return z [irow] [icol];
  95. }
  96. double structMatrix :: v_getFunction2 (double x, double y) {
  97. double rrow = (y - our y1) / our dy + 1.0;
  98. double rcol = (x - our x1) / our dx + 1.0;
  99. integer irow = Melder_ifloor (rrow), icol = Melder_ifloor (rcol);
  100. double drow = rrow - irow, dcol = rcol - icol;
  101. double z1 = irow < 1 || irow > our ny || icol < 1 || icol > our nx ? 0.0 : z [irow] [icol];
  102. double z2 = irow < 0 || irow >= our ny || icol < 1 || icol > our nx ? 0.0 : z [irow + 1] [icol];
  103. double z3 = irow < 1 || irow > our ny || icol < 0 || icol >= our nx ? 0.0 : z [irow] [icol + 1];
  104. double z4 = irow < 0 || irow >= our ny || icol < 0 || icol >= our nx ? 0.0 : z [irow + 1] [icol + 1];
  105. return (1.0 - drow) * (1.0 - dcol) * z1 + drow * (1.0 - dcol) * z2 + (1.0 - drow) * dcol * z3 + drow * dcol * z4;
  106. }
  107. void Matrix_init
  108. (Matrix me, double xmin, double xmax, integer nx, double dx, double x1,
  109. double ymin, double ymax, integer ny, double dy, double y1)
  110. {
  111. Sampled_init (me, xmin, xmax, nx, dx, x1);
  112. my ymin = ymin;
  113. my ymax = ymax;
  114. my ny = ny;
  115. my dy = dy;
  116. my y1 = y1;
  117. my z = MATzero (my ny, my nx);
  118. }
  119. autoMatrix Matrix_create
  120. (double xmin, double xmax, integer nx, double dx, double x1,
  121. double ymin, double ymax, integer ny, double dy, double y1)
  122. {
  123. try {
  124. autoMatrix me = Thing_new (Matrix);
  125. Matrix_init (me.get(), xmin, xmax, nx, dx, x1, ymin, ymax, ny, dy, y1);
  126. return me;
  127. } catch (MelderError) {
  128. Melder_throw (U"Matrix object not created.");
  129. }
  130. }
  131. autoMatrix Matrix_createSimple (integer numberOfRows, integer numberOfColumns) {
  132. try {
  133. autoMatrix me = Thing_new (Matrix);
  134. Matrix_init (me.get(), 0.5, numberOfColumns + 0.5, numberOfColumns, 1, 1,
  135. 0.5, numberOfRows + 0.5, numberOfRows, 1, 1);
  136. return me;
  137. } catch (MelderError) {
  138. Melder_throw (U"Matrix object not created.");
  139. }
  140. }
  141. double Matrix_columnToX (Matrix me, double column) { return my x1 + (column - 1.0) * my dx; } // FIXME inline and use Sampled
  142. double Matrix_rowToY (Matrix me, double row) { return my y1 + (row - 1.0) * my dy; }
  143. double Matrix_xToColumn (Matrix me, double x) { return (x - my x1) / my dx + 1.0; }
  144. integer Matrix_xToLowColumn (Matrix me, double x) { return Melder_ifloor (Matrix_xToColumn (me, x)); }
  145. integer Matrix_xToHighColumn (Matrix me, double x) { return Melder_iceiling (Matrix_xToColumn (me, x)); }
  146. integer Matrix_xToNearestColumn (Matrix me, double x) { return Melder_iround (Matrix_xToColumn (me, x)); }
  147. double Matrix_yToRow (Matrix me, double y) { return (y - my y1) / my dy + 1.0; }
  148. integer Matrix_yToLowRow (Matrix me, double y) { return Melder_ifloor (Matrix_yToRow (me, y)); }
  149. integer Matrix_yToHighRow (Matrix me, double y) { return Melder_iceiling (Matrix_yToRow (me, y)); }
  150. integer Matrix_yToNearestRow (Matrix me, double y) { return Melder_iround (Matrix_yToRow (me, y)); }
  151. integer Matrix_getWindowSamplesX (Matrix me, double xmin, double xmax, integer *ixmin, integer *ixmax) {
  152. *ixmin = 1 + Melder_iceiling ((xmin - my x1) / my dx);
  153. *ixmax = 1 + Melder_ifloor ((xmax - my x1) / my dx);
  154. if (*ixmin < 1) *ixmin = 1;
  155. if (*ixmax > my nx) *ixmax = my nx;
  156. if (*ixmin > *ixmax) return 0;
  157. return *ixmax - *ixmin + 1;
  158. }
  159. integer Matrix_getWindowSamplesY (Matrix me, double ymin, double ymax, integer *iymin, integer *iymax) {
  160. *iymin = 1 + Melder_iceiling ((ymin - my y1) / my dy);
  161. *iymax = 1 + Melder_ifloor ((ymax - my y1) / my dy);
  162. if (*iymin < 1) *iymin = 1;
  163. if (*iymax > my ny) *iymax = my ny;
  164. if (*iymin > *iymax) return 0;
  165. return *iymax - *iymin + 1;
  166. }
  167. integer Matrix_getWindowExtrema (Matrix me, integer ixmin, integer ixmax, integer iymin, integer iymax,
  168. double *minimum, double *maximum)
  169. {
  170. if (ixmin == 0) ixmin = 1;
  171. if (ixmax == 0) ixmax = my nx;
  172. if (iymin == 0) iymin = 1;
  173. if (iymax == 0) iymax = my ny;
  174. if (ixmin > ixmax || iymin > iymax) return 0;
  175. *minimum = *maximum = my z [iymin] [ixmin];
  176. for (integer iy = iymin; iy <= iymax; iy ++) {
  177. for (integer ix = ixmin; ix <= ixmax; ix ++) {
  178. if (my z [iy] [ix] < *minimum) *minimum = my z [iy] [ix];
  179. if (my z [iy] [ix] > *maximum) *maximum = my z [iy] [ix];
  180. }
  181. }
  182. return (ixmax - ixmin + 1) * (iymax - iymin + 1);
  183. }
  184. double Matrix_getValueAtXY (Matrix me, double x, double y) {
  185. double row_real = (y - my y1) / my dy + 1.0;
  186. double col_real = (x - my x1) / my dx + 1.0;
  187. /*
  188. * We imagine a unit square around every (xi, yi) point in the matrix.
  189. * For (x, y) values outside the union of these squares, the z value is undefined.
  190. */
  191. if (row_real < 0.5 || row_real > my ny + 0.5) return undefined;
  192. if (col_real < 0.5 || col_real > my nx + 0.5) return undefined;
  193. /*
  194. * Determine the four nearest (xi, yi) points.
  195. */
  196. integer bottomRow = Melder_ifloor (row_real); // 0 <= bottomRow <= my ny
  197. integer topRow = bottomRow + 1; // 1 <= topRow <= my ny + 1
  198. integer leftCol = Melder_ifloor (col_real); // 0 <= leftCol <= my nx
  199. integer rightCol = leftCol + 1; // 1 <= rightCol <= my nx + 1
  200. double drow = row_real - bottomRow; // 0.0 <= drow < 1.0
  201. double dcol = col_real - leftCol; // 0.0 <= dcol < 1.0
  202. /*
  203. * If adjacent points exist
  204. * (i.e., both row numbers are between 1 and my ny,
  205. * or both column numbers are between 1 and my nx),
  206. * we do linear interpolation.
  207. * If not, we do constant extrapolation,
  208. * which can be simulated by an interpolation between equal z values.
  209. */
  210. if (bottomRow < 1) bottomRow = 1; // 1 <= bottomRow <= my ny
  211. if (topRow > my ny) topRow = my ny; // 1 <= topRow <= my ny
  212. if (leftCol < 1) leftCol = 1; // 1 <= leftCol <= my nx
  213. if (rightCol > my nx) rightCol = my nx; // 1 <= rightCol <= my nx
  214. return (1.0 - drow) * (1.0 - dcol) * my z [bottomRow] [leftCol] +
  215. drow * (1.0 - dcol) * my z [topRow] [leftCol] +
  216. (1.0 - drow) * dcol * my z [bottomRow] [rightCol] +
  217. drow * dcol * my z [topRow] [rightCol];
  218. }
  219. double Matrix_getSum (Matrix me) {
  220. longdouble sum = 0.0;
  221. for (integer irow = 1; irow <= my ny; irow ++)
  222. for (integer icol = 1; icol <= my nx; icol ++)
  223. sum += my z [irow] [icol];
  224. return (double) sum;
  225. }
  226. double Matrix_getNorm (Matrix me) {
  227. longdouble sum = 0.0;
  228. for (integer irow = 1; irow <= my ny; irow ++)
  229. for (integer icol = 1; icol <= my nx; icol ++)
  230. sum += my z [irow] [icol] * my z [irow] [icol];
  231. return sqrt ((double) sum);
  232. }
  233. void Matrix_drawRows (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
  234. double minimum, double maximum)
  235. {
  236. if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
  237. if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
  238. integer ixmin, ixmax, iymin, iymax;
  239. (void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
  240. (void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
  241. if (maximum <= minimum)
  242. (void) Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, & minimum, & maximum);
  243. if (maximum <= minimum) { minimum -= 1.0; maximum += 1.0; }
  244. if (xmin >= xmax) return;
  245. Graphics_setInner (g);
  246. for (integer iy = iymin; iy <= iymax; iy ++) {
  247. Graphics_setWindow (g, xmin, xmax,
  248. minimum - (iy - iymin) * (maximum - minimum),
  249. maximum + (iymax - iy) * (maximum - minimum));
  250. Graphics_function (g, my z [iy], ixmin, ixmax,
  251. Matrix_columnToX (me, ixmin), Matrix_columnToX (me, ixmax));
  252. }
  253. Graphics_unsetInner (g);
  254. if (iymin < iymax)
  255. Graphics_setWindow (g, xmin, xmax, my y1 + (iymin - 1.5) * my dy, my y1 + (iymax - 0.5) * my dy);
  256. }
  257. void Matrix_drawOneContour (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
  258. double height)
  259. {
  260. bool xreversed = xmin > xmax, yreversed = ymin > ymax;
  261. if (xmax == xmin) { xmin = my xmin; xmax = my xmax; }
  262. if (ymax == ymin) { ymin = my ymin; ymax = my ymax; }
  263. if (xreversed) { double temp = xmin; xmin = xmax; xmax = temp; }
  264. if (yreversed) { double temp = ymin; ymin = ymax; ymax = temp; }
  265. integer ixmin, ixmax, iymin, iymax;
  266. (void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
  267. (void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
  268. if (xmin == xmax || ymin == ymax) return;
  269. Graphics_setInner (g);
  270. Graphics_setWindow (g, xreversed ? xmax : xmin, xreversed ? xmin : xmax, yreversed ? ymax : ymin, yreversed ? ymin : ymax);
  271. Graphics_contour (g, my z.at,
  272. ixmin, ixmax, Matrix_columnToX (me, ixmin), Matrix_columnToX (me, ixmax),
  273. iymin, iymax, Matrix_rowToY (me, iymin), Matrix_rowToY (me, iymax),
  274. height);
  275. Graphics_rectangle (g, xmin, xmax, ymin, ymax);
  276. Graphics_unsetInner (g);
  277. }
  278. void Matrix_drawContours (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
  279. double minimum, double maximum)
  280. {
  281. double border [1 + 8];
  282. if (xmax == xmin) { xmin = my xmin; xmax = my xmax; }
  283. if (ymax == ymin) { ymin = my ymin; ymax = my ymax; }
  284. integer ixmin, ixmax, iymin, iymax;
  285. (void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
  286. (void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
  287. if (maximum <= minimum)
  288. (void) Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, & minimum, & maximum);
  289. if (maximum <= minimum) { minimum -= 1.0; maximum += 1.0; }
  290. for (integer iborder = 1; iborder <= 8; iborder ++)
  291. border [iborder] = minimum + iborder * (maximum - minimum) / (8 + 1);
  292. if (xmin == xmax || ymin == ymax) return;
  293. Graphics_setInner (g);
  294. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  295. Graphics_altitude (g, my z.at,
  296. ixmin, ixmax, Matrix_columnToX (me, ixmin), Matrix_columnToX (me, ixmax),
  297. iymin, iymax, Matrix_rowToY (me, iymin), Matrix_rowToY (me, iymax),
  298. 8, border);
  299. Graphics_rectangle (g, xmin, xmax, ymin, ymax);
  300. Graphics_unsetInner (g);
  301. }
  302. void Matrix_paintContours (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
  303. double minimum, double maximum)
  304. {
  305. double border [1 + 30];
  306. if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
  307. if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
  308. integer ixmin, ixmax, iymin, iymax;
  309. (void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
  310. (void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
  311. if (maximum <= minimum)
  312. (void) Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, & minimum, & maximum);
  313. if (maximum <= minimum) { minimum -= 1.0; maximum += 1.0; }
  314. for (integer iborder = 1; iborder <= 30; iborder ++)
  315. border [iborder] = minimum + iborder * (maximum - minimum) / (30 + 1);
  316. if (xmin >= xmax || ymin >= ymax) return;
  317. Graphics_setInner (g);
  318. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  319. Graphics_grey (g, my z.at,
  320. ixmin, ixmax, Matrix_columnToX (me, ixmin), Matrix_columnToX (me, ixmax),
  321. iymin, iymax, Matrix_rowToY (me, iymin), Matrix_rowToY (me, iymax),
  322. 30, border);
  323. Graphics_rectangle (g, xmin, xmax, ymin, ymax);
  324. Graphics_unsetInner (g);
  325. }
  326. static void cellArrayOrImage (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
  327. double minimum, double maximum, bool interpolate)
  328. {
  329. if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
  330. if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
  331. integer ixmin, ixmax, iymin, iymax;
  332. (void) Matrix_getWindowSamplesX (me, xmin - 0.49999 * my dx, xmax + 0.49999 * my dx,
  333. & ixmin, & ixmax);
  334. (void) Matrix_getWindowSamplesY (me, ymin - 0.49999 * my dy, ymax + 0.49999 * my dy,
  335. & iymin, & iymax);
  336. if (maximum <= minimum)
  337. (void) Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, & minimum, & maximum);
  338. if (maximum <= minimum) { minimum -= 1.0; maximum += 1.0; }
  339. if (xmin >= xmax || ymin >= ymax) return;
  340. Graphics_setInner (g);
  341. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  342. if (interpolate)
  343. Graphics_image (g, my z.at,
  344. ixmin, ixmax, Sampled_indexToX (me, ixmin - 0.5), Sampled_indexToX (me, ixmax + 0.5),
  345. iymin, iymax, SampledXY_indexToY (me, iymin - 0.5), SampledXY_indexToY (me, iymax + 0.5),
  346. minimum, maximum);
  347. else
  348. Graphics_cellArray (g, my z.at,
  349. ixmin, ixmax, Sampled_indexToX (me, ixmin - 0.5), Sampled_indexToX (me, ixmax + 0.5),
  350. iymin, iymax, SampledXY_indexToY (me, iymin - 0.5), SampledXY_indexToY (me, iymax + 0.5),
  351. minimum, maximum);
  352. Graphics_rectangle (g, xmin, xmax, ymin, ymax);
  353. Graphics_unsetInner (g);
  354. }
  355. void Matrix_paintImage (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
  356. double minimum, double maximum)
  357. {
  358. cellArrayOrImage (me, g, xmin, xmax, ymin, ymax, minimum, maximum, true);
  359. }
  360. void Matrix_paintCells (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
  361. double minimum, double maximum)
  362. {
  363. cellArrayOrImage (me, g, xmin, xmax, ymin, ymax, minimum, maximum, false);
  364. }
  365. void Matrix_paintSurface (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
  366. double minimum, double maximum, double elevation, double azimuth)
  367. {
  368. if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
  369. if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
  370. integer ixmin, ixmax, iymin, iymax;
  371. (void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
  372. (void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
  373. if (maximum <= minimum)
  374. (void) Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, & minimum, & maximum);
  375. if (maximum <= minimum) { minimum -= 1.0; maximum += 1.0; }
  376. Graphics_setInner (g);
  377. Graphics_setWindow (g, -1.0, 1.0, minimum, maximum);
  378. Graphics_surface (g, my z.at,
  379. ixmin, ixmax, Matrix_columnToX (me, ixmin), Matrix_columnToX (me, ixmax),
  380. iymin, iymax, Matrix_rowToY (me, iymin), Matrix_rowToY (me, iymax),
  381. minimum, maximum, elevation, azimuth);
  382. Graphics_unsetInner (g);
  383. }
  384. void Matrix_movie (Matrix me, Graphics g) {
  385. autoVEC column = VECraw (my ny);
  386. double minimum = 0.0, maximum = 1.0;
  387. Matrix_getWindowExtrema (me, 1, my nx, 1, my ny, & minimum, & maximum);
  388. for (integer icol = 1; icol <= my nx; icol ++) {
  389. VECcolumn_preallocated (column.get(), my z.get(), icol);
  390. Graphics_beginMovieFrame (g, & Graphics_WHITE);
  391. Graphics_setWindow (g, my ymin, my ymax, minimum, maximum);
  392. Graphics_function (g, column.at, 1, my ny, my ymin, my ymax);
  393. Graphics_endMovieFrame (g, 0.03);
  394. }
  395. }
  396. autoMatrix Matrix_readAP (MelderFile file) {
  397. try {
  398. autofile f = Melder_fopen (file, "rb");
  399. int16 header [256];
  400. for (integer i = 0; i < 256; i ++)
  401. header [i] = bingeti16LE (f);
  402. double samplingFrequency = header [100]; // converting up (from 16 to 54 bytes)
  403. Melder_casual (U"Sampling frequency ", samplingFrequency);
  404. autoMatrix me = Matrix_create (0.0, (double) header [34], header [34] /* Number of frames. */, 1.0, 0.5,
  405. 0.0, (double) header [35], header [35] /* Number of words per frame. */, 1.0, 0.5);
  406. /*Mat := MATRIX_create (Buffer.I2 [36], (* Number of words per frame. *)
  407. Buffer.I2 [35], (* Number of frames. *)
  408. 1.0,
  409. Buffer.I2 [111] / (* Samples per frame. *)
  410. Buffer.I2 [101]); (* Sampling frequency. *)*/
  411. Melder_casual (U"... Loading ", header [34], U" frames",
  412. U" of ", header [35], U" words ...");
  413. for (integer i = 1; i <= my nx; i ++)
  414. for (integer j = 1; j <= my ny; j ++)
  415. my z [j] [i] = bingeti16LE (f); // converting up (from 16 to 54 bytes)
  416. /*
  417. * Get pitch frequencies.
  418. */
  419. for (integer i = 1; i <= my nx; i ++)
  420. if (my z [1] [i] != 0.0)
  421. my z [1] [i] = - samplingFrequency / my z [1] [i];
  422. f.close (file);
  423. return me;
  424. } catch (MelderError) {
  425. Melder_throw (U"Matrix object not read from AP file ", file);
  426. }
  427. }
  428. autoMatrix Matrix_appendRows (Matrix me, Matrix thee, ClassInfo klas) {
  429. try {
  430. autoMatrix him = Thing_newFromClass (klas).static_cast_move<structMatrix>();
  431. Matrix_init (him.get(), my xmin < thy xmin ? my xmin : thy xmin,
  432. my xmax > thy xmax ? my xmax : thy xmax,
  433. my nx > thy nx ? my nx : thy nx, my dx, my x1 < thy x1 ? my x1 : thy x1,
  434. my ymin, my ymax + (thy ymax - thy ymin), my ny + thy ny, my dy, my y1);
  435. for (integer irow = 1; irow <= my ny; irow ++)
  436. for (integer icol = 1; icol <= my nx; icol ++)
  437. his z [irow] [icol] = my z [irow] [icol];
  438. for (integer irow = 1; irow <= thy ny; irow ++)
  439. for (integer icol = 1; icol <= thy nx; icol ++)
  440. his z [irow + my ny] [icol] = thy z [irow] [icol];
  441. return him;
  442. } catch (MelderError) {
  443. Melder_throw (me, U" & ", thee, U": rows not appended.");
  444. }
  445. }
  446. autoMatrix Matrix_readFromRawTextFile (MelderFile file) { // BUG: not Unicode-compatible (use of fscanf)
  447. try {
  448. autofile f = Melder_fopen (file, "rb");
  449. /*
  450. Count columns.
  451. */
  452. integer numberOfColumns = 0;
  453. for (;;) {
  454. int kar = fgetc (f);
  455. if (kar == EOF || Melder_isVerticalSpace ((char32) kar))
  456. break;
  457. if (Melder_isHorizontalSpace ((char32) kar))
  458. continue;
  459. numberOfColumns ++;
  460. do {
  461. kar = fgetc (f);
  462. } while (kar != EOF && ! Melder_isHorizontalOrVerticalSpace ((char32) kar));
  463. if (kar == EOF || Melder_isVerticalSpace ((char32) kar)) break;
  464. }
  465. if (numberOfColumns == 0)
  466. Melder_throw (U"File empty");
  467. /*
  468. Count elements.
  469. */
  470. rewind (f);
  471. integer numberOfElements = 0;
  472. for (;;) {
  473. double element;
  474. if (fscanf (f, "%lf", & element) < 1)
  475. break; // zero or end-of-file
  476. numberOfElements ++;
  477. }
  478. /*
  479. Check if all columns are complete.
  480. */
  481. if (numberOfElements == 0 || numberOfElements % numberOfColumns != 0)
  482. Melder_throw (U"The number of elements (", numberOfElements, U") is not a multiple of the number of columns (", numberOfColumns, U").");
  483. /*
  484. Create simple matrix.
  485. */
  486. integer numberOfRows = numberOfElements / numberOfColumns;
  487. autoMatrix me = Matrix_createSimple (numberOfRows, numberOfColumns);
  488. /*
  489. Read elements.
  490. */
  491. rewind (f);
  492. for (integer irow = 1; irow <= numberOfRows; irow ++) {
  493. for (integer icol = 1; icol <= numberOfColumns; icol ++)
  494. fscanf (f, "%lf", & my z [irow] [icol]);
  495. }
  496. f.close (file);
  497. return me;
  498. } catch (MelderError) {
  499. Melder_throw (U"Matrix object not read from raw text file ", file, U".");
  500. }
  501. }
  502. void Matrix_eigen (Matrix me, autoMatrix *out_eigenvectors, autoMatrix *out_eigenvalues) {
  503. try {
  504. Melder_require (my nx == my ny,
  505. U"The number of rows and the number of columns must be equal.");
  506. autoEigen eigen = Thing_new (Eigen);
  507. Eigen_initFromSymmetricMatrix (eigen.get(), my z.get());
  508. autoMatrix eigenvectors = Data_copy (me);
  509. autoMatrix eigenvalues = Matrix_create (1.0, 1.0, 1, 1.0, 1.0, my ymin, my ymax, my ny, my dy, my y1);
  510. for (integer i = 1; i <= my nx; i ++) {
  511. eigenvalues -> z [i] [1] = eigen -> eigenvalues [i];
  512. for (integer j = 1; j <= my nx; j ++)
  513. eigenvectors -> z [i] [j] = eigen -> eigenvectors [j] [i];
  514. }
  515. *out_eigenvectors = eigenvectors.move();
  516. *out_eigenvalues = eigenvalues.move();
  517. } catch (MelderError) {
  518. Melder_throw (me, U": eigenstructure not computed.");
  519. }
  520. }
  521. autoMatrix Matrix_power (Matrix me, integer power) {
  522. try {
  523. if (my nx != my ny)
  524. Melder_throw (U"Matrix not square.");
  525. autoMatrix thee = Data_copy (me);
  526. autoMatrix him = Data_copy (me);
  527. for (integer ipow = 2; ipow <= power; ipow ++) {
  528. std::swap (his z, thy z);
  529. for (integer irow = 1; irow <= my ny; irow ++) {
  530. for (integer icol = 1; icol <= my nx; icol ++) {
  531. thy z [irow] [icol] = 0.0;
  532. for (integer i = 1; i <= my nx; i ++)
  533. thy z [irow] [icol] += his z [irow] [i] * my z [i] [icol];
  534. }
  535. }
  536. }
  537. return thee;
  538. } catch (MelderError) {
  539. Melder_throw (me, U": power not computed.");
  540. }
  541. }
  542. void Matrix_writeToMatrixTextFile (Matrix me, MelderFile file) {
  543. try {
  544. autofile f = Melder_fopen (file, "w");
  545. fprintf (f, "\"ooTextFile\"\n\"Matrix\"\n%s %s %s %s %s\n%s %s %s %s %s\n",
  546. Melder8_double (my xmin), Melder8_double (my xmax), Melder8_integer (my nx),
  547. Melder8_double (my dx), Melder8_double (my x1),
  548. Melder8_double (my ymin), Melder8_double (my ymax), Melder8_integer (my ny),
  549. Melder8_double (my dy), Melder8_double (my y1));
  550. for (integer i = 1; i <= my ny; i ++) {
  551. for (integer j = 1; j <= my nx; j ++) {
  552. if (j > 1)
  553. fprintf (f, " ");
  554. fprintf (f, "%s", Melder8_double (my z [i] [j]));
  555. }
  556. fprintf (f, "\n");
  557. }
  558. f.close (file);
  559. } catch (MelderError) {
  560. Melder_throw (me, U": not written to Matrix text file.");
  561. }
  562. }
  563. void Matrix_writeToHeaderlessSpreadsheetFile (Matrix me, MelderFile file) {
  564. try {
  565. autofile f = Melder_fopen (file, "w");
  566. for (integer i = 1; i <= my ny; i ++) {
  567. for (integer j = 1; j <= my nx; j ++) {
  568. if (j > 1)
  569. fprintf (f, "\t");
  570. fprintf (f, "%s", Melder8_single (my z [i] [j]));
  571. }
  572. fprintf (f, "\n");
  573. }
  574. f.close (file);
  575. } catch (MelderError) {
  576. Melder_throw (me, U": not saved as tab-separated file ", file);
  577. }
  578. }
  579. void Matrix_formula (Matrix me, conststring32 expression, Interpreter interpreter, Matrix target) {
  580. try {
  581. Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
  582. Formula_Result result;
  583. if (! target)
  584. target = me;
  585. for (integer irow = 1; irow <= my ny; irow ++) {
  586. for (integer icol = 1; icol <= my nx; icol ++) {
  587. Formula_run (irow, icol, & result);
  588. target -> z [irow] [icol] = result. numericResult;
  589. }
  590. }
  591. } catch (MelderError) {
  592. Melder_throw (me, U": formula not completed.");
  593. }
  594. }
  595. void Matrix_formula_part (Matrix me, double xmin, double xmax, double ymin, double ymax,
  596. conststring32 expression, Interpreter interpreter, Matrix target)
  597. {
  598. try {
  599. if (xmax <= xmin) {
  600. xmin = my xmin;
  601. xmax = my xmax;
  602. }
  603. if (ymax <= ymin) {
  604. ymin = my ymin;
  605. ymax = my ymax;
  606. }
  607. integer ixmin, ixmax, iymin, iymax;
  608. (void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
  609. (void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
  610. Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
  611. Formula_Result result;
  612. if (! target)
  613. target = me;
  614. for (integer irow = iymin; irow <= iymax; irow ++) {
  615. for (integer icol = ixmin; icol <= ixmax; icol ++) {
  616. Formula_run (irow, icol, & result);
  617. target -> z [irow] [icol] = result. numericResult;
  618. }
  619. }
  620. } catch (MelderError) {
  621. Melder_throw (me, U": formula not completed.");
  622. }
  623. }
  624. void Matrix_scaleAbsoluteExtremum (Matrix me, double scale) {
  625. double extremum = 0.0;
  626. for (integer i = 1; i <= my ny; i ++) {
  627. for (integer j = 1; j <= my nx; j ++) {
  628. if (fabs (my z [i] [j]) > extremum) {
  629. extremum = fabs (my z [i] [j]);
  630. }
  631. }
  632. }
  633. if (extremum != 0.0) {
  634. double factor = scale / extremum;
  635. for (integer i = 1; i <= my ny; i ++) {
  636. for (integer j = 1; j <= my nx; j ++) {
  637. my z [i] [j] *= factor;
  638. }
  639. }
  640. }
  641. }
  642. autoMatrix TableOfReal_to_Matrix (TableOfReal me) {
  643. try {
  644. autoMatrix thee = Matrix_createSimple (my numberOfRows, my numberOfColumns);
  645. for (integer i = 1; i <= my numberOfRows; i ++)
  646. for (integer j = 1; j <= my numberOfColumns; j ++)
  647. thy z [i] [j] = my data [i] [j];
  648. return thee;
  649. } catch (MelderError) {
  650. Melder_throw (me, U": not converted to Matrix.");
  651. }
  652. }
  653. autoTableOfReal Matrix_to_TableOfReal (Matrix me) {
  654. try {
  655. autoTableOfReal thee = TableOfReal_create (my ny, my nx);
  656. for (integer i = 1; i <= my ny; i ++)
  657. for (integer j = 1; j <= my nx; j ++)
  658. thy data [i] [j] = my z [i] [j];
  659. return thee;
  660. } catch (MelderError) {
  661. Melder_throw (me, U": not converted to TableOfReal.");
  662. }
  663. }
  664. autoMatrix Table_to_Matrix (Table me) {
  665. try {
  666. autoMatrix thee = Matrix_createSimple (my rows.size, my numberOfColumns);
  667. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  668. Table_numericize_Assert (me, icol);
  669. }
  670. for (integer irow = 1; irow <= my rows.size; irow ++) {
  671. TableRow row = my rows.at [irow];
  672. for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
  673. thy z [irow] [icol] = row -> cells [icol]. number;
  674. }
  675. }
  676. return thee;
  677. } catch (MelderError) {
  678. Melder_throw (me, U": not converted to Matrix.");
  679. }
  680. }
  681. /* End of file Matrix.cpp */