melder_tensor.h 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. #ifndef _melder_tensor_h_
  2. #define _melder_tensor_h_
  3. /* melder_tensor.h
  4. *
  5. * Copyright (C) 1992-2018 Paul Boersma
  6. *
  7. * This code is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * This code is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. * See the GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /********** Arrays with one index **********/
  21. byte * NUMvector_generic (integer elementSize, integer lo, integer hi, bool zero);
  22. /*
  23. Function:
  24. create a vector [lo...hi]; if `zero`, then all values are initialized to 0.
  25. Preconditions:
  26. hi >= lo;
  27. */
  28. void NUMvector_free_generic (integer elementSize, byte *v, integer lo) noexcept;
  29. /*
  30. Function:
  31. destroy a vector v that was created with NUMvector.
  32. Preconditions:
  33. lo must have the same values as with the creation of the vector.
  34. */
  35. byte * NUMvector_copy_generic (integer elementSize, const byte *v, integer lo, integer hi);
  36. /*
  37. Function:
  38. copy (part of) a vector v, which need not have been created with NUMvector, to a new one.
  39. Preconditions:
  40. if v != nullptr, the values v [lo..hi] must exist.
  41. */
  42. void NUMvector_copyElements_generic (integer elementSize, const byte *v, byte *to, integer lo, integer hi);
  43. /*
  44. copy the vector elements v [lo..hi] to those of a vector 'to'.
  45. These vectors need not have been created by NUMvector.
  46. */
  47. bool NUMvector_equal_generic (integer elementSize, const byte *v1, const byte *v2, integer lo, integer hi);
  48. /*
  49. return true if the vector elements v1 [lo..hi] are equal
  50. to the corresponding elements of the vector v2; otherwise, return false.
  51. The vectors need not have been created by NUMvector.
  52. */
  53. void NUMvector_append_generic (integer elementSize, byte **v, integer lo, integer *hi);
  54. void NUMvector_insert_generic (integer elementSize, byte **v, integer lo, integer *hi, integer position);
  55. /*
  56. add one element to the vector *v.
  57. The new element is initialized to zero.
  58. On success, *v points to the new vector, and *hi is incremented by 1.
  59. On failure, *v and *hi are not changed.
  60. */
  61. /********** Arrays with two indices **********/
  62. void * NUMmatrix_generic (integer elementSize, integer row1, integer row2, integer col1, integer col2, bool zero);
  63. /*
  64. Function:
  65. create a matrix [row1...row2] [col1...col2]; if `zero`, then all values are initialized to 0.
  66. Preconditions:
  67. row2 >= row1;
  68. col2 >= col1;
  69. */
  70. void NUMmatrix_free_generic (integer elementSize, byte **m, integer row1, integer col1) noexcept;
  71. /*
  72. Function:
  73. destroy a matrix m created with NUM...matrix.
  74. Preconditions:
  75. if m != nullptr: row1 and col1
  76. must have the same value as with the creation of the matrix.
  77. */
  78. void * NUMmatrix_copy_generic (integer elementSize, void *m, integer row1, integer row2, integer col1, integer col2);
  79. /*
  80. Function:
  81. copy (part of) a matrix m, wich does not have to be created with NUMmatrix, to a new one.
  82. Preconditions:
  83. if m != nullptr: the values m [rowmin..rowmax] [colmin..colmax] must exist.
  84. */
  85. void NUMmatrix_copyElements_generic (integer elementSize, char **mfrom, char **mto, integer row1, integer row2, integer col1, integer col2);
  86. /*
  87. copy the matrix elements m [r1..r2] [c1..c2] to those of a matrix 'to'.
  88. These matrices need not have been created by NUMmatrix.
  89. */
  90. bool NUMmatrix_equal_generic (integer elementSize, void *m1, void *m2, integer row1, integer row2, integer col1, integer col2);
  91. /*
  92. return 1 if the matrix elements m1 [r1..r2] [c1..c2] are equal
  93. to the corresponding elements of the matrix m2; otherwise, return 0.
  94. The matrices need not have been created by NUM...matrix.
  95. */
  96. byte *** NUMtensor3_generic (integer elementSize, integer pla1, integer pla2, integer row1, integer row2, integer col1, integer col2, bool initializeToZero);
  97. void NUMtensor3_free_generic (integer elementSize, byte ***t, integer pla1, integer row1, integer col1) noexcept;
  98. integer NUM_getTotalNumberOfArrays (); // for debugging
  99. template <class T>
  100. T* NUMvector (integer from, integer to) {
  101. T* result = reinterpret_cast <T*> (NUMvector_generic (sizeof (T), from, to, true));
  102. return result;
  103. }
  104. template <class T>
  105. T* NUMvector (integer from, integer to, bool initializeToZero) {
  106. T* result = reinterpret_cast <T*> (NUMvector_generic (sizeof (T), from, to, initializeToZero));
  107. return result;
  108. }
  109. template <class T>
  110. void NUMvector_free (T* ptr, integer from) noexcept {
  111. NUMvector_free_generic (sizeof (T), reinterpret_cast <byte *> (ptr), from);
  112. }
  113. template <class T>
  114. T* NUMvector_copy (const T* ptr, integer lo, integer hi) {
  115. T* result = reinterpret_cast <T*> (NUMvector_copy_generic (sizeof (T), reinterpret_cast <const byte *> (ptr), lo, hi));
  116. return result;
  117. }
  118. template <class T>
  119. bool NUMvector_equal (const T* v1, const T* v2, integer lo, integer hi) {
  120. return NUMvector_equal_generic (sizeof (T), reinterpret_cast <const byte *> (v1), reinterpret_cast <const byte *> (v2), lo, hi);
  121. }
  122. template <class T>
  123. void NUMvector_copyElements (const T* vfrom, T* vto, integer lo, integer hi) {
  124. NUMvector_copyElements_generic (sizeof (T), reinterpret_cast <const byte *> (vfrom), reinterpret_cast <byte *> (vto), lo, hi);
  125. }
  126. template <class T>
  127. void NUMvector_append (T** v, integer lo, integer *hi) {
  128. NUMvector_append_generic (sizeof (T), reinterpret_cast <byte **> (v), lo, hi);
  129. }
  130. template <class T>
  131. void NUMvector_insert (T** v, integer lo, integer *hi, integer position) {
  132. NUMvector_insert_generic (sizeof (T), reinterpret_cast <byte **> (v), lo, hi, position);
  133. }
  134. template <class T>
  135. class autoNUMvector {
  136. T* d_ptr;
  137. integer d_from;
  138. public:
  139. autoNUMvector<T> (integer from, integer to) : d_from (from) {
  140. d_ptr = NUMvector<T> (from, to, true);
  141. }
  142. autoNUMvector<T> (integer from, integer to, bool zero) : d_from (from) {
  143. d_ptr = NUMvector<T> (from, to, zero);
  144. }
  145. autoNUMvector (T *ptr, integer from) : d_ptr (ptr), d_from (from) {
  146. }
  147. autoNUMvector () : d_ptr (nullptr), d_from (1) {
  148. }
  149. ~autoNUMvector<T> () {
  150. if (d_ptr) NUMvector_free (d_ptr, d_from);
  151. }
  152. T& operator[] (integer i) {
  153. return d_ptr [i];
  154. }
  155. T* peek () const {
  156. return d_ptr;
  157. }
  158. T* transfer () {
  159. T* temp = d_ptr;
  160. d_ptr = nullptr; // make the pointer non-automatic again
  161. return temp;
  162. }
  163. void reset (integer from, integer to) {
  164. if (d_ptr) {
  165. NUMvector_free (d_ptr, d_from);
  166. d_ptr = nullptr;
  167. }
  168. d_from = from;
  169. d_ptr = NUMvector<T> (from, to, true);
  170. }
  171. void reset (integer from, integer to, bool zero) {
  172. if (d_ptr) {
  173. NUMvector_free (d_ptr, d_from);
  174. d_ptr = nullptr;
  175. }
  176. d_from = from;
  177. d_ptr = NUMvector<T> (from, to, zero);
  178. }
  179. };
  180. template <class T>
  181. T** NUMmatrix (integer row1, integer row2, integer col1, integer col2) {
  182. T** result = static_cast <T**> (NUMmatrix_generic (sizeof (T), row1, row2, col1, col2, true));
  183. return result;
  184. }
  185. template <class T>
  186. T** NUMmatrix (integer row1, integer row2, integer col1, integer col2, bool zero) {
  187. T** result = static_cast <T**> (NUMmatrix_generic (sizeof (T), row1, row2, col1, col2, zero));
  188. return result;
  189. }
  190. template <class T>
  191. void NUMmatrix_free (T** ptr, integer row1, integer col1) noexcept {
  192. NUMmatrix_free_generic (sizeof (T), reinterpret_cast <byte **> (ptr), row1, col1);
  193. }
  194. template <class T>
  195. T** NUMmatrix_copy (T** ptr, integer row1, integer row2, integer col1, integer col2) {
  196. #if 1
  197. T** result = static_cast <T**> (NUMmatrix_copy_generic (sizeof (T), ptr, row1, row2, col1, col2));
  198. #else
  199. T** result = static_cast <T**> (NUMmatrix_generic (sizeof (T), row1, row2, col1, col2));
  200. for (integer irow = row1; irow <= row2; irow ++)
  201. for (integer icol = col1; icol <= col2; icol ++)
  202. result [irow] [icol] = ptr [irow] [icol];
  203. #endif
  204. return result;
  205. }
  206. template <class T>
  207. bool NUMmatrix_equal (T** m1, T** m2, integer row1, integer row2, integer col1, integer col2) {
  208. return NUMmatrix_equal_generic (sizeof (T), m1, m2, row1, row2, col1, col2);
  209. }
  210. template <class T>
  211. void NUMmatrix_copyElements (T** mfrom, T** mto, integer row1, integer row2, integer col1, integer col2) {
  212. NUMmatrix_copyElements_generic (sizeof (T), reinterpret_cast <char **> (mfrom), reinterpret_cast <char **> (mto), row1, row2, col1, col2);
  213. }
  214. template <class T>
  215. class autoNUMmatrix {
  216. T** d_ptr;
  217. integer d_row1, d_col1;
  218. public:
  219. autoNUMmatrix (integer row1, integer row2, integer col1, integer col2) : d_row1 (row1), d_col1 (col1) {
  220. d_ptr = NUMmatrix<T> (row1, row2, col1, col2, true);
  221. }
  222. autoNUMmatrix (integer row1, integer row2, integer col1, integer col2, bool zero) : d_row1 (row1), d_col1 (col1) {
  223. d_ptr = NUMmatrix<T> (row1, row2, col1, col2, zero);
  224. }
  225. autoNUMmatrix (T **ptr, integer row1, integer col1) : d_ptr (ptr), d_row1 (row1), d_col1 (col1) {
  226. }
  227. autoNUMmatrix () : d_ptr (nullptr), d_row1 (0), d_col1 (0) {
  228. }
  229. ~autoNUMmatrix () {
  230. if (d_ptr)
  231. NUMmatrix_free_generic (sizeof (T), reinterpret_cast <byte **> (d_ptr), d_row1, d_col1);
  232. }
  233. T*& operator[] (integer row) {
  234. return d_ptr [row];
  235. }
  236. T** peek () const {
  237. return d_ptr;
  238. }
  239. T** transfer () {
  240. T** temp = d_ptr;
  241. d_ptr = nullptr;
  242. return temp;
  243. }
  244. void reset (integer row1, integer row2, integer col1, integer col2) {
  245. if (d_ptr) {
  246. NUMmatrix_free_generic (sizeof (T), reinterpret_cast <byte **> (d_ptr), d_row1, d_col1);
  247. d_ptr = nullptr;
  248. }
  249. d_row1 = row1;
  250. d_col1 = col1;
  251. d_ptr = NUMmatrix<T> (row1, row2, col1, col2, true);
  252. }
  253. void reset (integer row1, integer row2, integer col1, integer col2, bool zero) {
  254. if (d_ptr) {
  255. NUMmatrix_free_generic (sizeof (T), reinterpret_cast <byte **> (d_ptr), d_row1, d_col1);
  256. d_ptr = nullptr;
  257. }
  258. d_row1 = row1;
  259. d_col1 = col1;
  260. d_ptr = NUMmatrix<T> (row1, row2, col1, col2, zero);
  261. }
  262. };
  263. #pragma mark - TENSOR
  264. /*
  265. Base-1 tensors, for parallellism with the scripting language.
  266. Initialization (tested in praat.cpp):
  267. VEC x; // initializes x.at to nullptr and x.size to 0
  268. VEC x1 (100); // initializes x to 100 uninitialized values
  269. VEC x2 (100, 0.0); // initializes x to 100 zeroes
  270. NUMvector<double> a (1, 100);
  271. VEC x3 { a, 100 }; // initializes x to 100 values from a base-1 array
  272. autoVEC y; // initializes y.at to nullptr and y.size to 0
  273. autoVEC y1 (100); // initializes y to 100 uninitialized values, having ownership
  274. autoVEC y2 (100, 0.0); // initializes y to 100 zeroes, having ownership
  275. y.adoptFromAmbiguousOwner (x); // initializes y to the content of x, taking ownership (explicit, so not "y = x")
  276. VEC z = y.releaseToAmbiguousOwner(); // releases ownership, y.at becoming nullptr
  277. "}" // end of scope destroys y.at if not nullptr
  278. autoVEC z1 = y2.move() // moves the content of y2 to z1, emptying y2
  279. To return an autoVEC from a function, transfer ownership like this:
  280. autoVEC foo () {
  281. autoVEC x (100);
  282. ... // fill in the 100 values
  283. return x;
  284. }
  285. */
  286. enum class kTensorInitializationType { RAW = 0, ZERO = 1 };
  287. template <typename T>
  288. class autovector; // forward declaration, needed in the declaration of vector<>
  289. template <typename T>
  290. class vector {
  291. public:
  292. T *at = nullptr;
  293. integer size = 0;
  294. public:
  295. vector () = default;
  296. vector (T *givenAt, integer givenSize): at (givenAt), size (givenSize) { }
  297. vector (const vector& other) = default;
  298. /*
  299. Letting an autovector convert to a vector would lead to errors such as in
  300. VEC vec = VECzero (10);
  301. where VECzero produces a temporary that is deleted immediately
  302. after the initialization of vec.
  303. So we rule out this initialization.
  304. */
  305. vector (const autovector<T>& other) = delete;
  306. /*
  307. Likewise, an assignment like
  308. VEC vec1, vec2;
  309. vec1 = vec2;
  310. should be allowed...
  311. */
  312. vector& operator= (const vector&) = default;
  313. /*
  314. but an assignment like
  315. autoVEC x = VECzero (10);
  316. VEC y;
  317. y = x;
  318. should be ruled out. Instead, one should do
  319. y = x.get();
  320. explicitly.
  321. */
  322. vector& operator= (const autovector<T>&) = delete;
  323. T& operator[] (integer i) const {
  324. return our at [i];
  325. }
  326. vector<T> subview (integer first, integer last) const {
  327. const integer offset = first - 1;
  328. Melder_assert (offset >= 0 && offset < our size);
  329. const integer newSize = last - offset;
  330. if (newSize <= 0) return vector<T> (nullptr, 0);
  331. return vector<T> (& our at [offset], newSize);
  332. }
  333. T *begin () const { return & our at [1]; }
  334. T *end () const { return & our at [our size + 1]; }
  335. };
  336. template <typename T>
  337. class constvector {
  338. public:
  339. const T *at = nullptr;
  340. integer size = 0;
  341. constvector () = default;
  342. constvector (const T *givenAt, integer givenSize): at (givenAt), size (givenSize) { }
  343. constvector (vector<T> vec): at (vec.at), size (vec.size) { }
  344. //constvector (const constvector& other): at (other.at), size (other.size) { }
  345. //constvector& operator= (const constvector& other) {
  346. // our at = other.at;
  347. // our size = other.size;
  348. //}
  349. const T& operator[] (integer i) const { // it's still a reference, because we need to be able to take its address
  350. return our at [i];
  351. }
  352. constvector<T> subview (integer first, integer last) const {
  353. const integer offset = first - 1;
  354. Melder_assert (offset >= 0 && offset < our size);
  355. const integer newSize = last - offset;
  356. if (newSize <= 0) return constvector<T> (nullptr, 0);
  357. return constvector<T> (& our at [offset], newSize);
  358. }
  359. const T *begin () const { return & our at [1]; }
  360. const T *end () const { return & our at [our size + 1]; }
  361. };
  362. /*
  363. An autovector is the sole owner of its payload, which is a vector.
  364. When the autovector ends its life (goes out of scope),
  365. it should destroy its payload (if it has not sold it),
  366. because keeping a payload alive when the owner is dead
  367. would continue to use some of the computer's resources (namely, memory).
  368. */
  369. template <typename T>
  370. class autovector : public vector<T> {
  371. integer capacity = 0;
  372. public:
  373. autovector (): vector<T> (nullptr, 0) { } // come into existence without a payload
  374. autovector (integer givenSize, kTensorInitializationType initializationType) { // come into existence and manufacture a payload
  375. Melder_assert (givenSize >= 0);
  376. our at = ( givenSize == 0 ? nullptr
  377. : NUMvector<T> (1, givenSize, initializationType == kTensorInitializationType::ZERO) );
  378. our size = givenSize;
  379. our capacity = givenSize;
  380. }
  381. ~autovector () { // destroy the payload (if any)
  382. our reset ();
  383. our capacity = 0;
  384. }
  385. vector<T> get () const { return { our at, our size }; } // let the public use the payload (they may change the values of the elements but not the at-pointer or the size)
  386. void adoptFromAmbiguousOwner (vector<T> given) { // buy the payload from a non-autovector
  387. our reset();
  388. our at = given.at;
  389. our size = given.size;
  390. our capacity = given.size;
  391. }
  392. vector<T> releaseToAmbiguousOwner () { // sell the payload to a non-autovector
  393. T *oldAt = our at;
  394. our at = nullptr; // disown ourselves, preventing automatic destruction of the payload
  395. integer oldSize = our size;
  396. our capacity = 0;
  397. return { oldAt, oldSize };
  398. }
  399. /*
  400. Disable copying via construction or assignment (which would violate unique ownership of the payload).
  401. */
  402. autovector (const autovector&) = delete; // disable copy constructor
  403. autovector& operator= (const autovector&) = delete; // disable copy assignment
  404. /*
  405. Enable moving of r-values (temporaries, implicitly) or l-values (for variables, via an explicit move()).
  406. This implements buying a payload from another autovector (which involves destroying our current payload).
  407. */
  408. autovector (autovector&& other) noexcept : vector<T> { other.get() } { // enable move constructor
  409. other.at = nullptr; // disown source
  410. other.size = 0; // to keep the source in a valid state
  411. other.capacity = 0;
  412. }
  413. autovector& operator= (autovector&& other) noexcept { // enable move assignment
  414. if (other.at != our at) {
  415. our reset ();
  416. our at = other.at;
  417. our size = other.size;
  418. our capacity = other.capacity;
  419. other.at = nullptr; // disown source
  420. other.size = 0; // to keep the source in a valid state
  421. other.capacity = 0;
  422. }
  423. return *this;
  424. }
  425. void reset () noexcept { // on behalf of ambiguous owners (otherwise this could be in autovector<>)
  426. if (our at) {
  427. NUMvector_free (our at, 1);
  428. our at = nullptr;
  429. }
  430. our size = 0;
  431. }
  432. autovector&& move () noexcept { return static_cast <autovector&&> (*this); } // enable constriction and assignment for l-values (variables) via explicit move()
  433. /*
  434. Unlike std::vector, our vector is not really designed for dynamic resizing,
  435. i.e. it has no `capacity` member. This is because our vectors should mainly feel happy
  436. in an environment with matrixes, tensor3s and tensor4s, for which dynamic resizing
  437. makes little sense.
  438. The following functions, however, do support dynamic resizing,
  439. but the capacity should be kept in an external integer.
  440. Some of these functions are capable of keeping a valid `at` pointer
  441. while `size` can at the same time be zero.
  442. */
  443. void initWithCapacity (integer *inout_capacity, kTensorInitializationType initializationType = kTensorInitializationType::ZERO) {
  444. if (*inout_capacity > 0)
  445. our at = NUMvector<T> (1, *inout_capacity, initializationType == kTensorInitializationType::ZERO);
  446. our size = 0;
  447. our capacity = *inout_capacity;
  448. }
  449. /*
  450. If the new size N is less than the current size S,
  451. then the first N elements of the vector are kept,
  452. so if you want to keep a different range than the
  453. first N elements of your original vector,
  454. you should shift the elements before resizing.
  455. If the new size N is greater than the current size S,
  456. then all S elements of the vector are kept,
  457. and they are the first S elements of the new vector
  458. the remaining S - N elements may be initialized to zero.
  459. If you want the original S elements to show up
  460. elsewhere than at the head of the vector,
  461. you should shift the elements after resizing.
  462. */
  463. void resize (integer newSize, integer *inout_capacity = nullptr,
  464. kTensorInitializationType initializationType = kTensorInitializationType::ZERO)
  465. {
  466. const integer currentCapacity = ( inout_capacity ? *inout_capacity : our size );
  467. if (newSize > currentCapacity) {
  468. /*
  469. The new capacity is at least twice the old capacity.
  470. When starting at a capacity of 0, and continually upsizing by one,
  471. the capacity sequence will be: 0, 11, 33, 77, 165, 341, 693, 1397,
  472. 2805, 5621, 11253, 22517, 45045, 90101, 180213, 360437, 720885...
  473. */
  474. integer newCapacity = ( inout_capacity ? newSize + our size + 10 : newSize );
  475. /*
  476. Create without change.
  477. */
  478. T *newAt = NUMvector<T> (1, newCapacity, initializationType == kTensorInitializationType::ZERO);
  479. /*
  480. Change without error.
  481. */
  482. for (integer i = 1; i <= our size; i ++)
  483. newAt [i] = our at [i];
  484. if (our at) NUMvector_free (our at, 1);
  485. our at = newAt;
  486. if (inout_capacity)
  487. *inout_capacity = newCapacity;
  488. our capacity = newCapacity;
  489. }
  490. our size = newSize;
  491. }
  492. void insert (integer position, const T& value, integer *inout_capacity = nullptr) {
  493. resize (our size + 1, inout_capacity, kTensorInitializationType::RAW);
  494. Melder_assert (position >= 1 && position <= our size);
  495. for (integer i = our size; i > position; i --)
  496. our at [i] = our at [i - 1];
  497. our at [position] = value;
  498. }
  499. void remove (integer position) {
  500. Melder_assert (position >= 1 && position <= our size);
  501. for (integer i = position; i < our size; i ++)
  502. our at [i] = our at [i + 1];
  503. resize (our size - 1);
  504. }
  505. };
  506. template <typename T>
  507. autovector<T> vectorraw (integer size) {
  508. return autovector<T> (size, kTensorInitializationType::RAW);
  509. }
  510. template <typename T>
  511. autovector<T> vectorzero (integer size) {
  512. return autovector<T> (size, kTensorInitializationType::ZERO);
  513. }
  514. template <typename T>
  515. void vectorcopy_preallocated (vector<T> target, constvector<T> source) {
  516. Melder_assert (source.size == target.size);
  517. for (integer i = 1; i <= source.size; i ++)
  518. target [i] = source [i];
  519. }
  520. template <typename T>
  521. void vectorcopy_preallocated (vector<T> target, vector<T> source) {
  522. vectorcopy_preallocated (target, constvector<T> (source));
  523. }
  524. template <typename T>
  525. autovector<T> vectorcopy (constvector<T> source) {
  526. autovector<T> result = vectorraw<T> (source.size);
  527. vectorcopy_preallocated (result.get(), source);
  528. return result;
  529. }
  530. template <typename T>
  531. autovector<T> vectorcopy (vector<T> source) {
  532. return vectorcopy (constvector<T> (source));
  533. }
  534. template <typename T>
  535. class automatrix; // forward declaration, needed in the declaration of matrix
  536. #define PACKED_TENSORS 0
  537. template <typename T>
  538. class matrix {
  539. public:
  540. #if PACKED_TENSORS
  541. T *cells = nullptr;
  542. #else
  543. T **at = nullptr;
  544. #endif
  545. integer nrow = 0, ncol = 0;
  546. public:
  547. matrix () = default;
  548. #if PACKED_TENSORS
  549. matrix (T *givenCells, integer givenNrow, integer givenNcol): cells (givenCells), nrow (givenNrow), ncol (givenNcol) { }
  550. #else
  551. matrix (T **givenAt, integer givenNrow, integer givenNcol): at (givenAt), nrow (givenNrow), ncol (givenNcol) { }
  552. #endif
  553. matrix (const matrix& other) = default;
  554. matrix (const automatrix<T>& other) = delete;
  555. matrix& operator= (const matrix&) = default;
  556. matrix& operator= (const automatrix<T>&) = delete;
  557. #if PACKED_TENSORS
  558. vector<T> operator[] (integer i) const {
  559. return vector (our cells + (i - 1) * our ncol, our ncol);
  560. }
  561. #else
  562. T * const & operator[] (integer i) const {
  563. return our at [i];
  564. }
  565. #endif
  566. vector<T> row (integer rowNumber) const {
  567. Melder_assert (rowNumber >= 1 && rowNumber <= our nrow);
  568. #if PACKED_TENSORS
  569. return vector (our cells + (rowNumber - 1) * our ncol, our ncol);
  570. #else
  571. return vector<T> (our at [rowNumber], our ncol);
  572. #endif
  573. }
  574. matrix<T> horizontalBand (integer firstRow, integer lastRow) const {
  575. const integer offsetRow = firstRow - 1;
  576. Melder_assert (offsetRow >= 0 && offsetRow <= our nrow);
  577. Melder_assert (lastRow >= 0 && lastRow <= our nrow);
  578. const integer newNrow = lastRow - offsetRow;
  579. if (newNrow <= 0) return matrix<T> ();
  580. return matrix<T> (& our at [offsetRow], newNrow, our ncol);
  581. }
  582. };
  583. template <typename T>
  584. class constmatrix {
  585. public:
  586. #if PACKED_TENSORS
  587. const T *cells = nullptr;
  588. #else
  589. const T * const * at = nullptr;
  590. #endif
  591. integer nrow = 0, ncol = 0;
  592. constmatrix () = default;
  593. #if PACKED_TENSORS
  594. constmatrix (const T *givenCells, integer givenNrow, integer givenNcol): cells (givenCells), nrow (givenNrow), ncol (givenNcol) { }
  595. #else
  596. constmatrix (const T * const *givenAt, integer givenNrow, integer givenNcol): at (givenAt), nrow (givenNrow), ncol (givenNcol) { }
  597. #endif
  598. #if PACKED_TENSORS
  599. constmatrix (matrix<T> mat): cells (mat.cells), nrow (mat.nrow), ncol (mat.ncol) { }
  600. #else
  601. constmatrix (matrix<T> mat): at (mat.at), nrow (mat.nrow), ncol (mat.ncol) { }
  602. #endif
  603. #if PACKED_TENSORS
  604. const T * operator[] (integer i) const {
  605. return our cells + (i - 1) * our ncol;
  606. }
  607. #else
  608. const T * const & operator[] (integer i) const {
  609. return our at [i];
  610. }
  611. #endif
  612. constvector<T> row (integer rowNumber) const {
  613. Melder_assert (rowNumber >= 1 && rowNumber <= our nrow);
  614. return constvector<T> (our at [rowNumber], our ncol);
  615. }
  616. constmatrix<T> horizontalBand (integer firstRow, integer lastRow) const {
  617. const integer offsetRow = firstRow - 1;
  618. Melder_assert (offsetRow >= 0 && offsetRow <= our nrow);
  619. Melder_assert (lastRow >= 0 && lastRow <= our nrow);
  620. const integer newNrow = lastRow - offsetRow;
  621. if (newNrow <= 0) return matrix<T> (nullptr, 0, 0);
  622. return constmatrix<T> (& our at [offsetRow], newNrow, our ncol);
  623. }
  624. };
  625. /*
  626. An automatrix is the sole owner of its payload, which is a matrix.
  627. When the automatrix ends its life (goes out of scope),
  628. it should destroy its payload (if it has not sold it),
  629. because keeping a payload alive when the owner is dead
  630. would continue to use some of the computer's resources (namely, memory).
  631. */
  632. template <typename T>
  633. class automatrix : public matrix<T> {
  634. public:
  635. automatrix (): matrix<T> { nullptr, 0, 0 } { } // come into existence without a payload
  636. automatrix (integer givenNrow, integer givenNcol, kTensorInitializationType initializationType) { // come into existence and manufacture a payload
  637. Melder_assert (givenNrow >= 0);
  638. Melder_assert (givenNcol >= 0);
  639. #if PACKED_TENSORS
  640. our cells = ( givenNrow == 0 || givenNcol == 0 ? nullptr
  641. : NUMvector<T> (1, givenNrow * givenNcol, initializationType == kTensorInitializationType::ZERO));
  642. #else
  643. our at = ( givenNrow == 0 || givenNcol == 0 ? nullptr
  644. : NUMmatrix<T> (1, givenNrow, 1, givenNcol, initializationType == kTensorInitializationType::ZERO));
  645. #endif
  646. our nrow = givenNrow;
  647. our ncol = givenNcol;
  648. }
  649. ~automatrix () { // destroy the payload (if any)
  650. #if PACKED_TENSORS
  651. if (our cells) NUMvector_free (our cells, 1);
  652. #else
  653. if (our at) NUMmatrix_free (our at, 1, 1);
  654. #endif
  655. }
  656. //matrix<T> get () { return { our at, our nrow, our ncol }; } // let the public use the payload (they may change the values in the cells but not the at-pointer, nrow or ncol)
  657. const matrix<T>& get () { return *this; } // let the public use the payload (they may change the values in the cells but not the at-pointer, nrow or ncol)
  658. void adoptFromAmbiguousOwner (matrix<T> given) { // buy the payload from a non-automatrix
  659. our reset();
  660. #if PACKED_TENSORS
  661. our cells = given.cells;
  662. #else
  663. our at = given.at;
  664. #endif
  665. our nrow = given.nrow;
  666. our ncol = given.ncol;
  667. }
  668. matrix<T> releaseToAmbiguousOwner () { // sell the payload to a non-automatrix
  669. T **oldAt = our at;
  670. our at = nullptr; // disown ourselves, preventing automatic destruction of the payload
  671. return { oldAt, our nrow, our ncol };
  672. }
  673. /*
  674. Disable copying via construction or assignment (which would violate unique ownership of the payload).
  675. */
  676. automatrix (const automatrix&) = delete; // disable copy constructor
  677. automatrix& operator= (const automatrix&) = delete; // disable copy assignment
  678. /*
  679. Enable moving of r-values (temporaries, implicitly) or l-values (for variables, via an explicit move()).
  680. This implements buying a payload from another automatrix (which involves destroying our current payload).
  681. */
  682. automatrix (automatrix&& other) noexcept : matrix<T> { other.get() } { // enable move constructor
  683. #if PACKED_TENSORS
  684. other.cells = nullptr; // disown source
  685. #else
  686. other.at = nullptr; // disown source
  687. #endif
  688. other.nrow = 0; // to keep the source in a valid state
  689. other.ncol = 0; // to keep the source in a valid state
  690. }
  691. automatrix& operator= (automatrix&& other) noexcept { // enable move assignment
  692. #if PACKED_TENSORS
  693. if (other.cells != our cells) {
  694. if (our cells) NUMvector_free (our cells, 1);
  695. our cells = other.cells;
  696. our nrow = other.nrow;
  697. our ncol = other.ncol;
  698. other.cells = nullptr; // disown source
  699. other.nrow = 0; // to keep the source in a valid state
  700. other.ncol = 0; // to keep the source in a valid state
  701. }
  702. #else
  703. if (other.at != our at) {
  704. if (our at) NUMmatrix_free (our at, 1, 1);
  705. our at = other.at;
  706. our nrow = other.nrow;
  707. our ncol = other.ncol;
  708. other.at = nullptr; // disown source
  709. other.nrow = 0; // to keep the source in a valid state
  710. other.ncol = 0; // to keep the source in a valid state
  711. }
  712. #endif
  713. return *this;
  714. }
  715. void reset () noexcept { // on behalf of ambiguous owners (otherwise this could be in autoMAT)
  716. #if PACKED_TENSORS
  717. if (our cells) {
  718. NUMvector_free (our cells, 1);
  719. our cells = nullptr;
  720. }
  721. #else
  722. if (our at) {
  723. NUMmatrix_free (our at, 1, 1);
  724. our at = nullptr;
  725. }
  726. #endif
  727. our nrow = 0;
  728. our ncol = 0;
  729. }
  730. automatrix&& move () noexcept { return static_cast <automatrix&&> (*this); }
  731. };
  732. template <typename T>
  733. automatrix<T> matrixraw (integer nrow, integer ncol) {
  734. return automatrix<T> (nrow, ncol, kTensorInitializationType::RAW);
  735. }
  736. template <typename T>
  737. automatrix<T> matrixzero (integer nrow, integer ncol) {
  738. return automatrix<T> (nrow, ncol, kTensorInitializationType::ZERO);
  739. }
  740. template <typename T>
  741. vector<T> asvector (matrix<T> x) {
  742. #if PACKED_TENSORS
  743. return vector<T> (x.cells, x.nrow * x.ncol);
  744. #else
  745. return vector<T> (x [1], x.nrow * x.ncol);
  746. #endif
  747. }
  748. template <typename T>
  749. constvector<T> asvector (constmatrix<T> x) {
  750. return constvector<T> (x [1], x.nrow * x.ncol);
  751. }
  752. template <typename T>
  753. void matrixcopy_preallocated (matrix<T> target, constmatrix<T> source) {
  754. Melder_assert (source.nrow == target.nrow && source.ncol == target.ncol);
  755. for (integer irow = 1; irow <= source.nrow; irow ++)
  756. for (integer icol = 1; icol <= source.ncol; icol ++)
  757. target [irow] [icol] = source [irow] [icol];
  758. }
  759. template <typename T>
  760. void matrixcopy_preallocated (matrix<T> target, matrix<T> source) {
  761. matrixcopy_preallocated (target, constmatrix<T> (source));
  762. }
  763. template <typename T>
  764. automatrix<T> matrixcopy (constmatrix<T> source) {
  765. automatrix<T> result = matrixraw<T> (source.nrow, source.ncol);
  766. matrixcopy_preallocated (result.get(), source);
  767. return result;
  768. }
  769. template <typename T>
  770. automatrix<T> matrixcopy (matrix<T> source) {
  771. return matrixcopy (constmatrix<T> (source));
  772. }
  773. template <typename T>
  774. void assertCell (const constvector<T>& x, integer elementNumber) {
  775. Melder_assert (elementNumber >= 1 && elementNumber <= x.size);
  776. }
  777. template <typename T>
  778. void assertRow (const constmatrix<T>& x, integer rowNumber) {
  779. Melder_assert (rowNumber >= 1 && rowNumber <= x.nrow);
  780. }
  781. template <typename T>
  782. void assertColumn (const constmatrix<T>& x, integer columnNumber) {
  783. Melder_assert (columnNumber >= 1 && columnNumber <= x.nrow);
  784. }
  785. template <typename T>
  786. void assertCell (const constmatrix<T>& x, integer rowNumber, integer columnNumber) {
  787. assertRow (x, rowNumber);
  788. assertColumn (x, columnNumber);
  789. }
  790. template <typename T>
  791. automatrix<T> matrixpart (const constmatrix<T>& x, integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) {
  792. assertCell (x, firstRow, firstColumn);
  793. assertCell (x, lastRow, lastColumn);
  794. integer numberOfRows = lastRow - firstRow + 1;
  795. Melder_assert (numberOfRows >= 0);
  796. integer numberOfColumns = lastColumn - firstColumn + 1;
  797. Melder_assert (numberOfColumns >= 0);
  798. automatrix<T> result = matrixraw<T> (numberOfRows, numberOfColumns);
  799. for (integer irow = 1; irow <= numberOfRows; irow ++)
  800. for (integer icol = 1; icol <= numberOfColumns; icol ++)
  801. result [irow] [icol] = x [firstRow - 1 + irow] [firstColumn - 1 + icol];
  802. return result;
  803. }
  804. template <typename T>
  805. automatrix<T> matrixpart (const matrix<T>& x, integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) {
  806. matrixpart (constmatrix<T> (x), firstRow, lastRow, firstColumn, lastColumn);
  807. }
  808. /*
  809. instead of vector<double> we say VEC, because we want to have a one-to-one
  810. relation between VEC functions and the scripting language.
  811. For instance, we make VECraw and VECzero because Praat scripting has raw# and zero#.
  812. */
  813. using VEC = vector <double>;
  814. using constVEC = constvector <double>;
  815. using autoVEC = autovector <double>;
  816. inline autoVEC VECraw (integer size) { return vectorraw <double> (size); }
  817. inline autoVEC VECzero (integer size) { return vectorzero <double> (size); }
  818. inline void VECcopy_preallocated (VEC target, constVEC source) { vectorcopy_preallocated (target, source); }
  819. inline autoVEC VECcopy (constVEC source) { return vectorcopy (source); }
  820. /*
  821. And simply because we use vector<integer> so much as well,
  822. we have an abbreviation for that as well, namely INTVEC.
  823. But the scripting language has nothing that corresponds to INTVEC,
  824. so any numeric vector to be used by the scripting language
  825. should be a VEC, even if it contains integers.
  826. This is fine, as a double can contain an integer up to 54 bits.
  827. */
  828. using INTVEC = vector <integer>;
  829. using constINTVEC = constvector <integer>;
  830. using autoINTVEC = autovector <integer>;
  831. inline autoINTVEC INTVECraw (integer size) { return vectorraw <integer> (size); }
  832. inline autoINTVEC INTVECzero (integer size) { return vectorzero <integer> (size); }
  833. inline void INTVECcopy_preallocated (INTVEC target, constINTVEC source) { vectorcopy_preallocated (target, source); }
  834. inline autoINTVEC INTVECcopy (constINTVEC source) { return vectorcopy (source); }
  835. #define emptyVEC VEC (nullptr, 0)
  836. #define emptyINTVEC INTVEC (nullptr, 0)
  837. using MAT = matrix <double>;
  838. using constMAT = constmatrix <double>;
  839. using autoMAT = automatrix <double>;
  840. inline autoMAT MATraw (integer nrow, integer ncol) { return matrixraw <double> (nrow, ncol); }
  841. inline autoMAT MATzero (integer nrow, integer ncol) { return matrixzero <double> (nrow, ncol); }
  842. inline autoMAT MATcopy (constMAT source) { return matrixcopy (source); }
  843. inline autoMAT MATpart (const constMAT& source, integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) {
  844. return matrixpart (source, firstRow, lastRow, firstColumn, lastColumn);
  845. }
  846. using INTMAT = matrix <integer>;
  847. using constINTMAT = constmatrix <integer>;
  848. using autoINTMAT = automatrix <integer>;
  849. inline autoINTMAT INTMATraw (integer nrow, integer ncol) { return matrixraw <integer> (nrow, ncol); }
  850. inline autoINTMAT INTMATzero (integer nrow, integer ncol) { return matrixzero <integer> (nrow, ncol); }
  851. inline autoINTMAT INTMATcopy (constINTMAT source) { return matrixcopy (source); }
  852. #define emptyMAT MAT (nullptr, 0, 0)
  853. #define emptyINTMAT INTMAT (nullptr, 0, 0)
  854. conststring32 Melder_VEC (constVEC value);
  855. conststring32 Melder_MAT (constMAT value);
  856. /* End of file melder_tensor.h */
  857. #endif