1 #ifndef _melder_tensor_h_
2 #define _melder_tensor_h_
3 /* melder_tensor.h
4 *
5 * Copyright (C) 1992-2021 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
21 #pragma mark - TENSOR
22 /*
23 Base-1 tensors, for parallellism with the scripting language.
24
25 Initialization (tested in praat.cpp):
26 VEC x; // initializes x.cells to nullptr and x.size to 0
27 double a [] = { 3.14, 2.718 };
28 VEC x3 (a, 2); // initializes x3 to 100 values from a base-0 array
29 Melder_assert (x3 [2] == 2.718);
30 constVEC x4 = { 3.14, 2.718 };
31 Melder_assert (x4 [2] == 2.718);
32
33 autoVEC y; // initializes y.cells to nullptr and y.size to 0
34 autoVEC y2 = zero_VEC (100); // initializes y to 100 zeroes, having ownership
35 autoVEC y1 = raw_VEC (100); // initializes y to 100 uninitialized values (caution!), having ownership
36 y.adoptFromAmbiguousOwner (x); // initializes y to the content of x, taking ownership (explicit, so not "y = x")
37 VEC z = y.releaseToAmbiguousOwner(); // releases ownership, y.cells becoming nullptr
38 "}" // end of scope destroys y.cells if not nullptr
39 autoVEC z1 = y2.move() // moves the content of y2 to z1, emptying y2
40
41 To return an autoVEC from a function, transfer ownership like this:
42 autoVEC foo () {
43 autoVEC x = newVECero (100);
44 ... // fill in the 100 values
45 return x;
46 }
47 */
48
49 /*
50 Forward declarations, needed because of all the conversions and deletions.
51 */
52 template <typename T> class vector;
53 template <typename T> class constvector;
54 template <typename T> class vectorview;
55 template <typename T> class constvectorview;
56 template <typename T> class autovector;
57 template <typename T> class matrix;
58 template <typename T> class constmatrix;
59 template <typename T> class matrixview;
60 template <typename T> class constmatrixview;
61 template <typename T> class automatrix;
62
63 template <typename T>
64 struct vector {
65 T *cells = nullptr;
66 integer size = 0;
67 vector ()
68 = default;
vectorvector69 explicit vector (T *givenCells, integer givenSize)
70 : cells (givenCells), size (givenSize) { }
vectorvector71 explicit vector (matrix<T> const& mat)
72 : vector (mat.cells, mat.nrow * mat.ncol) { }
73 T& operator[] (integer i) const {
74 return our cells [i - 1];
75 }
76 /*
77 part (first, last) should crash under the exact
78 same conditions as a rising for-loop over the elements
79 from first to last (or a falling for-loop over
80 the elements from last to first) should crash.
81 */
partvector82 vector<T> part (integer first, integer last) const {
83 const integer newSize = last - (first - 1);
84 /*
85 for-loops don't crash if the number of elements is zero.
86 */
87 if (newSize <= 0)
88 return vector<T> ();
89 Melder_assert (first >= 1 && first <= our size);
90 Melder_assert (last >= 1 && last <= our size);
91 return vector<T> (& our cells [first - 1], newSize);
92 }
asmatrixvector93 matrix<T> asmatrix (integer nrow, integer ncol) {
94 Melder_assert (nrow * ncol <= our size);
95 return matrix (our cells, nrow, ncol);
96 }
beginvector97 T *begin () const { return our cells; }
endvector98 T *end () const { return our cells + our size; }
asArgumentToFunctionThatExpectsZeroBasedArrayvector99 T *asArgumentToFunctionThatExpectsZeroBasedArray () const { return our cells; }
asArgumentToFunctionThatExpectsOneBasedArrayvector100 T *asArgumentToFunctionThatExpectsOneBasedArray () const { return our cells - 1; }
101 };
102
103 template <typename T>
104 struct constvector {
105 const T *cells = nullptr;
106 integer size = 0;
107 constvector ()
108 = default;
constvectorconstvector109 explicit constvector (const T *givenCells, integer givenSize)
110 : cells (givenCells), size (givenSize) { }
constvectorconstvector111 explicit constvector (constmatrix<T> const& mat)
112 : constvector (mat.cells, mat.nrow * mat.ncol) { }
constvectorconstvector113 constvector (vector<T> const& other)
114 : constvector (other.cells, other.size) { }
115 const T& operator[] (integer i) const { // it's still a reference, because we need to be able to take its address
116 return our cells [i - 1];
117 }
partconstvector118 constvector<T> part (integer first, integer last) const {
119 const integer newSize = last - (first - 1);
120 if (newSize <= 0)
121 return constvector<T> ();
122 Melder_assert (first >= 1 && first <= our size);
123 Melder_assert (last >= 1 && last <= our size);
124 return constvector<T> (& our cells [first - 1], newSize);
125 }
asmatrixconstvector126 constmatrix<T> asmatrix (integer nrow, integer ncol) {
127 Melder_assert (nrow * ncol <= our size);
128 return constmatrix (our cells, nrow, ncol);
129 }
beginconstvector130 const T *begin () const { return our cells; }
endconstvector131 const T *end () const { return our cells + our size; }
asArgumentToFunctionThatExpectsZeroBasedArrayconstvector132 const T *asArgumentToFunctionThatExpectsZeroBasedArray () const { return our cells; }
asArgumentToFunctionThatExpectsOneBasedArrayconstvector133 const T *asArgumentToFunctionThatExpectsOneBasedArray () const { return our cells - 1; }
134 };
135
136 template <typename T>
137 struct vectorview {
138 T * firstCell = nullptr;
139 integer size = 0;
140 integer stride = 1;
141 vectorview ()
142 = default;
vectorviewvectorview143 explicit vectorview (T * const firstCell_, integer const size_, integer const stride_)
144 : firstCell (firstCell_), size (size_), stride (stride_) { }
vectorviewvectorview145 vectorview (vector<T> const& other)
146 : firstCell (other.cells), size (other.size), stride (1) { }
147 T& operator[] (integer i) const {
148 return our firstCell [(i - 1) * our stride];
149 }
partvectorview150 vectorview<T> part (integer first, integer last) const {
151 const integer newSize = last - (first - 1);
152 if (newSize <= 0)
153 return vectorview<T> ();
154 Melder_assert (first >= 1 && first <= our size);
155 Melder_assert (last >= 1 && last <= our size);
156 return vectorview<T> (& our operator[] (first), newSize, our stride);
157 }
asmatrixviewvectorview158 matrixview<T> asmatrixview (integer nrow, integer ncol) {
159 Melder_assert (nrow * ncol <= our size);
160 return matrixview (our cells, nrow, ncol, ncol * our stride, our stride);
161 }
asArgumentToFunctionThatExpectsZeroBasedArrayvectorview162 T *asArgumentToFunctionThatExpectsZeroBasedArray () const { return & our operator[] (1); }
asArgumentToFunctionThatExpectsOneBasedArrayvectorview163 T *asArgumentToFunctionThatExpectsOneBasedArray () const { return & our operator[] (0); }
164 };
165
166 template <typename T>
167 struct constvectorview {
168 const T * firstCell = nullptr;
169 integer size = 0;
170 integer stride = 1;
171 constvectorview () = default;
constvectorviewconstvectorview172 explicit constvectorview (const T * const firstCell_, integer const size_, integer const stride_)
173 : firstCell (firstCell_), size (size_), stride (stride_) { }
constvectorviewconstvectorview174 constvectorview (constvector<T> const& other)
175 : constvectorview (other.cells, other.size, 1) { }
constvectorviewconstvectorview176 constvectorview (vectorview<T> const& other)
177 : constvectorview (other.firstCell, other.size, other.stride) { }
constvectorviewconstvectorview178 constvectorview (vector<T> const& other)
179 : constvectorview (other.cells, other.size, 1) { }
180 T const& operator[] (integer i) const {
181 return our firstCell [(i - 1) * our stride];
182 }
partconstvectorview183 constvectorview<T> part (integer first, integer last) const {
184 const integer newSize = last - (first - 1);
185 if (newSize <= 0)
186 return constvectorview<T> ();
187 Melder_assert (first >= 1 && first <= our size);
188 Melder_assert (last >= 1 && last <= our size);
189 return constvectorview<T> (& our operator[] (first), newSize, our stride);
190 }
asmatrixviewconstvectorview191 constmatrixview<T> asmatrixview (integer nrow, integer ncol) {
192 Melder_assert (nrow * ncol <= our size);
193 return constmatrixview (our cells, nrow, ncol, ncol * our stride, our stride);
194 }
asArgumentToFunctionThatExpectsZeroBasedArrayconstvectorview195 const T *asArgumentToFunctionThatExpectsZeroBasedArray () const { return & our operator[] (1); }
asArgumentToFunctionThatExpectsOneBasedArrayconstvectorview196 const T *asArgumentToFunctionThatExpectsOneBasedArray () const { return & our operator[] (0); }
197 };
198
199 /*
200 An autovector is the sole owner of its payload, which is a vector.
201 When the autovector ends its life (goes out of scope),
202 it should destroy its payload (if it has not sold it),
203 because keeping a payload alive when the owner is dead
204 would continue to use some of the computer's resources (namely, memory).
205 */
206 template <typename T>
207 struct autovector {
208 T *cells = nullptr;
209 integer size = 0;
210 integer _capacity = 0;
211 autovector () // come into existence without a payload
212 = default;
autovectorautovector213 explicit autovector (integer givenSize, MelderArray::kInitializationType initializationType) { // come into existence and manufacture a payload
214 Melder_assert (givenSize >= 0);
215 our cells = MelderArray:: _alloc <T> (givenSize, initializationType);
216 our size = givenSize;
217 our _capacity = givenSize;
218 }
autovectorautovector219 autovector (std::initializer_list <const T> list) {
220 our size = uinteger_to_integer (list.size());
221 our cells = MelderArray:: _alloc <T> (our size, MelderArray::kInitializationType::RAW); // raw is possible because T is copyable data
222 T *p = our cells;
223 for (auto cell : list)
224 * (p ++) = cell;
225 }
resetautovector226 void reset () noexcept { // on behalf of ambiguous owners (otherwise this could be in autovector<>)
227 if (our cells) {
228 MelderArray:: _free (our cells, our _capacity);
229 our cells = nullptr;
230 }
231 our size = 0;
232 our _capacity = 0;
233 }
~autovectorautovector234 ~autovector () { // destroy the payload (if any)
235 our reset ();
236 }
237 T& operator[] (integer i) const {
238 return our cells [i - 1];
239 }
getautovector240 vector<T> get () const { return vector<T> (our cells, our size); } // let the public use the payload (they may change the values of the elements but not the at-pointer or the size)
allautovector241 vectorview<T> all () const { return vectorview<T> (our cells, our size, 1); }
adoptFromAmbiguousOwnerautovector242 void adoptFromAmbiguousOwner (vector<T> given) { // buy the payload from a non-autovector
243 our reset();
244 our cells = given.cells;
245 our size = given.size;
246 our _capacity = given.size;
247 }
releaseToAmbiguousOwnerautovector248 vector<T> releaseToAmbiguousOwner () { // sell the payload to a non-autovector
249 T *oldCells = our cells;
250 our cells = nullptr; // disown ourselves, preventing automatic destruction of the payload
251 integer oldSize = our size;
252 our size = 0;
253 our _capacity = 0;
254 return vector<T> (oldCells, oldSize);
255 }
partautovector256 vector<T> part (integer first, integer last) const {
257 const integer newSize = last - (first - 1);
258 /*
259 for-loops don't crash if the number of elements is zero.
260 */
261 if (newSize <= 0)
262 return vector<T> ();
263 Melder_assert (first >= 1 && first <= our size);
264 Melder_assert (last >= 1 && last <= our size);
265 return vector<T> (& our cells [first - 1], newSize);
266 }
beginautovector267 T *begin () const { return our cells; }
endautovector268 T *end () const { return our cells + our size; }
asArgumentToFunctionThatExpectsZeroBasedArrayautovector269 T *asArgumentToFunctionThatExpectsZeroBasedArray () const { return our cells; }
asArgumentToFunctionThatExpectsOneBasedArrayautovector270 T *asArgumentToFunctionThatExpectsOneBasedArray () const { return our cells - 1; }
271 /*
272 Disable copying via construction or assignment (which would violate unique ownership of the payload).
273 */
274 autovector (autovector const& other) = delete; // disable copy construction
275 autovector& operator= (autovector const& other) = delete; // disable copy assignment
276 /*
277 Enable moving of r-values (temporaries, implicitly) or l-values (for variables, via an explicit move()).
278 This implements buying a payload from another autovector (which involves destroying our current payload).
279 */
autovectorautovector280 autovector (autovector&& other) noexcept : cells (other.cells), size (other.size), _capacity (other._capacity) { // enable move construction
281 other.cells = nullptr; // disown source
282 other.size = 0; // to keep the source in a valid state
283 other._capacity = 0;
284 }
285 autovector& operator= (autovector&& other) noexcept { // enable move assignment
286 if (other.cells != our cells) {
287 our reset ();
288 our cells = other.cells;
289 our size = other.size;
290 our _capacity = other._capacity;
291 other.cells = nullptr; // disown source
292 other.size = 0; // to keep the source in a valid state
293 other._capacity = 0;
294 }
295 return *this;
296 }
moveautovector297 autovector&& move () noexcept { return static_cast <autovector&&> (*this); } // enable construction and assignment for l-values (variables) via explicit move()
298 /*
299 Some of the following functions are capable of keeping a valid `cells` pointer
300 while `size` can at the same time be zero.
301 */
302 void initWithCapacity (integer capacity, MelderArray::kInitializationType initializationType = MelderArray::kInitializationType::ZERO) {
303 if (capacity > 0)
304 our cells = MelderArray:: _alloc <T> (capacity, initializationType);
305 our size = 0;
306 our _capacity = capacity;
307 }
308 /*
309 If the new size N is less than the current size S,
310 then the first N elements of the vector are kept,
311 so if you want to keep a different range than the
312 first N elements of your original vector,
313 you should shift the elements before resizing.
314
315 If the new size N is greater than the current size S,
316 then all S elements of the vector are kept,
317 and they are the first S elements of the new vector
318 the remaining S - N elements may be initialized to zero.
319 If you want the original S elements to show up
320 elsewhere than at the head of the vector,
321 you should shift the elements after resizing.
322 */
323 void resize (integer newSize, MelderArray::kInitializationType initializationType = MelderArray::kInitializationType::ZERO) {
324 if (newSize > our _capacity) {
325 /*
326 The new capacity is at least twice the old capacity.
327 When starting at a capacity of 0, and continually upsizing by one,
328 the capacity sequence will be: 0, 11, 33, 77, 165, 341, 693, 1397,
329 2805, 5621, 11253, 22517, 45045, 90101, 180213, 360437, 720885...
330 */
331 integer newCapacity = newSize + our size + 10;
332 /*
333 Create without change.
334 */
335 T *newCells = MelderArray:: _alloc <T> (newCapacity, initializationType);
336 /*
337 Change without error.
338 */
339 for (integer i = 1; i <= our size; i ++)
340 newCells [i - 1] = std::move (our cells [i - 1]);
341 if (our cells)
342 MelderArray:: _free (our cells, our _capacity);
343 our cells = newCells;
344 our _capacity = newCapacity;
345 }
346 our size = newSize;
347 }
insertautovector348 void insert (integer position, const T& value) {
349 resize (our size + 1, MelderArray::kInitializationType::RAW);
350 Melder_assert (position >= 1 && position <= our size);
351 for (integer i = our size; i > position; i --)
352 our cells [i - 1] = std::move (our cells [i - 2]);
353 our cells [position - 1] = value;
354 }
appendautovector355 T* append () {
356 resize (our size + 1, MelderArray::kInitializationType::ZERO);
357 return & our cells [our size - 1];
358 }
removeautovector359 void remove (integer position) {
360 Melder_assert (position >= 1 && position <= our size);
361 for (integer i = position; i < our size; i ++)
362 our cells [i - 1] = std::move (our cells [i]);
363 resize (our size - 1);
364 }
365 };
366
367 template <typename T>
newvectorraw(integer size)368 autovector<T> newvectorraw (integer size) {
369 return autovector<T> (size, MelderArray::kInitializationType::RAW);
370 }
371 template <typename T>
newvectorzero(integer size)372 autovector<T> newvectorzero (integer size) {
373 return autovector<T> (size, MelderArray::kInitializationType::ZERO);
374 }
375 template <typename T>
newvectorcopy(constvectorview<T> source)376 autovector<T> newvectorcopy (constvectorview<T> source) {
377 autovector<T> result = newvectorraw<T> (source.size);
378 for (integer i = 1; i <= source.size; i ++)
379 result [i] = source [i];
380 return result;
381 }
382 template <typename T>
newvectorcopy(vectorview<T> source)383 autovector<T> newvectorcopy (vectorview<T> source) {
384 return newvectorcopy (constvectorview<T> (source));
385 }
386
387 template <typename T>
388 struct matrix {
389 T *cells = nullptr;
390 integer nrow = 0, ncol = 0;
391 matrix ()
392 = default;
matrixmatrix393 explicit matrix (T *givenCells, integer givenNrow, integer givenNcol)
394 : cells (givenCells), nrow (givenNrow), ncol (givenNcol) { }
395 //matrix (matrix const& other)
396 // = default;
397 //matrix& operator= (matrix const& other)
398 // = default;
matrixmatrix399 explicit matrix (vector<T> const& vec, integer givenNrow, integer givenNcol)
400 : matrix (vec.cells, givenNrow, givenNcol)
401 {
402 Melder_assert (givenNrow * givenNcol <= vec. size);
403 }
404 vector<T> operator[] (integer rowNumber) const {
405 return vector<T> (our cells + (rowNumber - 1) * our ncol, our ncol);
406 }
rowmatrix407 vector<T> row (integer rowNumber) const {
408 Melder_assert (rowNumber >= 1 && rowNumber <= our nrow);
409 Melder_assert (our cells);
410 return vector<T> (our cells + (rowNumber - 1) * our ncol, our ncol);
411 }
columnmatrix412 vectorview<T> column (integer columnNumber) const {
413 Melder_assert (columnNumber >= 1 && columnNumber <= our ncol);
414 return vectorview<T> (our cells + (columnNumber - 1), our nrow, our ncol);
415 }
diagonalmatrix416 vectorview<T> diagonal () const {
417 return vectorview<T> (our cells, std::min (our nrow, our ncol), our ncol + 1);
418 }
horizontalBandmatrix419 matrixview<T> horizontalBand (integer firstRow, integer lastRow) const {
420 const integer newNrow = lastRow - (firstRow - 1);
421 if (newNrow <= 0)
422 return matrixview<T> ();
423 Melder_assert (firstRow >= 1 && firstRow <= our nrow);
424 Melder_assert (lastRow >= 1 && lastRow <= our nrow);
425 return matrixview<T> (our cells + (firstRow - 1) * our ncol, newNrow, our ncol, our ncol, 1);
426 }
verticalBandmatrix427 matrixview<T> verticalBand (integer firstColumn, integer lastColumn) const {
428 const integer newNcol = lastColumn - (firstColumn - 1);
429 if (newNcol <= 0)
430 return matrixview<T> ();
431 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
432 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
433 return matrixview<T> (our cells + (firstColumn - 1), our nrow, newNcol, our ncol, 1);
434 }
partmatrix435 matrixview<T> part (integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) const {
436 const integer newNrow = lastRow - (firstRow - 1), newNcol = lastColumn - (firstColumn - 1);
437 if (newNrow <= 0 || newNcol <= 0)
438 return matrixview<T> ();
439 Melder_assert (firstRow >= 1 && firstRow <= our nrow);
440 Melder_assert (lastRow >= 1 && lastRow <= our nrow);
441 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
442 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
443 return matrixview<T> (
444 our cells + (firstRow - 1) * our ncol + (firstColumn - 1),
445 newNrow, newNcol, our ncol, 1
446 );
447 }
transposematrix448 matrixview<T> transpose () const {
449 return matrixview<T> (our cells, our ncol, our nrow, 1, our ncol);
450 }
asvectormatrix451 vector<T> asvector () const {
452 return vector<T> (our cells, our nrow * our ncol);
453 }
asvectormatrix454 vector<T> asvector (integer size) const {
455 Melder_assert (size <= our nrow * our ncol);
456 return vector<T> (our cells, size);
457 }
458 };
459
460 template <typename T>
461 struct constmatrix {
462 const T *cells = nullptr;
463 integer nrow = 0, ncol = 0;
464 constmatrix ()
465 = default;
constmatrixconstmatrix466 explicit constmatrix (const T *givenCells, integer givenNrow, integer givenNcol)
467 : cells (givenCells), nrow (givenNrow), ncol (givenNcol) { }
constmatrixconstmatrix468 constmatrix (matrix<T> const& other)
469 : constmatrix (other.cells, other.nrow, other.ncol) { }
constmatrixconstmatrix470 explicit constmatrix (vector<T> const& vec, integer givenNrow, integer givenNcol)
471 : constmatrix (vec.cells, givenNrow, givenNcol)
472 {
473 Melder_assert (givenNrow * givenNcol <= vec. size);
474 }
475 constvector<T> operator[] (integer rowNumber) const {
476 return constvector<T> (our cells + (rowNumber - 1) * our ncol, our ncol);
477 }
rowconstmatrix478 constvector<T> row (integer rowNumber) const {
479 Melder_assert (rowNumber >= 1 && rowNumber <= our nrow);
480 Melder_assert (our cells);
481 return constvector<T> (our cells + (rowNumber - 1) * our ncol, our ncol);
482 }
columnconstmatrix483 constvectorview<T> column (integer columnNumber) const {
484 Melder_assert (columnNumber >= 1 && columnNumber <= our ncol);
485 return constvectorview<T> (our cells + (columnNumber - 1), our nrow, our ncol);
486 }
diagonalconstmatrix487 constvectorview<T> diagonal () const {
488 return constvectorview<T> (our cells, std::min (our nrow, our ncol), our ncol + 1);
489 }
horizontalBandconstmatrix490 constmatrixview<T> horizontalBand (integer firstRow, integer lastRow) const {
491 const integer newNrow = lastRow - (firstRow - 1);
492 if (newNrow <= 0)
493 return constmatrixview<T> ();
494 Melder_assert (firstRow >= 1 && firstRow <= our nrow);
495 Melder_assert (lastRow >= 1 && lastRow <= our nrow);
496 return constmatrixview<T> (our cells + (firstRow - 1) * our ncol, newNrow, our ncol, our ncol, 1);
497 }
verticalBandconstmatrix498 constmatrixview<T> verticalBand (integer firstColumn, integer lastColumn) const {
499 const integer newNcol = lastColumn - (firstColumn - 1);
500 if (newNcol <= 0)
501 return constmatrixview<T> ();
502 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
503 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
504 return constmatrixview<T> (our cells + (firstColumn - 1), our nrow, newNcol, our ncol, 1);
505 }
partconstmatrix506 constmatrixview<T> part (integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) const {
507 const integer newNrow = lastRow - (firstRow - 1), newNcol = lastColumn - (firstColumn - 1);
508 if (newNrow <= 0 || newNcol <= 0)
509 return constmatrixview<T> ();
510 Melder_assert (firstRow >= 1 && firstRow <= our nrow);
511 Melder_assert (lastRow >= 1 && lastRow <= our nrow);
512 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
513 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
514 return constmatrixview<T> (
515 our cells + (firstRow - 1) * our ncol + (firstColumn - 1),
516 newNrow, newNcol, our ncol, 1
517 );
518 }
transposeconstmatrix519 constmatrixview<T> transpose () const {
520 return constmatrixview<T> (our cells, our ncol, our nrow, 1, our ncol);
521 }
asvectorconstmatrix522 constvector<T> asvector () const {
523 return constvector<T> (our cells, our nrow * our ncol);
524 }
asvectorconstmatrix525 constvector<T> asvector (integer size) const {
526 Melder_assert (size <= our nrow * our ncol);
527 return constvector<T> (our cells, size);
528 }
529 };
530
531 template <typename T>
532 struct matrixview {
533 T * firstCell = nullptr;
534 integer nrow = 0, ncol = 0;
535 /*mutable*/ integer rowStride = 0, colStride = 1; // mutable perhaps once an automatrix has strides
536 /*
537 Make sure that each of the following creates an appropriately initialized matrixview:
538 matrixview<double> matvu; // OK
539 auto matvu = matrixview<double>(); // OK
540 */
541 matrixview ()
542 = default;
543 /*
544 The following constructor is explicit, i.e.,
545 it cannot be used as an implicit conversion from an initializer list,
546 as in any of the following:
547 matrixview<double> mat = { p, 10, 100, 100, 1 }; // WRONG
548 myFunction ({ p, 10, 100, 100, 1 }); // WRONG
549 whereas any of the following is fine:
550 matrixview<double> mat { p, 10, 100, 100, 1 }; // OK
551 matrixview<double> mat (p, 10, 100, 100, 1); // OK
552 auto mat = matrixview<double> { p, 10, 100, 100, 1 }; // OK
553 auto mat = matrixview<double> (p, 10, 100, 100, 1); // OK
554 myFunction (matrixview<double> { p, 10, 100, 100, 1 }); // OK
555 myFunction (matrixview<double> (p, 10, 100, 100, 1)); // OK
556 */
matrixviewmatrixview557 explicit matrixview (T * firstCell_, integer nrow_, integer ncol_, integer rowStride_, integer colStride_)
558 : firstCell (firstCell_), nrow (nrow_), ncol (ncol_), rowStride (rowStride_), colStride (colStride_) { }
559 /*
560 The following constructor is implicit, i.e.,
561 you can assign a matrix to a matrixview.
562 */
matrixviewmatrixview563 matrixview (matrix<T> const& other)
564 : matrixview (other.cells, other.nrow, other.ncol, other.ncol, 1_integer) { }
matrixviewmatrixview565 explicit matrixview (vectorview<T> const& vec, integer givenNrow, integer givenNcol) :
566 matrixview (vec.cells, givenNrow, givenNcol, givenNcol * vec.stride, vec.stride)
567 {
568 Melder_assert (givenNrow * givenNcol <= vec. size);
569 }
570 vectorview<T> operator[] (integer rowNumber) const {
571 return vectorview<T> (our firstCell + (rowNumber - 1) * our rowStride, our ncol, our colStride);
572 }
rowmatrixview573 vectorview<T> row (integer rowNumber) const {
574 Melder_assert (rowNumber >= 1 && rowNumber <= our nrow);
575 return vectorview<T> (our firstCell + (rowNumber - 1) * our rowStride, our ncol, our colStride);
576 }
columnmatrixview577 vectorview<T> column (integer columnNumber) const {
578 Melder_assert (columnNumber >= 1 && columnNumber <= our ncol);
579 return vectorview<T> (our firstCell + (columnNumber - 1) * our colStride, our nrow, our rowStride);
580 }
diagonalmatrixview581 vectorview<T> diagonal () const {
582 return vectorview<T> (our firstCell, std::min (our nrow, our ncol), our rowStride + our colStride);
583 }
verticalBandmatrixview584 matrixview<T> verticalBand (integer firstColumn, integer lastColumn) const {
585 const integer newNcol = lastColumn - (firstColumn - 1);
586 if (newNcol <= 0)
587 return matrixview<T> ();
588 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
589 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
590 return matrixview<T> (our firstCell + (firstColumn - 1) * our colStride,
591 our nrow, newNcol, our rowStride, our colStride);
592 }
partmatrixview593 matrixview<T> part (integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) const {
594 const integer newNrow = lastRow - (firstRow - 1), newNcol = lastColumn - (firstColumn - 1);
595 if (newNrow <= 0 || newNcol <= 0)
596 return matrixview<T> ();
597 Melder_assert (firstRow >= 1 && firstRow <= our nrow);
598 Melder_assert (lastRow >= 1 && lastRow <= our nrow);
599 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
600 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
601 return matrixview<T> (
602 our firstCell + (firstRow - 1) * our rowStride + (firstColumn - 1) * our colStride,
603 newNrow, newNcol, our rowStride, our colStride
604 );
605 }
transposematrixview606 matrixview<T> transpose () const {
607 return matrixview<T> (our firstCell, our ncol, our nrow, our colStride, our rowStride);
608 }
609 };
610
611 template <typename T>
612 struct constmatrixview {
613 const T * firstCell = nullptr;
614 integer nrow = 0, ncol = 0;
615 integer rowStride = 0, colStride = 1;
616 constmatrixview ()
617 = default;
constmatrixviewconstmatrixview618 explicit constmatrixview (const T * const firstCell_, integer const nrow_, integer const ncol_, integer const rowStride_, integer const colStride_)
619 : firstCell (firstCell_), nrow (nrow_), ncol (ncol_), rowStride (rowStride_), colStride (colStride_) { }
constmatrixviewconstmatrixview620 constmatrixview (const constmatrix<T>& other)
621 : constmatrixview (other.cells, other.nrow, other.ncol, other.ncol, 1_integer) { }
constmatrixviewconstmatrixview622 constmatrixview (const matrix<T>& other) // shortcut the otherwise double conversion
623 : constmatrixview (other.cells, other.nrow, other.ncol, other.ncol, 1_integer) { }
constmatrixviewconstmatrixview624 constmatrixview (matrixview<T> const& other)
625 : constmatrixview (other.firstCell, other.nrow, other.ncol, other.rowStride, other.colStride) { }
constmatrixviewconstmatrixview626 explicit constmatrixview (constvectorview<T> const& vec, integer givenNrow, integer givenNcol) :
627 constmatrixview (vec.cells, givenNrow, givenNcol, givenNcol * vec.stride, vec.stride)
628 {
629 Melder_assert (givenNrow * givenNcol <= vec. size);
630 }
631 constvectorview<T> operator[] (integer i) const {
632 return constvectorview<T> (our firstCell + (i - 1) * our rowStride, our ncol, our colStride);
633 }
rowconstmatrixview634 constvectorview<T> row (integer rowNumber) const {
635 Melder_assert (rowNumber >= 1 && rowNumber <= our nrow);
636 return constvectorview<T> (our firstCell + (rowNumber - 1) * our rowStride, our ncol, our colStride);
637 }
columnconstmatrixview638 constvectorview<T> column (integer columnNumber) const {
639 Melder_assert (columnNumber >= 1 && columnNumber <= our ncol);
640 return constvectorview<T> (our firstCell + (columnNumber - 1) * our colStride, our nrow, our rowStride);
641 }
diagonalconstmatrixview642 constvectorview<T> diagonal () const {
643 return constvectorview<T> (our firstCell, std::min (our nrow, our ncol), our rowStride + our colStride);
644 }
verticalBandconstmatrixview645 constmatrixview<T> verticalBand (integer firstColumn, integer lastColumn) const {
646 const integer newNcol = lastColumn - (firstColumn - 1);
647 if (newNcol <= 0)
648 return constmatrixview<T> ();
649 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
650 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
651 return constmatrixview<T> (our firstCell + (firstColumn - 1) * our colStride,
652 our nrow, newNcol, our rowStride, our colStride);
653 }
partconstmatrixview654 constmatrixview<T> part (integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) const {
655 const integer newNrow = lastRow - (firstRow - 1), newNcol = lastColumn - (firstColumn - 1);
656 if (newNrow <= 0 || newNcol <= 0)
657 return constmatrixview<T> ();
658 Melder_assert (firstRow >= 1 && firstRow <= our nrow);
659 Melder_assert (lastRow >= 1 && lastRow <= our nrow);
660 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
661 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
662 return constmatrixview<T> (
663 our firstCell
664 + (firstRow - 1) * our rowStride
665 + (firstColumn - 1) * our colStride,
666 newNrow, newNcol,
667 our rowStride, our colStride
668 );
669 }
transposeconstmatrixview670 constmatrixview<T> transpose () const {
671 return constmatrixview<T> (our firstCell, our ncol, our nrow, our colStride, our rowStride);
672 }
673 };
674
675 /*
676 An automatrix is the sole owner of its payload, which is a matrix.
677 When the automatrix ends its life (goes out of scope),
678 it should destroy its payload (if it has not sold it),
679 because keeping a payload alive when the owner is dead
680 would continue to use some of the computer's resources (namely, memory).
681 */
682 template <typename T>
683 struct automatrix {
684 T *cells = nullptr;
685 integer nrow = 0, ncol = 0;
686 automatrix () // come into existence without a payload
687 = default;
automatrixautomatrix688 explicit automatrix (integer givenNrow, integer givenNcol, MelderArray::kInitializationType initializationType) { // come into existence and manufacture a payload
689 Melder_assert (givenNrow >= 0);
690 Melder_assert (givenNcol >= 0);
691 our cells = MelderArray:: _alloc <T> (givenNrow * givenNcol, initializationType);
692 our nrow = givenNrow;
693 our ncol = givenNcol;
694 }
automatrixautomatrix695 automatrix (std::initializer_list <std::initializer_list <T>> list) {
696 our nrow = uinteger_to_integer (list.size());
697 Melder_assert (our nrow > 0); // empty matrices should be created with automatrix<T>() or automatrix<T> (0, 10) or so
698 our ncol = uinteger_to_integer (list.begin()->size());
699 Melder_assert (our ncol > 0); // empty matrices should be created with automatrix<T>() or automatrix<T> (10, 0) or so
700 our cells = MelderArray:: _alloc <T> (our nrow * our ncol, MelderArray::kInitializationType::RAW);
701 double *p = our cells;
702 for (auto row : list) {
703 const integer numberOfColumnsInThisRow = uinteger_to_integer (row.size());
704 Melder_assert (numberOfColumnsInThisRow == our ncol); // unfortunately, no support for static_assert here in C++17
705 for (auto cell : row)
706 * (p ++) = cell;
707 }
708 }
~automatrixautomatrix709 ~automatrix () { // destroy the payload (if any)
710 if (our cells)
711 MelderArray:: _free (our cells, our nrow * our ncol);
712 }
getautomatrix713 matrix<T> get() const { return matrix<T> (our cells, our nrow, our ncol); } // let the public use the payload (they may change the values in the cells but not the cell pointer, nrow or ncol)
allautomatrix714 matrixview<T> all () const {
715 return matrixview<T> (our cells, our nrow, our ncol, our ncol, 1);
716 }
adoptFromAmbiguousOwnerautomatrix717 void adoptFromAmbiguousOwner (matrix<T> const& given) { // buy the payload from a non-automatrix
718 our reset();
719 our cells = given.cells;
720 our nrow = given.nrow;
721 our ncol = given.ncol;
722 }
releaseToAmbiguousOwnerautomatrix723 matrix<T> releaseToAmbiguousOwner () { // sell the payload to a non-automatrix
724 T *oldCells = our cells;
725 our cells = nullptr; // disown ourselves, preventing automatic destruction of the payload
726 return matrix<T> (oldCells, our nrow, our ncol);
727 }
728 /*
729 Disable copying via construction or assignment (which would violate unique ownership of the payload).
730 */
731 automatrix (automatrix const& other) // disable copy constructor
732 = delete;
733 automatrix& operator= (automatrix const& other) // disable copy assignment
734 = delete;
735 /*
736 Enable moving of r-values (temporaries, implicitly) or l-values (for variables, via an explicit move()).
737 This implements buying a payload from another automatrix (which involves destroying our current payload).
738 */
automatrixautomatrix739 automatrix (automatrix&& other) noexcept : cells (other.cells), nrow (other.nrow), ncol (other.ncol) // enable move constructor
740 {
741 other.cells = nullptr; // disown source
742 other.nrow = 0; // to keep the source in a valid state
743 other.ncol = 0; // to keep the source in a valid state
744 }
745 automatrix& operator= (automatrix&& other) noexcept { // enable move assignment
746 if (other.cells != our cells) {
747 if (our cells)
748 MelderArray:: _free (our cells, our nrow * our ncol);
749 our cells = other.cells;
750 our nrow = other.nrow;
751 our ncol = other.ncol;
752 other.cells = nullptr; // disown source
753 other.nrow = 0; // to keep the source in a valid state
754 other.ncol = 0; // to keep the source in a valid state
755 } else if (! our cells) {
756 our nrow = other.nrow; // yes; if both cells are null, we still have to copy the shape, which could be { 0, 2 } or so
757 our ncol = other.ncol;
758 }
759 return *this;
760 }
761 vector<T> operator[] (integer rowNumber) const {
762 return vector<T> (our cells + (rowNumber - 1) * our ncol, our ncol);
763 }
rowautomatrix764 vector<T> row (integer rowNumber) const {
765 Melder_assert (rowNumber >= 1 && rowNumber <= our nrow);
766 Melder_assert (our cells);
767 return vector<T> (our cells + (rowNumber - 1) * our ncol, our ncol);
768 }
columnautomatrix769 vectorview<T> column (integer columnNumber) const {
770 Melder_assert (columnNumber >= 1 && columnNumber <= our ncol);
771 return vectorview<T> (our cells + (columnNumber - 1), our nrow, our ncol);
772 }
diagonalautomatrix773 vectorview<T> diagonal () const {
774 return vectorview<T> (our cells, std::min (our nrow, our ncol), our ncol + 1);
775 }
horizontalBandautomatrix776 matrixview<T> horizontalBand (integer firstRow, integer lastRow) const {
777 const integer newNrow = lastRow - (firstRow - 1);
778 if (newNrow <= 0)
779 return matrixview<T> ();
780 Melder_assert (firstRow >= 1 && firstRow <= our nrow);
781 Melder_assert (lastRow >= 1 && lastRow <= our nrow);
782 return matrixview<T> (our cells + (firstRow - 1) * our ncol, newNrow, our ncol, our ncol, 1);
783 }
verticalBandautomatrix784 matrixview<T> verticalBand (integer firstColumn, integer lastColumn) const {
785 const integer newNcol = lastColumn - (firstColumn - 1);
786 if (newNcol <= 0)
787 return matrixview<T> ();
788 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
789 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
790 return matrixview<T> (our cells + (firstColumn - 1), our nrow, newNcol, our ncol, 1);
791 }
partautomatrix792 matrixview<T> part (integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) const {
793 const integer newNrow = lastRow - (firstRow - 1), newNcol = lastColumn - (firstColumn - 1);
794 if (newNrow <= 0 || newNcol <= 0)
795 return matrixview<T> ();
796 Melder_assert (firstRow >= 1 && firstRow <= our nrow);
797 Melder_assert (lastRow >= 1 && lastRow <= our nrow);
798 Melder_assert (firstColumn >= 1 && firstColumn <= our ncol);
799 Melder_assert (lastColumn >= 1 && lastColumn <= our ncol);
800 return matrixview<T> (
801 our cells + (firstRow - 1) * our ncol + (firstColumn - 1),
802 newNrow, newNcol, our ncol, 1
803 );
804 }
transposeautomatrix805 matrixview<T> transpose () const {
806 return matrixview<T> (our cells, our ncol, our nrow, 1, our ncol);
807 }
808 void resize (integer newNrow, integer newNcol, MelderArray::kInitializationType initializationType = MelderArray::kInitializationType::ZERO) {
809 if (newNrow > our nrow || newNcol > our ncol) {
810 integer const newNumberOfCells = newNrow * newNcol;
811 T *newCells = MelderArray:: _alloc <T> (newNumberOfCells, initializationType);
812 integer const numberOfRowsToCopy = std::min (our nrow, newNrow);
813 integer const numberOfColumnsToCopy = std::min (our ncol, newNcol);
814 for (integer irow = 1; irow <= numberOfRowsToCopy; irow ++)
815 for (integer icol = 1; icol <= numberOfColumnsToCopy; icol ++)
816 newCells [(irow - 1) * newNcol + (icol - 1)] = std::move (our cells [(irow - 1) * our ncol + (icol - 1)]);
817 if (our cells)
818 MelderArray:: _free (our cells, our nrow * our ncol);
819 our cells = newCells;
820 } else if (newNcol == our ncol) {
821 // do nothing
822 } else {
823 /*
824 The cells of the first new row already have the correct values.
825 */
826 for (integer irow = 2; irow <= newNrow; irow ++)
827 for (integer icol = 1; icol <= newNcol; icol ++)
828 our cells [(irow - 1) * newNcol + (icol - 1)] = std::move (our cells [(irow - 1) * our ncol + (icol - 1)]);
829 }
830 our nrow = newNrow;
831 our ncol = newNcol;
832 }
resetautomatrix833 void reset () noexcept { // on behalf of ambiguous owners (otherwise this could be in autoMAT)
834 if (our cells) {
835 MelderArray:: _free (our cells, our nrow * our ncol);
836 our cells = nullptr;
837 }
838 our nrow = 0;
839 our ncol = 0;
840 }
moveautomatrix841 automatrix&& move () noexcept { return static_cast <automatrix&&> (*this); }
842 };
843
844 template <typename T>
newmatrixraw(integer nrow,integer ncol)845 automatrix<T> newmatrixraw (integer nrow, integer ncol) {
846 return automatrix<T> (nrow, ncol, MelderArray::kInitializationType::RAW);
847 }
848 template <typename T>
newmatrixzero(integer nrow,integer ncol)849 automatrix<T> newmatrixzero (integer nrow, integer ncol) {
850 return automatrix<T> (nrow, ncol, MelderArray::kInitializationType::ZERO);
851 }
852 template <typename T>
matrixcopy(matrixview<T> const & target,constmatrixview<T> const & source)853 void matrixcopy (matrixview<T> const& target, constmatrixview<T> const& source) {
854 Melder_assert (source.nrow == target.nrow && source.ncol == target.ncol);
855 for (integer irow = 1; irow <= source.nrow; irow ++)
856 for (integer icol = 1; icol <= source.ncol; icol ++)
857 target [irow] [icol] = source [irow] [icol];
858 }
859 template <typename T>
matrixcopy(matrixview<T> const & target,matrixview<T> const & source)860 void matrixcopy (matrixview<T> const& target, matrixview<T> const& source) {
861 matrixcopy (target, constmatrixview<T> (source));
862 }
863 template <typename T>
newmatrixcopy(constmatrixview<T> const & source)864 automatrix<T> newmatrixcopy (constmatrixview<T> const& source) {
865 automatrix<T> result = newmatrixraw<T> (source.nrow, source.ncol);
866 matrixcopy (result.all(), source);
867 return result;
868 }
869 template <typename T>
newmatrixcopy(matrixview<T> const & source)870 automatrix<T> newmatrixcopy (matrixview<T> const& source) {
871 return newmatrixcopy<T> (constmatrixview<T> (source));
872 }
873
874 template <typename T>
assertCell(constvector<T> const & x,integer elementNumber)875 void assertCell (constvector<T> const& x, integer elementNumber) {
876 Melder_assert (elementNumber >= 1 && elementNumber <= x.size);
877 }
878 template <typename T>
assertRow(constmatrix<T> const & x,integer rowNumber)879 void assertRow (constmatrix<T> const& x, integer rowNumber) {
880 Melder_assert (rowNumber >= 1 && rowNumber <= x.nrow);
881 }
882 template <typename T>
assertColumn(constmatrix<T> const & x,integer columnNumber)883 void assertColumn (constmatrix<T> const& x, integer columnNumber) {
884 Melder_assert (columnNumber >= 1 && columnNumber <= x.ncol);
885 }
886 template <typename T>
assertCell(constmatrix<T> const & x,integer rowNumber,integer columnNumber)887 void assertCell (constmatrix<T> const& x, integer rowNumber, integer columnNumber) {
888 assertRow (x, rowNumber);
889 assertColumn (x, columnNumber);
890 }
891 template <typename T>
newmatrixpart(constmatrix<T> const & x,integer firstRow,integer lastRow,integer firstColumn,integer lastColumn)892 automatrix<T> newmatrixpart (constmatrix<T> const& x, integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) {
893 assertCell (x, firstRow, firstColumn);
894 assertCell (x, lastRow, lastColumn);
895 integer numberOfRows = lastRow - (firstRow - 1);
896 Melder_assert (numberOfRows >= 0);
897 integer numberOfColumns = lastColumn - (firstColumn - 1);
898 Melder_assert (numberOfColumns >= 0);
899 automatrix<T> result = newmatrixraw<T> (numberOfRows, numberOfColumns);
900 for (integer irow = 1; irow <= numberOfRows; irow ++)
901 for (integer icol = 1; icol <= numberOfColumns; icol ++)
902 result [irow] [icol] = x [firstRow - 1 + irow] [firstColumn - 1 + icol];
903 return result;
904 }
905 template <typename T>
newmatrixpart(matrix<T> const & x,integer firstRow,integer lastRow,integer firstColumn,integer lastColumn)906 automatrix<T> newmatrixpart (matrix<T> const& x, integer firstRow, integer lastRow, integer firstColumn, integer lastColumn) {
907 newmatrixpart (constmatrix<T> (x), firstRow, lastRow, firstColumn, lastColumn);
908 }
909
910 template <typename T>
911 struct autotensor3;
912
913 template <typename T>
914 struct tensor3 {
915 T * cells = nullptr;
916 integer ndim1 = 0, ndim2 = 0, ndim3 = 0;
917 integer stride1 = 0, stride2 = 0, stride3 = 1;
918 tensor3 ()
919 = default;
920 tensor3 (autotensor3<T> const& other)
921 = delete;
tensor3tensor3922 explicit tensor3 (T * cells_,
923 integer ndim1_, integer ndim2_, integer ndim3_,
924 integer stride1_, integer stride2_, integer stride3_
925 ) :
926 cells (cells_),
927 ndim1 (ndim1_), ndim2 (ndim2_), ndim3 (ndim3_),
928 stride1 (stride1_), stride2 (stride2_), stride3 (stride3_)
929 { }
930 matrixview<T> operator[] (integer dim1) const {
931 return matrixview<T> (our cells + (dim1 - 1) * our stride1, our ndim2, our ndim3, our stride2, our stride3);
932 }
line1tensor3933 vectorview<T> line1 (integer dim2, integer dim3) const {
934 Melder_assert (dim2 >= 1 && dim2 <= our ndim2);
935 Melder_assert (dim3 >= 1 && dim3 <= our ndim3);
936 return vectorview<T> (
937 our cells
938 + (dim2 - 1) * our stride2
939 + (dim3 - 1) * our stride3,
940 our ndim1,
941 our stride1
942 );
943 }
line2tensor3944 vectorview<T> line2 (integer dim1, integer dim3) const {
945 Melder_assert (dim1 >= 1 && dim1 <= our ndim1);
946 Melder_assert (dim3 >= 1 && dim3 <= our ndim3);
947 return vectorview<T> (
948 our cells
949 + (dim1 - 1) * our stride1
950 + (dim3 - 1) * our stride3,
951 our ndim2,
952 our stride2
953 );
954 }
line3tensor3955 vectorview<T> line3 (integer dim1, integer dim2) const {
956 Melder_assert (dim1 >= 1 && dim1 <= our ndim1);
957 Melder_assert (dim2 >= 1 && dim2 <= our ndim2);
958 return vectorview<T> (
959 our cells
960 + (dim1 - 1) * our stride1
961 + (dim2 - 1) * our stride2,
962 our ndim3,
963 our stride3
964 );
965 }
plane12tensor3966 matrixview<T> plane12 (integer dim3) const {
967 Melder_assert (dim3 >= 1 && dim3 <= our ndim3);
968 return matrixview<T> (
969 our cells
970 + (dim3 - 1) * our stride3,
971 our ndim1, our ndim2,
972 our stride1, our stride2
973 );
974 }
plane13tensor3975 matrixview<T> plane13 (integer dim2) const {
976 Melder_assert (dim2 >= 1 && dim2 <= our ndim2);
977 return matrixview<T> (
978 our cells
979 + (dim2 - 1) * our stride2,
980 our ndim1, our ndim3,
981 our stride1, our stride3
982 );
983 }
plane23tensor3984 matrixview<T> plane23 (integer dim1) const {
985 Melder_assert (dim1 >= 1 && dim1 <= our ndim1);
986 return matrixview<T> (
987 our cells
988 + (dim1 - 1) * our stride1,
989 our ndim2, our ndim3,
990 our stride2, our stride3
991 );
992 }
parttensor3993 tensor3<T> part (
994 integer firstDim1, integer lastDim1,
995 integer firstDim2, integer lastDim2,
996 integer firstDim3, integer lastDim3
997 ) const {
998 const integer newNdim1 = lastDim1 - (firstDim1 - 1);
999 const integer newNdim2 = lastDim2 - (firstDim2 - 1);
1000 const integer newNdim3 = lastDim3 - (firstDim3 - 1);
1001 if (newNdim1 <= 0 || newNdim2 <= 0 || newNdim3 <= 0)
1002 return tensor3<T> ();
1003 Melder_assert (firstDim1 >= 1 && firstDim1 <= our ndim1);
1004 Melder_assert (lastDim1 >= 1 && lastDim1 <= our ndim1);
1005 Melder_assert (firstDim2 >= 1 && firstDim2 <= our ndim2);
1006 Melder_assert (lastDim2 >= 1 && lastDim2 <= our ndim2);
1007 Melder_assert (firstDim3 >= 1 && firstDim3 <= our ndim3);
1008 Melder_assert (lastDim3 >= 1 && lastDim3 <= our ndim3);
1009 return tensor3<T> (
1010 our cells
1011 + (firstDim1 - 1) * our stride1
1012 + (firstDim2 - 1) * our stride2
1013 + (firstDim3 - 1) * our stride3,
1014 newNdim1, newNdim2, newNdim3,
1015 our stride1, our stride2, our stride3
1016 );
1017 }
1018 };
1019
1020 template <typename T>
1021 struct consttensor3 {
1022 const T * cells = nullptr;
1023 integer ndim1 = 0, ndim2 = 0, ndim3 = 0;
1024 integer stride1 = 0, stride2 = 0, stride3 = 1;
1025 consttensor3 ()
1026 = default;
1027 consttensor3 (const autotensor3<T>& other)
1028 = delete;
consttensor3consttensor31029 explicit consttensor3 (const T * cells_,
1030 integer ndim1_, integer ndim2_, integer ndim3_,
1031 integer stride1_, integer stride2_, integer stride3_
1032 ) :
1033 cells (cells_),
1034 ndim1 (ndim1_), ndim2 (ndim2_), ndim3 (ndim3_),
1035 stride1 (stride1_), stride2 (stride2_), stride3 (stride3_)
1036 { }
consttensor3consttensor31037 consttensor3 (tensor3<T> ten) :
1038 cells (ten.cells),
1039 ndim1 (ten.ndim1), ndim2 (ten.ndim2), ndim3 (ten.ndim3),
1040 stride1 (ten.stride1), stride2 (ten.stride2), stride3 (ten.stride3)
1041 { }
1042 constmatrixview<T> operator[] (integer dim1) const {
1043 return constmatrixview<T> (our cells + (dim1 - 1) * our stride1, our ndim2, our ndim3, our stride2, our stride3);
1044 }
line1consttensor31045 constvectorview<T> line1 (integer dim2, integer dim3) const {
1046 Melder_assert (dim2 >= 1 && dim2 <= our ndim2);
1047 Melder_assert (dim3 >= 1 && dim3 <= our ndim3);
1048 return constvectorview<T> (
1049 our cells
1050 + (dim2 - 1) * our stride2
1051 + (dim3 - 1) * our stride3,
1052 our nidm1,
1053 our stride1
1054 );
1055 }
line2consttensor31056 constvectorview<T> line2 (integer dim1, integer dim3) const {
1057 Melder_assert (dim1 >= 1 && dim1 <= our ndim1);
1058 Melder_assert (dim3 >= 1 && dim3 <= our ndim3);
1059 return constvectorview<T> (
1060 our cells
1061 + (dim1 - 1) * our stride1
1062 + (dim3 - 1) * our stride3,
1063 our ndim2,
1064 our stride2
1065 );
1066 }
line3consttensor31067 constvectorview<T> line3 (integer dim1, integer dim2) const {
1068 Melder_assert (dim1 >= 1 && dim1 <= our ndim1);
1069 Melder_assert (dim2 >= 1 && dim2 <= our ndim2);
1070 return constvectorview<T> (
1071 our cells
1072 + (dim1 - 1) * our stride1
1073 + (dim2 - 1) * our stride2,
1074 our ndim3,
1075 our stride3
1076 );
1077 }
plane12consttensor31078 constmatrixview<T> plane12 (integer dim3) const {
1079 Melder_assert (dim3 >= 1 && dim3 <= our ndim3);
1080 return constmatrixview<T> (
1081 our cells
1082 + (dim3 - 1) * our stride3,
1083 our ndim1, our ndim2,
1084 our stride1, our stride2
1085 );
1086 }
plane13consttensor31087 constmatrixview<T> plane13 (integer dim2) const {
1088 Melder_assert (dim2 >= 1 && dim2 <= our ndim2);
1089 return constmatrixview<T> (
1090 our cells
1091 + (dim2 - 1) * our stride2,
1092 our ndim1, our ndim3,
1093 our stride1, our stride3
1094 );
1095 }
plane23consttensor31096 constmatrixview<T> plane23 (integer dim1) const {
1097 Melder_assert (dim1 >= 1 && dim1 <= our ndim1);
1098 return constmatrixview<T> (
1099 our cells
1100 + (dim1 - 1) * our stride1,
1101 our ndim2, our ndim3,
1102 our stride2, our stride3
1103 );
1104 }
partconsttensor31105 consttensor3<T> part (
1106 integer firstDim1, integer lastDim1,
1107 integer firstDim2, integer lastDim2,
1108 integer firstDim3, integer lastDim3
1109 ) const {
1110 const integer newNdim1 = lastDim1 - (firstDim1 - 1);
1111 const integer newNdim2 = lastDim2 - (firstDim2 - 1);
1112 const integer newNdim3 = lastDim3 - (firstDim3 - 1);
1113 if (newNdim1 <= 0 || newNdim2 <= 0 || newNdim3 <= 0)
1114 return consttensor3<T> ();
1115 Melder_assert (firstDim1 >= 1 && firstDim1 <= our ndim1);
1116 Melder_assert (lastDim1 >= 1 && lastDim1 <= our ndim1);
1117 Melder_assert (firstDim2 >= 1 && firstDim2 <= our ndim2);
1118 Melder_assert (lastDim2 >= 1 && lastDim2 <= our ndim2);
1119 Melder_assert (firstDim3 >= 1 && firstDim3 <= our ndim3);
1120 Melder_assert (lastDim3 >= 1 && lastDim3 <= our ndim3);
1121 return consttensor3<T> (
1122 our cells
1123 + (firstDim1 - 1) * our stride1
1124 + (firstDim2 - 1) * our stride2
1125 + (firstDim3 - 1) * our stride3,
1126 newNdim1, newNdim2, newNdim3,
1127 our stride1, our stride2, our stride3
1128 );
1129 }
1130 };
1131
1132 template <typename T>
1133 struct autotensor3 : public tensor3<T> {
1134 autotensor3 () = default; // come into existence without a payload
autotensor3autotensor31135 explicit autotensor3 (integer givenNdim1, integer givenNdim2, integer givenNdim3, MelderArray::kInitializationType initializationType) { // come into existence and manufacture a payload
1136 Melder_assert (givenNdim1 >= 0);
1137 Melder_assert (givenNdim2 >= 0);
1138 Melder_assert (givenNdim3 >= 0);
1139 our cells = MelderArray:: _alloc <T> (givenNdim3 * givenNdim2 * givenNdim1, initializationType);
1140 our ndim1 = givenNdim1;
1141 our ndim2 = givenNdim2;
1142 our ndim3 = givenNdim3;
1143 our stride3 = 1;
1144 our stride2 = givenNdim3;
1145 our stride1 = givenNdim3 * givenNdim2;
1146 }
~autotensor3autotensor31147 ~autotensor3 () { // destroy the payload (if any)
1148 if (our cells)
1149 MelderArray:: _free (our cells, our ndim1 * our ndim2 * our ndim3);
1150 }
1151 //tensor3<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 structure)
getautotensor31152 const tensor3<T>& get () const { return *this; } // let the public use the payload (they may change the values in the cells but not the structure)
adoptFromAmbiguousOwnerautotensor31153 void adoptFromAmbiguousOwner (tensor3<T> const& given) { // buy the payload from a non-automatrix
1154 our reset();
1155 our cells = given.cells;
1156 our ndim1 = given.ndim1;
1157 our ndim2 = given.ndim2;
1158 our ndim3 = given.ndim3;
1159 our stride1 = given.stride1;
1160 our stride2 = given.stride2;
1161 our stride3 = given.stride3;
1162 }
releaseToAmbiguousOwnerautotensor31163 tensor3<T> releaseToAmbiguousOwner () { // sell the payload to a non-automatrix
1164 T * oldCells = our cells;
1165 our cells = nullptr; // disown ourselves, preventing automatic destruction of the payload
1166 return tensor3<T> (oldCells, our ndim1, our ndim2, our ndim3, our stride1, our stride2, our stride3);
1167 }
1168 /*
1169 Disable copying via construction or assignment (which would violate unique ownership of the payload).
1170 */
1171 autotensor3 (const autotensor3&) = delete; // disable copy constructor
1172 autotensor3& operator= (const autotensor3&) = delete; // disable copy assignment
1173 /*
1174 Enable moving of r-values (temporaries, implicitly) or l-values (for variables, via an explicit move()).
1175 This implements buying a payload from another automatrix (which involves destroying our current payload).
1176 */
autotensor3autotensor31177 autotensor3 (autotensor3&& other) noexcept : tensor3<T> (other.get()) { // enable move constructor
1178 other.cells = nullptr; // disown source
1179 other.ndim1 = 0; // to keep the source in a valid state
1180 other.ndim2 = 0; // to keep the source in a valid state
1181 other.ndim3 = 0; // to keep the source in a valid state
1182 }
1183 autotensor3& operator= (autotensor3&& other) noexcept { // enable move assignment
1184 if (other.cells != our cells) {
1185 if (our cells)
1186 MelderArray:: _free (our cells, our ndim1 * our ndim2 * our ndim3);
1187 our cells = other.cells;
1188 our ndim1 = other.ndim1;
1189 our ndim2 = other.ndim2;
1190 our ndim3 = other.ndim3;
1191 other.cells = nullptr; // disown source
1192 other.ndim1 = 0; // to keep the source in a valid state
1193 other.ndim2 = 0; // to keep the source in a valid state
1194 other.ndim3 = 0; // to keep the source in a valid state
1195 } else if (! our cells) {
1196 our ndim1 = other.ndim1; // me and other may or may not be the same object
1197 our ndim2 = other.ndim2;
1198 our ndim3 = other.ndim3;
1199 }
1200 return *this;
1201 }
resetautotensor31202 void reset () noexcept { // on behalf of ambiguous owners (otherwise this could be in autoMAT)
1203 if (our cells) {
1204 MelderArray:: _free (our cells, our ndim1 * our ndim2 * our ndim3);
1205 our cells = nullptr;
1206 }
1207 our ndim1 = 0;
1208 our ndim2 = 0;
1209 our ndim3 = 0;
1210 }
moveautotensor31211 autotensor3&& move () noexcept { return static_cast <autotensor3&&> (*this); }
1212 };
1213 template <typename T>
newtensor3raw(integer ndim1,integer ndim2,integer ndim3)1214 autotensor3<T> newtensor3raw (integer ndim1, integer ndim2, integer ndim3) {
1215 return autotensor3<T> (ndim1, ndim2, ndim3, MelderArray::kInitializationType::RAW);
1216 }
1217 template <typename T>
newtensor3zero(integer ndim1,integer ndim2,integer ndim3)1218 autotensor3<T> newtensor3zero (integer ndim1, integer ndim2, integer ndim3) {
1219 return autotensor3<T> (ndim1, ndim2, ndim3, MelderArray::kInitializationType::ZERO);
1220 }
1221 template <typename T>
tensor3copy(tensor3<T> const & target,consttensor3<T> const & source)1222 void tensor3copy (tensor3<T> const& target, consttensor3<T> const& source) {
1223 Melder_assert (source.ndim1 == target.ndim1 && source.ndim2 == target.ndim2 && source.ndim3 == target.ndim3);
1224 for (integer idim1 = 1; idim1 <= source.ndim1; idim1 ++)
1225 for (integer idim2 = 1; idim2 <= source.ndim2; idim2 ++)
1226 for (integer idim3 = 1; idim3 <= source.ndim3; idim3 ++)
1227 target [idim1] [idim2] [idim3] = source [idim1] [idim2] [idim3];
1228 }
1229 template <typename T>
tensor3copy(tensor3<T> const & target,tensor3<T> const & source)1230 void tensor3copy (tensor3<T> const& target, tensor3<T> const& source) {
1231 tensor3copy (target, consttensor3<T> (source));
1232 }
1233 template <typename T>
newtensor3copy(consttensor3<T> const & source)1234 autotensor3<T> newtensor3copy (consttensor3<T> const& source) {
1235 autotensor3<T> result = newtensor3raw<T> (source.ndim1, source.ndim2, source.ndim3);
1236 tensor3copy (result.get(), source);
1237 return result;
1238 }
1239 template <typename T>
newtensor3copy(tensor3<T> const & source)1240 autotensor3<T> newtensor3copy (tensor3<T> const& source) {
1241 return newtensor3copy<T> (consttensor3<T> (source));
1242 }
1243 template <typename T>
assertDim1(consttensor3<T> const & x,integer dim1)1244 void assertDim1 (consttensor3<T> const& x, integer dim1) {
1245 Melder_assert (dim1 >= 1 && dim1 <= x.ndim1);
1246 }
1247 template <typename T>
assertDim2(consttensor3<T> const & x,integer dim2)1248 void assertDim2 (consttensor3<T> const& x, integer dim2) {
1249 Melder_assert (dim2 >= 1 && dim2 <= x.ndim2);
1250 }
1251 template <typename T>
assertDim3(consttensor3<T> const & x,integer dim3)1252 void assertDim3 (consttensor3<T> const& x, integer dim3) {
1253 Melder_assert (dim3 >= 1 && dim3 <= x.ndim3);
1254 }
1255 template <typename T>
assertCell(consttensor3<T> const & x,integer dim1,integer dim2,integer dim3)1256 void assertCell (consttensor3<T> const& x, integer dim1, integer dim2, integer dim3) {
1257 assertDim1 (x, dim1);
1258 assertDim2 (x, dim2);
1259 assertDim3 (x, dim3);
1260 }
1261 template <typename T>
newtensor3part(consttensor3<T> const & x,integer firstDim1,integer lastDim1,integer firstDim2,integer lastDim2,integer firstDim3,integer lastDim3)1262 autotensor3<T> newtensor3part (consttensor3<T> const& x,
1263 integer firstDim1, integer lastDim1,
1264 integer firstDim2, integer lastDim2,
1265 integer firstDim3, integer lastDim3
1266 ) {
1267 assertCell (x, firstDim1, firstDim2, firstDim3);
1268 assertCell (x, lastDim1, lastDim2, lastDim3);
1269 integer ndim1 = lastDim1 - (firstDim1 - 1);
1270 Melder_assert (ndim1 >= 0);
1271 integer ndim2 = lastDim2 - (firstDim2 - 1);
1272 Melder_assert (ndim2 >= 0);
1273 integer ndim3 = lastDim3 - (firstDim3 - 1);
1274 Melder_assert (ndim3 >= 0);
1275 autotensor3<T> result = newtensor3raw<T> (ndim1, ndim2, ndim3);
1276 for (integer idim1 = 1; idim1 <= ndim1; idim1 ++)
1277 for (integer idim2 = 1; idim2 <= ndim2; idim2 ++)
1278 for (integer idim3 = 1; idim3 <= ndim3; idim3 ++)
1279 result [idim1] [idim2] [idim3] = x [firstDim1 - 1 + idim1] [firstDim2 - 1 + idim2] [firstDim3 - 1 + idim3];
1280 return result;
1281 }
1282 template <typename T>
newtensor3part(tensor3<T> const & x,integer firstDim1,integer lastDim1,integer firstDim2,integer lastDim2,integer firstDim3,integer lastDim3)1283 autotensor3<T> newtensor3part (tensor3<T> const& x,
1284 integer firstDim1, integer lastDim1,
1285 integer firstDim2, integer lastDim2,
1286 integer firstDim3, integer lastDim3
1287 ) {
1288 return newtensor3part (consttensor3<T> (x), firstDim1, lastDim1, firstDim2, lastDim2, firstDim3, lastDim3);
1289 }
1290
1291 /*
1292 instead of vector<double> we say VEC, because we want to have a one-to-one
1293 relation between VEC functions and the scripting language.
1294 For instance, we have raw_VEC and zero_VEC because Praat scripting has raw# and zero#.
1295 */
1296 using VEC = vector <double>;
1297 using VECVU = vectorview <double>;
1298 using constVEC = constvector <double>;
1299 using constVECVU = constvectorview <double>;
1300 using autoVEC = autovector <double>;
raw_VEC(integer size)1301 inline autoVEC raw_VEC (integer size) {
1302 return newvectorraw <double> (size);
1303 }
zero_VEC(integer size)1304 inline autoVEC zero_VEC (integer size) {
1305 return newvectorzero <double> (size);
1306 }
copy_VEC(constVECVU const & source)1307 inline autoVEC copy_VEC (constVECVU const& source) {
1308 return newvectorcopy (source);
1309 }
1310 #define ARRAY_TO_VEC(doubleArray) constVEC (& doubleArray [0], sizeof (doubleArray) / sizeof (double))
1311
1312 /*
1313 And simply because we use vector<integer> so much as well,
1314 we have an abbreviation for that as well, namely INTVEC.
1315 But the scripting language has nothing that corresponds to INTVEC,
1316 so any numeric vector to be used by the scripting language
1317 should be a VEC, even if it contains integers.
1318 This is fine, as a double can contain an integer up to 54 bits.
1319 */
1320 using INTVEC = vector <integer>;
1321 using INTVECVU = vectorview <integer>;
1322 using constINTVEC = constvector <integer>;
1323 using constINTVECVU = constvectorview <integer>;
1324 using autoINTVEC = autovector <integer>;
raw_INTVEC(integer size)1325 inline autoINTVEC raw_INTVEC (integer size) {
1326 return newvectorraw <integer> (size);
1327 }
zero_INTVEC(integer size)1328 inline autoINTVEC zero_INTVEC (integer size) {
1329 return newvectorzero <integer> (size);
1330 }
copy_INTVEC(constINTVECVU const & source)1331 inline autoINTVEC copy_INTVEC (constINTVECVU const& source) {
1332 return newvectorcopy (source);
1333 }
1334 #define ARRAY_TO_INTVEC(integerArray) constINTVEC (& integerArray [0], sizeof (integerArray) / sizeof (integer))
1335
1336
1337 using BOOLVEC = vector <bool>;
1338 using BOOLVECVU = vectorview <bool>;
1339 using constBOOLVEC = constvector <bool>;
1340 using constBOOLVECVU = constvectorview <bool>;
1341 using autoBOOLVEC = autovector <bool>;
raw_BOOLVEC(integer size)1342 inline autoBOOLVEC raw_BOOLVEC (integer size) {
1343 return newvectorraw <bool> (size);
1344 }
zero_BOOLVEC(integer size)1345 inline autoBOOLVEC zero_BOOLVEC (integer size) {
1346 return newvectorzero <bool> (size);
1347 }
copy_BOOLVEC(constBOOLVECVU const & source)1348 inline autoBOOLVEC copy_BOOLVEC (constBOOLVECVU const& source) {
1349 return newvectorcopy (source);
1350 }
1351 #define ARRAY_TO_BOOLVEC(boolArray) constBOOLVEC (& boolArray [0], sizeof (boolArray) / sizeof (bool))
1352
1353 using BYTEVEC = vector <byte>;
1354 using BYTEVECVU = vectorview <byte>;
1355 using constBYTEVEC = constvector <byte>;
1356 using constBYTEVECVU = constvectorview <byte>;
1357 using autoBYTEVEC = autovector <byte>;
raw_BYTEVEC(integer size)1358 inline autoBYTEVEC raw_BYTEVEC (integer size) {
1359 return newvectorraw <byte> (size);
1360 }
zero_BYTEVEC(integer size)1361 inline autoBYTEVEC zero_BYTEVEC (integer size) {
1362 return newvectorzero <byte> (size);
1363 }
copy_BYTEVEC(constBYTEVECVU const & source)1364 inline autoBYTEVEC copy_BYTEVEC (constBYTEVECVU const& source) {
1365 return newvectorcopy (source);
1366 }
1367 #define ARRAY_TO_BYTEVEC(byteArray) constBYTEVEC (& byteArray [0], sizeof (byteArray) / sizeof (byte))
1368
1369 using COMPVEC = vector <dcomplex>;
1370 using COMPVECVU = vectorview <dcomplex>;
1371 using constCOMPVEC = constvector <dcomplex>;
1372 using constCOMPVECVU = constvectorview <dcomplex>;
1373 using autoCOMPVEC = autovector <dcomplex>;
raw_COMPVEC(integer size)1374 inline autoCOMPVEC raw_COMPVEC (integer size) {
1375 return newvectorraw <dcomplex> (size);
1376 }
zero_COMPVEC(integer size)1377 inline autoCOMPVEC zero_COMPVEC (integer size) {
1378 return newvectorzero <dcomplex> (size);
1379 }
copy_COMPVEC(constCOMPVECVU const & source)1380 inline autoCOMPVEC copy_COMPVEC (constCOMPVECVU const& source) {
1381 return newvectorcopy (source);
1382 }
1383 #define ARRAY_TO_COMPVEC(dcomplexArray) constCOMPVEC (& dcomplexArray [0], sizeof (dcomplexArray) / sizeof (dcomplex))
1384
1385 using MAT = matrix <double>;
1386 using MATVU = matrixview <double>;
1387 using constMAT = constmatrix <double>;
1388 using constMATVU = constmatrixview <double>;
1389 using autoMAT = automatrix <double>;
raw_MAT(integer nrow,integer ncol)1390 inline autoMAT raw_MAT (integer nrow, integer ncol) {
1391 return newmatrixraw <double> (nrow, ncol);
1392 }
zero_MAT(integer nrow,integer ncol)1393 inline autoMAT zero_MAT (integer nrow, integer ncol) {
1394 return newmatrixzero <double> (nrow, ncol);
1395 }
copy_MAT(constMATVU const & source)1396 inline autoMAT copy_MAT (constMATVU const& source) {
1397 return newmatrixcopy (source);
1398 }
part_MAT(constMAT const & source,integer firstRow,integer lastRow,integer firstColumn,integer lastColumn)1399 inline autoMAT part_MAT (constMAT const& source,
1400 integer firstRow, integer lastRow,
1401 integer firstColumn, integer lastColumn
1402 ) {
1403 return newmatrixpart (source, firstRow, lastRow, firstColumn, lastColumn);
1404 }
1405
1406 using TEN3 = tensor3 <double>;
1407 using constTEN3 = consttensor3 <double>;
1408 using autoTEN3 = autotensor3 <double>;
raw_TEN3(integer ndim1,integer ndim2,integer ndim3)1409 inline autoTEN3 raw_TEN3 (integer ndim1, integer ndim2, integer ndim3) {
1410 return newtensor3raw <double> (ndim1, ndim2, ndim3);
1411 }
zero_TEN3(integer ndim1,integer ndim2,integer ndim3)1412 inline autoTEN3 zero_TEN3 (integer ndim1, integer ndim2, integer ndim3) {
1413 return newtensor3zero <double> (ndim1, ndim2, ndim3);
1414 }
copy_TEN3(constTEN3 source)1415 inline autoTEN3 copy_TEN3 (constTEN3 source) {
1416 return newtensor3copy (source);
1417 }
part_TEN3(const constTEN3 & source,integer firstDim1,integer lastDim1,integer firstDim2,integer lastDim2,integer firstDim3,integer lastDim3)1418 inline autoTEN3 part_TEN3 (const constTEN3& source,
1419 integer firstDim1, integer lastDim1,
1420 integer firstDim2, integer lastDim2,
1421 integer firstDim3, integer lastDim3
1422 ) {
1423 return newtensor3part (source, firstDim1, lastDim1, firstDim2, lastDim2, firstDim3, lastDim3);
1424 }
1425
1426 using INTMAT = matrix <integer>;
1427 using INTMATVU = matrixview <integer>;
1428 using constINTMAT = constmatrix <integer>;
1429 using constINTMATVU = constmatrixview <integer>;
1430 using autoINTMAT = automatrix <integer>;
raw_INTMAT(integer nrow,integer ncol)1431 inline autoINTMAT raw_INTMAT (integer nrow, integer ncol) {
1432 return newmatrixraw <integer> (nrow, ncol);
1433 }
zero_INTMAT(integer nrow,integer ncol)1434 inline autoINTMAT zero_INTMAT (integer nrow, integer ncol) {
1435 return newmatrixzero <integer> (nrow, ncol);
1436 }
copy_INTMAT(constINTMATVU source)1437 inline autoINTMAT copy_INTMAT (constINTMATVU source) {
1438 return newmatrixcopy (source);
1439 }
1440
1441 using BOOLMAT = matrix <bool>;
1442 using BOOLMATVU = matrixview <bool>;
1443 using constBOOLMAT = constmatrix <bool>;
1444 using constBOOLMATVU = constmatrixview <bool>;
1445 using autoBOOLMAT = automatrix <bool>;
raw_BOOLMAT(integer nrow,integer ncol)1446 inline autoBOOLMAT raw_BOOLMAT (integer nrow, integer ncol) {
1447 return newmatrixraw <bool> (nrow, ncol);
1448 }
zero_BOOLMAT(integer nrow,integer ncol)1449 inline autoBOOLMAT zero_BOOLMAT (integer nrow, integer ncol) {
1450 return newmatrixzero <bool> (nrow, ncol);
1451 }
copy_BOOLMAT(constBOOLMATVU source)1452 inline autoBOOLMAT copy_BOOLMAT (constBOOLMATVU source) {
1453 return newmatrixcopy (source);
1454 }
1455
1456 using BYTEMAT = matrix <byte>;
1457 using BYTEMATVU = matrixview <byte>;
1458 using constBYTEMAT = constmatrix <byte>;
1459 using constBYTEMATVU = constmatrixview <byte>;
1460 using autoBYTEMAT = automatrix <byte>;
raw_BYTEMAT(integer nrow,integer ncol)1461 inline autoBYTEMAT raw_BYTEMAT (integer nrow, integer ncol) {
1462 return newmatrixraw <byte> (nrow, ncol);
1463 }
zero_BYTEMAT(integer nrow,integer ncol)1464 inline autoBYTEMAT zero_BYTEMAT (integer nrow, integer ncol) {
1465 return newmatrixzero <byte> (nrow, ncol);
1466 }
copy_BYTEMAT(constBYTEMATVU source)1467 inline autoBYTEMAT copy_BYTEMAT (constBYTEMATVU source) {
1468 return newmatrixcopy (source);
1469 }
1470
1471 conststring32 Melder_VEC (constVECVU const& value);
1472 conststring32 Melder_MAT (constMATVU const& value);
1473
1474 inline void operator<<= (INTVECVU const& target, constINTVECVU const& source) {
1475 Melder_assert (target.size == source.size);
1476 for (integer i = 1; i <= target.size; i ++)
1477 target [i] = source [i];
1478 }
1479 inline void operator<<= (BOOLVECVU const& target, constBOOLVECVU const& source) {
1480 Melder_assert (target.size == source.size);
1481 for (integer i = 1; i <= target.size; i ++)
1482 target [i] = source [i];
1483 }
1484 inline void operator<<= (TEN3 const& target, constTEN3 const& source) {
1485 Melder_assert (target.ndim1 == source.ndim1);
1486 Melder_assert (target.ndim2 == source.ndim2);
1487 Melder_assert (target.ndim3 == source.ndim3);
1488 for (integer idim1 = 1; idim1 <= target.ndim1; idim1 ++)
1489 for (integer idim2 = 1; idim2 <= target.ndim2; idim2 ++)
1490 for (integer idim3 = 1; idim3 <= target.ndim3; idim3 ++)
1491 target [idim1] [idim2] [idim3] = source [idim1] [idim2] [idim3];
1492 }
1493
1494 /* End of file melder_tensor.h */
1495 #endif
1496