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