AFLOW
 
Loading...
Searching...
No Matches
aurostd_xtensor.cpp
Go to the documentation of this file.
1//****************************************************************************
2// * *
3// * Aflow STEFANO CURTAROLO - Duke University 2003-2024 *
4// * Aflow MARCO ESTERS - Duke University 2018-2021 *
5// * *
6//****************************************************************************
7//
8// This class implements n-dimensional tensors using a 1D array to mimic a
9// tensor. See aurostd_xtensor.h for descriptions of the class attributes.
10
11#ifndef _AUROSTD_XTENSOR_CPP_
12#define _AUROSTD_XTENSOR_CPP_
13
14#include "aurostd_xtensor.h"
15
16#include <cstddef>
17#include <iostream>
18#include <ostream>
19#include <sstream>
20#include <string>
21#include <vector>
22
23#include "aurostd.h"
25#include "aurostd_xerror.h"
26#include "aurostd_xmatrix.h"
27#include "aurostd_xscalar.h"
28#include "aurostd_xvector.h"
29
30#include "aflow_xhost.h" // todo required for XHOST.DEBUG use
31
32#define _DEBUG_XTENSOR_ false
33
34// _CHECK_BOUNDS_ defines whether a bounds check is performed when indexing an
35// xtensor. While it is safe to set it to true, it greatly impact performance
36// It is recommended to uncomment the line below when testing new code and set
37// comment it out once the code it working.
38// #define _CHECK_BOUNDS_
39
40static const std::string _SUBTENSOR_ERR_PREFIX_ = "aurostd::_subtensor::";
41static const std::string _XTENSOR_ERR_PREFIX_ = "aurostd::xtensor::";
42
43using aurostd::xerror;
44
45/********************************* SUBTENSOR ********************************/
46// Helper class for indexing of xtensor. Indexing xtensor is performed by
47// storing the indices subsequently into _subtensor and then by using the
48// assignment operator or type casting (see conversion operators).
49//
50// The indices in _subtensor must be 0-based, so they need to be converted
51// before being passed into the constructor or appended to the indices vector.
52namespace aurostd {
53
54 // Constructors////////////////////////////////////////////////////////////////
55 template <class utype> _subtensor<utype>::_subtensor(const int& i, utype* crp, const xtensor<utype>& tnsr) : _tensor(tnsr) {
56 indexed_dim = 1;
57 shift = (i - _tensor.lindex[0]) * _tensor.shifts[0];
58 corpus = crp;
59 }
60#define AST_TEMPLATE(utype) template _subtensor<utype>::_subtensor(const int&, utype*, const xtensor<utype>&);
62#undef AST_TEMPLATE
63
64 template <class utype> _subtensor<utype>::_subtensor(const std::vector<int>& ind, utype* crp, const xtensor<utype>& tnsr) : _tensor(tnsr) {
65 const uint isize = ind.size();
66 indexed_dim = isize;
67 shift = 0;
68 for (uint i = 0; i < isize; i++) {
69 shift += (ind[i] - _tensor.lindex[i]) * _tensor.shifts[i];
70 }
71 corpus = crp;
72 }
73#define AST_TEMPLATE(utype) template _subtensor<utype>::_subtensor(const std::vector<int>&, utype*, const xtensor<utype>&);
75#undef AST_TEMPLATE
77 template <class utype> _subtensor<utype>::_subtensor(const aurostd::xvector<int>& ind, utype* crp, const xtensor<utype>& tnsr) : _tensor(tnsr) {
79 shift = 0;
80 for (int i = 0, ixvec = ind.lrows; ixvec <= ind.urows; i++, ixvec++) {
81 shift += (ind[ixvec] - _tensor.lindex[i]) * _tensor.shifts[i];
82 }
83 corpus = crp;
84 }
85#define AST_TEMPLATE(utype) template _subtensor<utype>::_subtensor(const aurostd::xvector<int>&, utype*, const xtensor<utype>&);
87#undef AST_TEMPLATE
88
89 // Destructor//////////////////////////////////////////////////////////////////
90 template <class utype> _subtensor<utype>::~_subtensor() {}
91#define AST_TEMPLATE(utype) template _subtensor<utype>::~_subtensor();
93#undef AST_TEMPLATE
94
95 // Indexing operator///////////////////////////////////////////////////////////
96 template <class utype> _subtensor<utype>& _subtensor<utype>::operator[](const int& i) {
97#ifdef _CHECK_BOUNDS_
98 std::stringstream message;
99 if (indexed_dim == _tensor.ndim) {
100 message << "Cannot subscribe tensor any further (tensor size: " << _tensor.ndim << ").";
102 } else if ((i < _tensor.lindex[indexed_dim]) || (i > _tensor.uindex[indexed_dim])) {
103 message << "Index " << i << " out of bounds for dimension " << (indexed_dim);
104 message << " (lindex = " << _tensor.lindex[indexed_dim] << ", uindex = ";
105 message << _tensor.uindex[indexed_dim] << ")";
108#endif
109 shift += (i - _tensor.lindex[indexed_dim]) * _tensor.shifts[indexed_dim];
110 indexed_dim++;
111 return *this;
113#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator[](const int&);
115#undef AST_TEMPLATE
117 template <class utype> _subtensor<utype>& _subtensor<utype>::operator()(const std::vector<int>& ind) {
118 const uint isize = ind.size();
119#ifdef _CHECK_BOUNDS_
120 std::stringstream message;
121 if (indexed_dim + isize > _tensor.ndim) {
122 message << "Too many indices for tensor with " << _tensor.ndim << " dimensions";
123 message << " (" << (indexed_dim + isize) << " provided).";
125 }
126#endif
127 for (uint i = 0; i < isize; i++) {
128#ifdef _CHECK_BOUNDS_
129 if ((ind[i] < _tensor.lindex[i + indexed_dim]) || (ind[i] > _tensor.uindex[i + indexed_dim])) {
130 message << "Index " << ind[i] << " out of bounds for dimension " << (i + indexed_dim);
131 message << " (lindex = " << _tensor.lindex[i + indexed_dim];
132 message << ", uindex = " << _tensor.uindex[i + indexed_dim] << ")";
134 }
135#endif
136 shift += (ind[i] - _tensor.lindex[indexed_dim]) * _tensor.shifts[indexed_dim];
137 indexed_dim++;
138 }
139 return *this;
140 }
141#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator()(const std::vector<int>&);
143#undef AST_TEMPLATE
144
146#ifdef _CHECK_BOUNDS_
147 std::stringstream message;
148 if (indexed_dim + ind.rows > _tensor.ndim) {
149 message << "Too many indices for tensor with " << _tensor.ndim << " dimensions";
150 message << " (" << (indexed_dim + ind.rows) << " provided).";
152 }
153#endif
154 for (int i = ind.lrows; i <= ind.urows; i++) {
155#ifdef _CHECK_BOUNDS_
156 if ((ind[i] < _tensor.lindex[indexed_dim]) || (ind[i] > _tensor.uindex[indexed_dim])) {
157 message << "Index " << ind[i] << " out of bounds for dimension " << indexed_dim;
158 message << " (lindex = " << _tensor.lindex[indexed_dim];
159 message << ", uindex = " << _tensor.uindex[indexed_dim] << ")";
161 }
162#endif
163 shift += (ind[i] - _tensor.lindex[indexed_dim]) * _tensor.shifts[indexed_dim];
164 indexed_dim++;
165 }
166 return *this;
167 }
168#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator()(const aurostd::xvector<int>&);
170#undef AST_TEMPLATE
171
172 template <class utype> void _subtensor<utype>::set(const utype& val) {
173 const int n = getNumElements();
174 for (int s = 0; s < n; s++) {
175 corpus[shift + s] = val;
176 }
177 }
178#define AST_TEMPLATE(utype) template void _subtensor<utype>::set(const utype&);
180#undef AST_TEMPLATE
181
182 template <class utype> void _subtensor<utype>::set(const utype& val, const int& i) {
183 corpus[i] = val;
184 }
185#define AST_TEMPLATE(utype) template void _subtensor<utype>::set(const utype&, const int&);
187#undef AST_TEMPLATE
188
189 template <class utype> utype _subtensor<utype>::get(const int& i) const {
190 return corpus[i];
191 }
192#define AST_TEMPLATE(utype) template utype _subtensor<utype>::get(const int&) const;
194#undef AST_TEMPLATE
195
196 // BEGIN Operators
197 // Unary operators/////////////////////////////////////////////////////////////
199 template <class utype> _subtensor<utype>& _subtensor<utype>::operator+=(utype scalar) {
200 if (indexed_dim == _tensor.ndim) {
201 corpus[shift] += scalar;
202 } else {
203 const int n = getNumElements();
204 for (int s = 0; s < n; s++) {
205 corpus[shift + s] += scalar;
206 }
207 }
208 return *this;
209 }
210#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator+=(utype);
212#undef AST_TEMPLATE
213
214 template <class utype> _subtensor<utype>& _subtensor<utype>::operator-=(utype scalar) {
215 if (indexed_dim == _tensor.ndim) {
216 corpus[shift] -= scalar;
217 } else {
218 const int n = getNumElements();
219 for (int s = 0; s < n; s++) {
220 corpus[shift + s] -= scalar;
221 }
222 }
223 return *this;
224 }
225#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator-=(utype);
227#undef AST_TEMPLATE
228
229 template <class utype> _subtensor<utype>& _subtensor<utype>::operator*=(utype scalar) {
230 if (indexed_dim == _tensor.ndim) {
231 corpus[shift] *= scalar;
232 } else {
233 const int n = getNumElements();
234 for (int s = 0; s < n; s++) {
235 corpus[shift + s] *= scalar;
236 }
237 }
238 return *this;
239 }
240#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator*=(utype);
242#undef AST_TEMPLATE
243
244 template <class utype> _subtensor<utype>& _subtensor<utype>::operator/=(utype scalar) {
245 if (indexed_dim == _tensor.ndim) {
246 corpus[shift] /= scalar;
247 } else {
248 const int n = getNumElements();
249 for (int s = 0; s < n; s++) {
250 corpus[shift + s] /= scalar;
251 }
252 }
253 return *this;
254 }
255#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator/=(utype);
257#undef AST_TEMPLATE
258
260
262
264 if (sameShape(st)) {
265 if (indexed_dim == _tensor.ndim) {
266 corpus[shift] += st.get(st.shift);
267 } else {
268 const int n = getNumElements();
269 for (int s = 0; s < n; s++) {
270 corpus[shift + s] += st.get(st.shift + s);
271 }
272 }
273 } else {
274 const std::string message = "Subtensors have different shapes.";
276 }
277 return *this;
278 }
279#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator+=(const _subtensor<utype>&);
281#undef AST_TEMPLATE
282
284 if (sameShape(st)) {
285 if (indexed_dim == _tensor.ndim) {
286 corpus[shift] -= st.corpus[st.shift];
287 } else {
288 const int n = getNumElements();
289 for (int s = 0; s < n; s++) {
290 corpus[shift + s] -= st.get(st.shift + s);
291 }
292 }
293 } else {
294 const std::string message = "Subtensors have different shapes.";
296 }
297 return *this;
298 }
299#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator-=(const _subtensor<utype>&);
301#undef AST_TEMPLATE
302
303 template <class utype> _subtensor<utype>& _subtensor<utype>::operator+=(const xtensor<utype>& tensor) {
304 if (sameShape(tensor)) {
305 if (indexed_dim == _tensor.ndim) {
306 corpus[shift] += tensor[0];
307 } else {
308 for (int i = 0; i < tensor.nelements; i++) {
309 corpus[shift + i] += tensor.get(i);
310 }
311 }
312 } else {
313 const std::string message = "Subtensor and tensor have different shapes.";
315 }
316 return *this;
317 }
318#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator+=(const xtensor<utype>&);
320#undef AST_TEMPLATE
321
322 template <class utype> _subtensor<utype>& _subtensor<utype>::operator-=(const xtensor<utype>& tensor) {
323 if (sameShape(tensor)) {
324 if (indexed_dim == _tensor.ndim) {
325 corpus[shift] -= tensor[0];
326 } else {
327 for (int i = 0; i < tensor.nelements; i++) {
328 corpus[shift + i] -= tensor.get(i);
329 }
330 }
331 } else {
332 const std::string message = "Subtensor and tensor have different shapes.";
334 }
335 return *this;
336 }
337#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator-=(const xtensor<utype>&);
339#undef AST_TEMPLATE
340
342
344
345 template <class utype> xtensor<utype> operator+(const _subtensor<utype>& st) {
346 return xtensor<utype>(st);
347 }
348#define AST_TEMPLATE(utype) template xtensor<utype> operator+(const _subtensor<utype>&);
350#undef AST_TEMPLATE
351
352 template <class utype> xtensor<utype> operator-(const _subtensor<utype>& st) {
353 const xtensor<utype> tensor(st);
354 return -tensor;
355 }
356#define AST_TEMPLATE(utype) template xtensor<utype> operator-(const _subtensor<utype>&);
358#undef AST_TEMPLATE
359
361
362 // Conversion operators////////////////////////////////////////////////////////
363 // Converts a _subtensor into utype to be assigned to a utype variable. For
364 // the conversion of _subtensor into xtensor, see the (copy) constructor for
365 // xtensor.
366 template <class utype> _subtensor<utype>::operator utype() const {
367 return corpus[shift];
368 }
369#define AST_TEMPLATE(utype) template _subtensor<utype>::operator utype() const;
371#undef AST_TEMPLATE
372
373 // Assigns a utype to an xtensor element
374 template <class utype> _subtensor<utype>& _subtensor<utype>::operator=(const utype& val) {
375 if (indexed_dim == _tensor.ndim) {
376 set(val, shift);
377 // Exception handling
378 } else {
379 std::stringstream message;
380 message << "Cannot assign single value to tensor of size " << (_tensor.ndim - indexed_dim) << ".";
382 }
383 return *this;
384 }
385#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator=(const utype&);
387#undef AST_TEMPLATE
388
389 // Assigns a subtensor to another subtensor
391 if (sameShape(st)) {
392 const int end = _tensor.shifts[indexed_dim - 1] + shift;
393 for (int i = shift, ist = st.shift; i < end; i++, ist++) {
394 corpus[i] = st.get(ist);
395 }
396 } else {
397 const std::string message = "Subtensors have different shapes.";
399 }
400 return *this;
401 }
402#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator=(const _subtensor<utype>&);
404#undef AST_TEMPLATE
405
406 // Assigns a tensor to a subtensor
407 template <class utype> _subtensor<utype>& _subtensor<utype>::operator=(const xtensor<utype>& tensor) {
408 if (sameShape(tensor)) {
409 for (int i = 0, ist = shift; i < tensor.nelements; i++, ist++) {
410 corpus[ist] = tensor.get(i);
411 }
412 } else {
413 const std::string message = "Subtensor and tensor have different shapes.";
415 }
416 return *this;
417 }
418#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator=(const xtensor<utype>&);
420#undef AST_TEMPLATE
421
422 // Assigns a vector to a 1D slice of a tensor
423 template <class utype> _subtensor<utype>& _subtensor<utype>::operator=(const std::vector<utype>& vec) {
424 bool throw_exception = false;
425 std::stringstream message;
426 // Slice must be 1D
427 if (indexed_dim == (_tensor.ndim - 1)) {
428 // Tensor slice and vector must have same size
429 const int vsize = (int) vec.size();
430 if (vsize == _tensor.shape[indexed_dim]) {
431 for (int i = 0, ist = shift; i < vsize; i++, ist++) {
432 corpus[ist] = vec[i];
433 }
434 // Exception handling.
435 } else {
436 throw_exception = true;
437 message << "Tensor slice and vector have different sizes. ";
438 message << "Size of tensor slice: " << _tensor.shape[indexed_dim] << "; ";
439 message << "size of vector: " << vec.size() << ".";
440 }
441 } else {
442 throw_exception = true;
443 message << "Tensor slice must be 1D to assign vector (is " << (_tensor.ndim - indexed_dim) << "D).";
444 }
445 if (throw_exception) {
447 }
448 return *this;
449 }
450#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator=(const std::vector<utype>&);
452#undef AST_TEMPLATE
453
454 // Assigns an xvector to a 1D slice of a tensor
456 bool throw_exception = false;
457 std::stringstream message;
458 // Tensor slice must be 1D
459 if (indexed_dim == (_tensor.ndim - 1)) {
460 // Tensor slice and xvector must have same size
461 if (xvec.rows == _tensor.shape[indexed_dim]) {
462 for (int i = xvec.lrows, ist = shift; i <= xvec.urows; i++, ist++) {
463 corpus[ist] = xvec[i];
464 }
465 // Exception handling
466 } else {
467 throw_exception = true;
468 message << "Tensor slice and xvector have different sizes. ";
469 message << "Size of tensor slice: " << _tensor.shape[indexed_dim] << "; ";
470 message << "size of xvector: " << xvec.rows << ".";
471 }
472 } else {
473 throw_exception = true;
474 message << "Tensor slice must be 1D to assign xvector (is " << (_tensor.ndim - indexed_dim) << "D).";
475 }
476 if (throw_exception) {
478 }
479 return *this;
480 }
481#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator=(const aurostd::xvector<utype>&);
483#undef AST_TEMPLATE
484
485 // Assigns an xmatrix to a 2D slice of a tensor
487 bool throw_exception = false;
488 std::stringstream message;
489 // Tensor slice must be 2D
490 if (indexed_dim == (_tensor.ndim - 2)) {
491 // Tensor slice must have same shape as matrix
492 if ((xmat.rows == _tensor.shape[indexed_dim]) && (xmat.cols == _tensor.shape[indexed_dim + 1])) {
493 for (int i = xmat.lrows; i <= xmat.urows; i++) {
494 for (int j = xmat.lcols; j <= xmat.ucols; j++) {
495 corpus[shift] = xmat[i][j];
496 shift++;
497 }
498 }
499 } else {
500 throw_exception = true;
501 message << "Tensor slice and xmatrix have different shapes. ";
502 message << "Shape of tensor slice: (" << _tensor.shape[indexed_dim] << ", " << _tensor.shape[indexed_dim + 1] << "); ";
503 message << "shape of xmatrix: (" << xmat.rows << ", " << xmat.cols << ").";
504 }
505 } else {
506 throw_exception = true;
507 message << "Tensor slice must be 2D to assign xmatrix (is " << (_tensor.ndim - indexed_dim) << "D).";
508 }
509 if (throw_exception) {
511 }
512 return *this;
513 }
514#define AST_TEMPLATE(utype) template _subtensor<utype>& _subtensor<utype>::operator=(const aurostd::xmatrix<utype>&);
516#undef AST_TEMPLATE
517 // END Operators
518
519 // BEGIN Helper functions
520 // getNumElements//////////////////////////////////////////////////////////////
521 template <class utype> int _subtensor<utype>::getNumElements() const {
522 int n = 1;
523 for (uint i = indexed_dim; i < _tensor.ndim; i++) {
524 n *= _tensor.shape[i];
525 }
526 return n;
527 }
528#define AST_TEMPLATE(utype) template int _subtensor<utype>::getNumElements() const;
530#undef AST_TEMPLATE
531
532 // sameShape///////////////////////////////////////////////////////////////////
533 template <class utype> bool _subtensor<utype>::sameShape(const _subtensor<utype>& st) {
534 const uint size1 = _tensor.ndim - indexed_dim;
535 const uint size2 = st._tensor.ndim - st.indexed_dim;
536 if (size1 != size2) {
537 return false;
538 } else {
539 const int diff = (int) (size2 - size1);
540 for (uint i = indexed_dim; i < _tensor.ndim; i++) {
541 if (_tensor.shape[i] != st._tensor.shape[i + diff]) {
542 return false;
543 }
544 }
545 }
546 return true;
547 }
548#define AST_TEMPLATE(utype) template bool _subtensor<utype>::sameShape(const _subtensor<utype>&);
550#undef AST_TEMPLATE
551
552 template <class utype> bool _subtensor<utype>::sameShape(const xtensor<utype>& tensor) {
553 const uint size = _tensor.ndim - indexed_dim;
554 if (size != tensor.ndim) {
555 return false;
556 } else {
557 for (uint i = 0; i < size; i++) {
558 if (_tensor.shape[i + indexed_dim] != tensor.shape[i]) {
559 return false;
560 }
561 }
562 }
563 return true;
564 }
565#define AST_TEMPLATE(utype) template bool _subtensor<utype>::sameShape(const xtensor<utype>&);
567#undef AST_TEMPLATE
568
569 // END Helper functions
570} // namespace aurostd
571
572/******************************* END SUBTENSOR ******************************/
573
574/********************************** XTENSOR *********************************/
575// The xtensor class. As with xvector and xmatrix, xtensors are initialized
576// upper indices (uind/uindex) and the lower indices (lind/lindex), and the
577// default indexing is 1-based. uindex and lindex can be provided using
578// (x)vectors or an integer describing the number of dimensions and the lower
579// index for all dimensions (default 1).
580namespace aurostd {
581
582 // BEGIN Constructors/Destructors
583 // Constructors////////////////////////////////////////////////////////////////
584 template <class utype> xtensor<utype>::xtensor() { // Default constructor
585 const std::vector<int> uind(3, 3);
586 const std::vector<int> lind(3, 1);
587 buildTensor(uind, lind);
588 }
589#define AST_TEMPLATE(utype) template xtensor<utype>::xtensor();
591#undef AST_TEMPLATE
592
593 template <class utype> xtensor<utype>::xtensor(const std::vector<int>& uind) {
594 const std::vector<int> lind(uind.size(), 1);
595 buildTensor(uind, lind);
596 }
597#define AST_TEMPLATE(utype) template xtensor<utype>::xtensor(const std::vector<int>&);
599#undef AST_TEMPLATE
600
601 template <class utype> xtensor<utype>::xtensor(const std::vector<int>& uind, const std::vector<int>& lind) {
602 buildTensor(uind, lind);
603 }
604#define AST_TEMPLATE(utype) template xtensor<utype>::xtensor(const std::vector<int>&, const std::vector<int>&);
606#undef AST_TEMPLATE
607
608 template <class utype> xtensor<utype>::xtensor(const aurostd::xvector<int>& xuind) {
609 const std::vector<int> uind = aurostd::xvector2vector(xuind);
610 const std::vector<int> lind(uind.size(), 1);
611 buildTensor(uind, lind);
612 }
613#define AST_TEMPLATE(utype) template xtensor<utype>::xtensor(const aurostd::xvector<int>&);
615#undef AST_TEMPLATE
616
617 template <class utype> xtensor<utype>::xtensor(const aurostd::xvector<int>& xuind, const aurostd::xvector<int>& xlind) {
618 const std::vector<int> uind = aurostd::xvector2vector(xuind);
619 const std::vector<int> lind = aurostd::xvector2vector(xlind);
620 buildTensor(uind, lind);
621 }
622#define AST_TEMPLATE(utype) template xtensor<utype>::xtensor(const aurostd::xvector<int>&, const aurostd::xvector<int>&);
624#undef AST_TEMPLATE
625
626 template <class utype> xtensor<utype>::xtensor(const int& ui, const int& li) {
627 // Creates a tensor with (ui-li + 1) dimensions of size (ui-li). For example,
628 // a 3x3x3 tensor would be xtensor(3) (1-based) or xtensor(2, 0) (0-based).
629 const int n = ui - li + 1;
630 const std::vector<int> uind(n, n);
631 const std::vector<int> lind(n, li);
632 buildTensor(uind, lind);
633 }
634#define AST_TEMPLATE(utype) template xtensor<utype>::xtensor(const int&, const int&);
636#undef AST_TEMPLATE
637
638 template <class utype> xtensor<utype>::xtensor(const _subtensor<utype>& st) {
639 std::vector<int> uind;
640 std::vector<int> lind;
641 if (st.indexed_dim == st._tensor.ndim) {
642 uind.resize(1, 1);
643 lind.resize(1, st._tensor.lindex[st._tensor.ndim - 1]);
644 } else {
645 const int size = (int) st._tensor.ndim - st.indexed_dim;
646 uind.resize(size);
647 lind.resize(size);
648 for (int i = 0; i < size; i++) {
649 uind[i] = st._tensor.uindex[i + st.indexed_dim];
650 lind[i] = st._tensor.lindex[i + st.indexed_dim];
651 }
652 }
653 buildTensor(uind, lind);
654 const int end = st.shift + st._tensor.shifts[st.indexed_dim - 1];
655 for (int i = 0, ist = st.shift; ist < end; i++, ist++) {
656 corpus[i] = st.get(ist);
657 }
658 }
659#define AST_TEMPLATE(utype) template xtensor<utype>::xtensor(const _subtensor<utype>&);
661#undef AST_TEMPLATE
662
663 // buildTensor/////////////////////////////////////////////////////////////////
664 template <class utype> void xtensor<utype>::buildTensor(const std::vector<int>& uind, const std::vector<int>& lind) {
665 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
666 if (checkInit(uind, lind)) {
667 ndim = uind.size();
668 uindex = new int[ndim];
669 lindex = new int[ndim];
670 shape = new int[ndim];
671 shifts = new int[ndim];
672
673 for (uint i = 0; i < ndim; i++) {
674 uindex[i] = uind[i];
675 lindex[i] = lind[i];
676 shape[i] = uindex[i] - lindex[i] + 1;
677 shifts[i] = 1;
678 }
679
680 if (LDEBUG) {
681 std::cerr << _XTENSOR_ERR_PREFIX_ << "buildTensor - Tensor dimensions:";
682 for (uint i = 0; i < ndim; i++) {
683 std::cerr << " " << shape[i];
684 }
685 std::cerr << std::endl;
686 }
687
688 for (uint s = 0; s < ndim - 1; s++) {
689 for (uint i = s + 1; i < ndim; i++) {
690 shifts[s] *= shape[i];
691 }
692 }
693
694 // Special case for a 0D tensor
695 if ((uind.size() == 1) && ((uindex[0] - lindex[0]) == 0)) {
696 ndim = 0;
697 }
698
699 if (ndim < 2) {
700 is_cubic = false;
701 } else {
702 is_cubic = true;
703 for (uint i = 1; i < ndim; i++) {
704 if (shape[i] != shape[i - 1]) {
705 is_cubic = false;
706 i = ndim;
707 }
708 }
709 }
710
711 nelements = 1;
712 for (uint i = 0; i < ndim; i++) {
713 nelements *= shape[i];
714 }
715
716 size = (char) (sizeof(utype));
717 tsize = (long int) size * nelements;
718
719 corpus = new utype[nelements];
720 for (int i = 0; i < nelements; i++) {
721 corpus[i] = (utype) 0;
722 }
723
724 if (LDEBUG) {
725 std::cerr << "is_cubic = " << ((is_cubic) ? "true" : "false");
726 std::cerr << ", sizeof = " << size << ", tsize = " << tsize << std::endl;
727 }
728 if (!corpus) {
729 const std::string message = "Allocation failure in xtensor constructor.";
731 }
732 // Exception handling
733 } else {
734 tsize = 0; // For destructor
735 std::stringstream message;
736 int code;
737 if (uind.size() != lind.size()) {
738 message << "uindex and lindex are of different size.";
739 code = _INDEX_MISMATCH_;
740 } else {
741 if (uind.empty() || lind.empty()) {
742 message << "Cannot initialize tensor with empty vector.";
743 } else {
744 message << "Vector describing tensor indices contains illegal values (uindex < lindex).";
745 }
746 code = _INDEX_ILLEGAL_;
747 }
748 throw xerror(__AFLOW_FILE__, __AFLOW_FUNC__, message, code);
749 }
750 }
751#define AST_TEMPLATE(utype) template void xtensor<utype>::buildTensor(const std::vector<int>&, const std::vector<int>&);
753#undef AST_TEMPLATE
754
755 // Copy Constructors///////////////////////////////////////////////////////////
756 template <class utype> xtensor<utype>::xtensor(const xtensor<utype>& that) {
757 is_cubic = that.is_cubic;
758 nelements = that.nelements;
759 ndim = that.ndim;
760 tsize = that.tsize;
761
762 uindex = new int[ndim];
763 lindex = new int[ndim];
764 shape = new int[ndim];
765 shifts = new int[ndim];
766 for (uint i = 0; i < ndim; i++) {
767 uindex[i] = that.uindex[i];
768 lindex[i] = that.lindex[i];
769 shape[i] = that.shape[i];
770 shifts[i] = that.shifts[i];
771 }
772
773 corpus = new utype[nelements];
774 for (int i = 0; i < nelements; i++) {
775 corpus[i] = that.corpus[i];
776 }
777 }
778#define AST_TEMPLATE(utype) template xtensor<utype>::xtensor(const xtensor<utype>&);
780#undef AST_TEMPLATE
781
782 template <class utype> xtensor<utype> xtensor<utype>::operator=(const xtensor<utype>& that) {
783 if (corpus != that.corpus) {
784 is_cubic = that.is_cubic;
785 ndim = that.ndim;
786 nelements = that.nelements;
787 size = that.size;
788 tsize = that.tsize;
789
790 delete[] (uindex);
791 delete[] (lindex);
792 delete[] (shape);
793 delete[] (shifts);
794 uindex = new int[ndim];
795 lindex = new int[ndim];
796 shape = new int[ndim];
797 shifts = new int[ndim];
798 for (uint i = 0; i < ndim; i++) {
799 uindex[i] = that.uindex[i];
800 lindex[i] = that.lindex[i];
801 shape[i] = that.shape[i];
802 shifts[i] = that.shifts[i];
803 }
804
805 delete[] (corpus);
806 corpus = new utype[nelements];
807 for (int i = 0; i < nelements; i++) {
808 corpus[i] = that.corpus[i];
809 }
810 }
811 return *this;
812 }
813#define AST_TEMPLATE(utype) template xtensor<utype> xtensor<utype>::operator=(const xtensor<utype>&);
815#undef AST_TEMPLATE
816
818 const xtensor<utype> tensor(st);
819 *this = tensor;
820 return *this;
821 }
822#define AST_TEMPLATE(utype) template xtensor<utype> xtensor<utype>::operator=(const _subtensor<utype>&);
824#undef AST_TEMPLATE
825
826 // Destructor//////////////////////////////////////////////////////////////////
827 template <class utype> xtensor<utype>::~xtensor() {
828 if (tsize > 0) {
829 delete[] (corpus);
830 delete[] (shape);
831 delete[] (uindex);
832 delete[] (lindex);
833 delete[] (shifts);
834 }
835 }
836#define AST_TEMPLATE(utype) template xtensor<utype>::~xtensor();
838#undef AST_TEMPLATE
839 // END Constructors/Destructors
840
841 // BEGIN helper functions
842 // checkInit///////////////////////////////////////////////////////////////////
843 // helper function for the constructor to test the validity of the input std::vector
844 template <class utype> bool xtensor<utype>::checkInit(const std::vector<int>& uind, const std::vector<int>& lind) {
845 if (uind.size() != lind.size()) {
846 return false;
847 }
848 if (uind.empty() || lind.empty()) {
849 return false;
850 }
851 for (size_t i = 0; i < uind.size(); i++) {
852 if (uind[i] < lind[i]) {
853 return false;
854 }
855 }
856 return true;
857 }
858#define AST_TEMPLATE(utype) template bool xtensor<utype>::checkInit(const std::vector<int>&, const std::vector<int>&);
860#undef AST_TEMPLATE
861
862 // sameShape///////////////////////////////////////////////////////////////////
863 // helper function for operations between two tensors to check if both have
864 // the same shape
865 template <class utype> bool xtensor<utype>::sameShape(const xtensor<utype>& tensor) const {
866 for (uint d = 0; d < ndim; d++) {
867 if (shape[d] != tensor.shape[d]) {
868 return false;
869 }
870 }
871 return true;
872 }
873#define AST_TEMPLATE(utype) template bool xtensor<utype>::sameShape(const xtensor<utype>&) const;
875#undef AST_TEMPLATE
876
877 template <class utype> bool xtensor<utype>::sameShape(const _subtensor<utype>& st) const {
878 const uint size = st._tensor.ndim - (uint) st.indexed_dim;
879 if (size != ndim) {
880 return false;
881 } else {
882 for (uint i = 0; i < size; i++) {
883 if (st._tensor.shape[i + st.indexed_dim] != shape[i]) {
884 return false;
885 }
886 }
887 }
888 return true;
889 }
890#define AST_TEMPLATE(utype) template bool xtensor<utype>::sameShape(const _subtensor<utype>&) const;
892#undef AST_TEMPLATE
893 // END helper functions
894
895 // BEGIN operators
896 // BEGIN index operators
897 template <class utype> _subtensor<utype> xtensor<utype>::operator()(std::vector<int> indices) const {
898#ifdef _CHECK_BOUNDS_
899 std::stringstream message;
900 uint isize = indices.size();
901 if (isize > ndim) {
902 message << "Too many indices for tensor with " << ndim << " dimensions (" << isize << " provided).";
904 } else {
905 for (uint i = 0; i < isize; i++) {
906 if ((indices[i] < lindex[i]) || indices[i] > uindex[i]) {
907 message << "Index " << indices[i] << " out of bounds for dimension " << i;
908 message << " (lindex = " << lindex[i] << ", uindex = " << uindex[i] << ").";
910 }
911 }
912 }
913#endif
914 return _subtensor<utype>(indices, corpus, *this);
915 }
916#define AST_TEMPLATE(utype) template _subtensor<utype> xtensor<utype>::operator()(std::vector<int>) const;
918#undef AST_TEMPLATE
919
921#ifdef _CHECK_BOUNDS_
922 std::stringstream message;
923 if (indices.rows > (int) ndim) {
924 message << "Too many indices for tensor with " << ndim << " dimensions (" << indices.rows << " provided).";
926 } else {
927 for (int i = 0, ixvec = indices.lrows; ixvec <= indices.urows; i++, ixvec++) {
928 if (indices[ixvec] < lindex[i] || indices[ixvec] > uindex[i]) {
929 message << "Index " << indices[i] << " out of bounds for dimension " << i;
930 message << " (lindex = " << lindex[i] << ", uindex = " << uindex[i] << ").";
932 }
933 }
934 }
935#endif
936 return _subtensor<utype>(indices, corpus, *this);
937 }
938#define AST_TEMPLATE(utype) template _subtensor<utype> xtensor<utype>::operator()(aurostd::xvector<int>) const;
940#undef AST_TEMPLATE
941
942 template <class utype> _subtensor<utype> xtensor<utype>::operator[](int i) const {
943#ifdef _CHECK_BOUNDS_
944 if ((i < lindex[0]) || (i > uindex[0])) {
945 std::stringstream message;
946 message << "Index " << i << " out of bounds for dimension 0";
947 message << " (lindex = " << lindex[0] << ", uindex = " << uindex[0] << ").";
949 }
950#endif
951 return _subtensor<utype>(i, corpus, *this);
952 }
953#define AST_TEMPLATE(utype) template _subtensor<utype> xtensor<utype>::operator[](int) const;
955#undef AST_TEMPLATE
956 // END index operators
957
960 template <class utype> xtensor<utype>& xtensor<utype>::operator+=(utype scalar) {
961 for (int i = 0; i < nelements; i++) {
962 corpus[i] += scalar;
963 }
964 return *this;
965 }
966#define AST_TEMPLATE(utype) template xtensor<utype>& xtensor<utype>::operator+=(utype);
968#undef AST_TEMPLATE
969
970 template <class utype> xtensor<utype>& xtensor<utype>::operator-=(utype scalar) {
971 for (int i = 0; i < nelements; i++) {
972 corpus[i] -= scalar;
973 }
974 return *this;
975 }
976#define AST_TEMPLATE(utype) template xtensor<utype>& xtensor<utype>::operator-=(utype);
978#undef AST_TEMPLATE
979
980 template <class utype> xtensor<utype>& xtensor<utype>::operator*=(utype scalar) {
981 for (int i = 0; i < nelements; i++) {
982 corpus[i] *= scalar;
983 }
984 return *this;
985 }
986#define AST_TEMPLATE(utype) template xtensor<utype>& xtensor<utype>::operator*=(utype);
988#undef AST_TEMPLATE
989
990 template <class utype> xtensor<utype>& xtensor<utype>::operator/=(utype scalar) {
991 for (int i = 0; i < nelements; i++) {
992 corpus[i] /= scalar;
993 }
994 return *this;
995 }
996#define AST_TEMPLATE(utype) template xtensor<utype>& xtensor<utype>::operator/=(utype);
998#undef AST_TEMPLATE
1000
1002 template <class utype> xtensor<utype>& xtensor<utype>::operator+=(const xtensor<utype>& tensor) {
1003 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1004 if (LDEBUG) {
1005 std::cerr << _XTENSOR_ERR_PREFIX_ << "operator+= : Dimensions tensor 1:";
1006 for (uint i = 0; i < ndim; i++) {
1007 std::cerr << " " << shape[i];
1008 }
1009 std::cerr << ", dimensions tensor 2:";
1010 for (uint i = 0; i < tensor.ndim; i++) {
1011 std::cerr << " " << tensor.shape[i];
1012 }
1013 std::cerr << std::endl;
1014 }
1015 if (sameShape(tensor)) {
1016 for (int i = 0; i < nelements; i++) {
1017 corpus[i] += tensor.get(i);
1018 }
1019 return *this;
1020 // Exception handling
1021 } else {
1022 const std::string message = "Tensors are of different size.";
1024 }
1025 }
1026#define AST_TEMPLATE(utype) template xtensor<utype>& xtensor<utype>::operator+=(const xtensor<utype>&);
1028#undef AST_TEMPLATE
1029
1030 template <class utype> xtensor<utype>& xtensor<utype>::operator-=(const xtensor<utype>& tensor) {
1031 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1032 if (LDEBUG) {
1033 std::cerr << _XTENSOR_ERR_PREFIX_ << "operator-= : Dimensions tensor 1:";
1034 for (uint i = 0; i < ndim; i++) {
1035 std::cerr << " " << shape[i];
1036 }
1037 std::cerr << ", dimensions tensor 2:";
1038 for (uint i = 0; i < tensor.ndim; i++) {
1039 std::cerr << " " << tensor.shape[i];
1040 }
1041 std::cerr << std::endl;
1042 }
1043 if (sameShape(tensor)) {
1044 for (int i = 0; i < nelements; i++) {
1045 corpus[i] -= tensor.get(i);
1046 }
1047 return *this;
1048 // Exception handling
1049 } else {
1050 const std::string message = "Tensors are of different size.";
1052 }
1053 }
1054#define AST_TEMPLATE(utype) template xtensor<utype>& xtensor<utype>::operator-=(const xtensor<utype>&);
1056#undef AST_TEMPLATE
1057
1058 template <class utype> xtensor<utype> operator+(const xtensor<utype>& tensor) {
1059 return tensor;
1060 }
1061#define AST_TEMPLATE(utype) template xtensor<utype> operator+(const xtensor<utype>&);
1063#undef AST_TEMPLATE
1064
1065 template <class utype> xtensor<utype> operator-(xtensor<utype> tensor) {
1066 tensor *= -1;
1067 return tensor;
1068 }
1069#define AST_TEMPLATE(utype) template xtensor<utype> operator-(const xtensor<utype>);
1071#undef AST_TEMPLATE
1073
1076 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1077 if (LDEBUG) {
1078 std::cerr << _XTENSOR_ERR_PREFIX_ << "operator-= : Dimensions tensor:";
1079 for (uint i = 0; i < ndim; i++) {
1080 std::cerr << " " << shape[i];
1081 }
1082 std::cerr << ", dimensions subtensor:";
1083 if (st.indexed_dim == st._tensor.ndim) {
1084 std::cerr << " 1" << std::endl;
1085 } else {
1086 for (uint i = st.indexed_dim; i < st._tensor.ndim; i++) {
1087 std::cerr << " " << st._tensor.shape[i];
1088 }
1089 std::cerr << std::endl;
1090 }
1091 }
1092 if (sameShape(st)) {
1093 if (st.indexed_dim == st._tensor.ndim) {
1094 corpus[0] += st.get(st.shift);
1095 } else {
1096 const int n = st.getNumElements();
1097 for (int i = 0, ist = st.shift; i < n; i++, ist++) {
1098 corpus[i] += st.get(ist);
1099 }
1100 }
1101 return *this;
1102 } else {
1103 const std::string message = "Tensor and subtensor are of different size.";
1105 }
1106 }
1107#define AST_TEMPLATE(utype) template xtensor<utype>& xtensor<utype>::operator+=(const _subtensor<utype>&);
1109#undef AST_TEMPLATE
1110
1112 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1113 if (LDEBUG) {
1114 std::cerr << _XTENSOR_ERR_PREFIX_ << "operator-= : Dimensions tensor:";
1115 for (uint i = 0; i < ndim; i++) {
1116 std::cerr << " " << shape[i];
1117 }
1118 std::cerr << ", dimensions subtensor:";
1119 if (st.indexed_dim == st._tensor.ndim) {
1120 std::cerr << " 1" << std::endl;
1121 } else {
1122 for (uint i = st.indexed_dim; i < st._tensor.ndim; i++) {
1123 std::cerr << " " << st._tensor.shape[i];
1124 }
1125 std::cerr << std::endl;
1126 }
1127 }
1128 if (sameShape(st)) {
1129 if (st.indexed_dim == st._tensor.ndim) {
1130 corpus[0] -= st.get(st.shift);
1131 } else {
1132 const int n = st.getNumElements();
1133 for (int i = 0, ist = st.shift; i < n; i++, ist++) {
1134 corpus[i] -= st.get(ist);
1135 }
1136 }
1137 return *this;
1138 } else {
1139 const std::string message = "Tensor and subtensor are of different size.";
1141 }
1142 }
1143#define AST_TEMPLATE(utype) template xtensor<utype>& xtensor<utype>::operator-=(const _subtensor<utype>&);
1145#undef AST_TEMPLATE
1148
1151 template <class utype> xtensor<utype> operator*(xtensor<utype> tensor, const utype& scalar) {
1152 tensor *= scalar;
1153 return tensor;
1154 }
1155#define AST_TEMPLATE(utype) template xtensor<utype> operator*(xtensor<utype>, const utype&);
1157#undef AST_TEMPLATE
1158
1159 template <class utype> xtensor<utype> operator*(const utype& scalar, const xtensor<utype>& tensor) {
1160 return tensor * scalar;
1161 }
1162#define AST_TEMPLATE(utype) template xtensor<utype> operator*(const utype&, const xtensor<utype>&);
1164#undef AST_TEMPLATE
1165
1166 template <class utype> xtensor<utype> operator/(xtensor<utype> tensor, const utype& scalar) {
1167 tensor /= scalar;
1168 return tensor;
1169 }
1170#define AST_TEMPLATE(utype) template xtensor<utype> operator/(xtensor<utype>, const utype&);
1172#undef AST_TEMPLATE
1174
1176 template <class utype> xtensor<utype> operator+(xtensor<utype> tensor1, const xtensor<utype>& tensor2) {
1177 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1178 if (LDEBUG) {
1179 std::cerr << _XTENSOR_ERR_PREFIX_ << "operator+ : Dimensions tensor 1";
1180 for (uint i = 0; i < tensor1.ndim; i++) {
1181 std::cerr << " " << tensor1.shape[i];
1182 }
1183 std::cerr << ", dimensions tensor 2:";
1184 for (uint i = 0; i < tensor2.ndim; i++) {
1185 std::cerr << " " << tensor2.shape[i];
1186 }
1187 std::cerr << std::endl;
1188 }
1189 if (tensor1.sameShape(tensor2)) {
1190 tensor1 += tensor2;
1191 return tensor1;
1192 // Exception handling
1193 } else {
1194 const std::string message = "Tensors are of different size.";
1196 }
1197 }
1198#define AST_TEMPLATE(utype) template xtensor<utype> operator+(xtensor<utype>, const xtensor<utype>&);
1200#undef AST_TEMPLATE
1201
1202 template <class utype> xtensor<utype> operator-(xtensor<utype> tensor1, const xtensor<utype>& tensor2) {
1203 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1204 if (LDEBUG) {
1205 std::cerr << _XTENSOR_ERR_PREFIX_ << "operator- : Dimensions tensor 1";
1206 for (uint i = 0; i < tensor1.ndim; i++) {
1207 std::cerr << " " << tensor1.shape[i];
1208 }
1209 std::cerr << ", dimensions tensor 2:";
1210 for (uint i = 0; i < tensor2.ndim; i++) {
1211 std::cerr << " " << tensor2.shape[i];
1212 }
1213 std::cerr << std::endl;
1214 }
1215 if (tensor1.sameShape(tensor2)) {
1216 tensor1 -= tensor2;
1217 return tensor1;
1218 // Exception handling
1219 } else {
1220 const std::string message = "Tensors are of different size.";
1222 }
1223 }
1224#define AST_TEMPLATE(utype) template xtensor<utype> operator-(xtensor<utype>, const xtensor<utype>&);
1226#undef AST_TEMPLATE
1227
1230 template <class utype> xtensor<utype> operator+(const xtensor<utype>& tensor, const _subtensor<utype>& st) {
1231 const xtensor<utype> tensor_from_st(st);
1232 return tensor + tensor_from_st;
1233 }
1234#define AST_TEMPLATE(utype) template xtensor<utype> operator+(const xtensor<utype>&, const _subtensor<utype>&);
1236#undef AST_TEMPLATE
1237
1238 template <class utype> xtensor<utype> operator+(const _subtensor<utype>& st, const xtensor<utype>& tensor) {
1239 return tensor + st;
1240 }
1241#define AST_TEMPLATE(utype) template xtensor<utype> operator+(const _subtensor<utype>&, const xtensor<utype>&);
1243#undef AST_TEMPLATE
1244
1245 template <class utype> xtensor<utype> operator+(const _subtensor<utype>& st1, const _subtensor<utype>& st2) {
1246 const xtensor<utype> tensor1(st1);
1247 const xtensor<utype> tensor2(st2);
1248 return tensor1 + tensor2;
1249 }
1250#define AST_TEMPLATE(utype) template xtensor<utype> operator+(const _subtensor<utype>&, const _subtensor<utype>&);
1252#undef AST_TEMPLATE
1253
1254 template <class utype> xtensor<utype> operator-(const xtensor<utype>& tensor, const _subtensor<utype>& st) {
1255 const xtensor<utype> tensor_from_st(st);
1256 return tensor - tensor_from_st;
1257 }
1258#define AST_TEMPLATE(utype) template xtensor<utype> operator-(const xtensor<utype>&, const _subtensor<utype>&);
1260#undef AST_TEMPLATE
1261
1262 template <class utype> xtensor<utype> operator-(const _subtensor<utype>& st, const xtensor<utype>& tensor) {
1263 return -tensor + st;
1264 }
1265#define AST_TEMPLATE(utype) template xtensor<utype> operator-(const _subtensor<utype>&, const xtensor<utype>&);
1267#undef AST_TEMPLATE
1268
1269 template <class utype> xtensor<utype> operator-(const _subtensor<utype>& st1, const _subtensor<utype>& st2) {
1270 const xtensor<utype> tensor1(st1);
1271 const xtensor<utype> tensor2(st2);
1272 return tensor1 - tensor2;
1273 }
1274#define AST_TEMPLATE(utype) template xtensor<utype> operator-(const _subtensor<utype>&, const _subtensor<utype>&);
1276#undef AST_TEMPLATE
1277
1280 // END operators
1281
1282 // BEGIN member functions
1283 // set/////////////////////////////////////////////////////////////////////////
1284 template <class utype> void xtensor<utype>::set(const utype& value) {
1285 for (int i = 0; i < nelements; i++) {
1286 corpus[i] = (utype) value;
1287 }
1288 }
1289#define AST_TEMPLATE(utype) template void xtensor<utype>::set(const utype&);
1291#undef AST_TEMPLATE
1292
1293 template <class utype> void xtensor<utype>::set(const utype& value, const int& i) {
1294 corpus[i] = value;
1295 }
1296#define AST_TEMPLATE(utype) template void xtensor<utype>::set(const utype&, const int&);
1298#undef AST_TEMPLATE
1299
1300 template <class utype> void xtensor<utype>::reset() {
1301 for (int i = 0; i < nelements; i++) {
1302 corpus[i] = (utype) 0.0;
1303 }
1304 }
1305#define AST_TEMPLATE(utype) template void xtensor<utype>::reset();
1307#undef AST_TEMPLATE
1308
1309 template <class utype> void xtensor<utype>::clear() {
1310 reset();
1311 }
1312#define AST_TEMPLATE(utype) template void xtensor<utype>::clear();
1314#undef AST_TEMPLATE
1315
1316 template <class utype> utype xtensor<utype>::get(const int& i) const {
1317 return corpus[i];
1318 }
1319#define AST_TEMPLATE(utype) template utype xtensor<utype>::get(const int&) const;
1321#undef AST_TEMPLATE
1322
1323 // END member functions
1324
1325 // BEGIN non-member functions
1328 template <class utype> std::vector<utype> xtensor2vector(xtensor<utype>& tensor) {
1329 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1330 if (LDEBUG) {
1331 std::cerr << _XTENSOR_ERR_PREFIX_ << "xtensor2vector - Number of tensor dimensions: " << tensor.ndim << std::endl;
1332 }
1333 if (tensor.ndim > 1) {
1334 // Exception handling
1335 std::stringstream message;
1336 message << "Cannot convert xtensor with " << tensor.ndim << " dimensions to vector.";
1338 } else {
1339 const int rows = tensor.shape[0];
1340 std::vector<utype> vec(rows);
1341 for (int i = 0; i < rows; i++) {
1342 vec[i] = tensor[i + tensor.lindex[0]];
1343 }
1344 return vec;
1345 }
1346 }
1347#define AST_TEMPLATE(utype) template std::vector<utype> xtensor2vector(xtensor<utype>&);
1349#undef AST_TEMPLATE
1350
1351 template <class utype> std::vector<utype> xtensor2vector(const _subtensor<utype>& st) {
1352 xtensor<utype> tensor(st);
1353 return xtensor2vector(tensor);
1354 }
1355#define AST_TEMPLATE(utype) template std::vector<utype> xtensor2vector(const _subtensor<utype>&);
1357#undef AST_TEMPLATE
1358
1359 template <class utype> xvector<utype> xtensor2xvector(xtensor<utype>& tensor) {
1360 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1361 if (LDEBUG) {
1362 std::cerr << _XTENSOR_ERR_PREFIX_ << "xtensor2xvector - Number of tensor dimensions: " << tensor.ndim << std::endl;
1363 }
1364 if (tensor.ndim > 1) {
1365 // Exception handling
1366 std::stringstream message;
1367 message << "Cannot convert xtensor with " << tensor.ndim << " dimensions to xvector.";
1369 } else {
1370 const int rows = tensor.shape[0];
1371 const aurostd::xvector<utype> xvec(rows);
1372 for (int i = 0; i < rows; i++) {
1373 xvec(i + xvec.lrows) = tensor[i + tensor.lindex[0]];
1374 }
1375 return xvec;
1376 }
1377 }
1378#define AST_TEMPLATE(utype) template xvector<utype> xtensor2xvector(xtensor<utype>&);
1380#undef AST_TEMPLATE
1381
1382 template <class utype> xvector<utype> xtensor2xvector(const _subtensor<utype>& st) {
1383 xtensor<utype> tensor(st);
1384 return xtensor2xvector(tensor);
1385 }
1386#define AST_TEMPLATE(utype) template xvector<utype> xtensor2xvector(const _subtensor<utype>&);
1388#undef AST_TEMPLATE
1389
1390 template <class utype> xmatrix<utype> xtensor2xmatrix(xtensor<utype>& tensor) {
1391 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1392 if (LDEBUG) {
1393 std::cerr << _XTENSOR_ERR_PREFIX_ << "xtensor2xmatrix - Number of tensor dimensions: " << tensor.ndim << std::endl;
1394 }
1395 if (tensor.ndim > 2) {
1396 // Exception handling
1397 std::stringstream message;
1398 message << "Cannot convert xtensor with " << tensor.ndim << " dimensions to xmatrix.";
1400 } else {
1401 int rows;
1402 int cols;
1403 rows = tensor.shape[0];
1404 if (tensor.ndim > 1) {
1405 cols = tensor.shape[1];
1406 } else {
1407 cols = 1;
1408 }
1409 const aurostd::xmatrix<utype> mat(rows, cols);
1410 for (int i = 0; i < rows; i++) {
1411 if (tensor.ndim > 1) {
1412 for (int j = 0; j < cols; j++) {
1413 mat(i + 1, j + 1) = tensor[i + tensor.lindex[0]][j + tensor.lindex[1]];
1414 }
1415 } else {
1416 mat(i, 1) = tensor[i + tensor.lindex[0]];
1417 }
1418 }
1419 return mat;
1420 }
1421 }
1422#define AST_TEMPLATE(utype) template xmatrix<utype> xtensor2xmatrix(xtensor<utype>&);
1424#undef AST_TEMPLATE
1425
1426 template <class utype> xmatrix<utype> xtensor2xmatrix(const _subtensor<utype>& st) {
1427 xtensor<utype> tensor(st);
1428 return xtensor2xmatrix(tensor);
1429 }
1430#define AST_TEMPLATE(utype) template xmatrix<utype> xtensor2xmatrix(const _subtensor<utype>&);
1432#undef AST_TEMPLATE
1433
1435 template <class utype> xtensor<utype> vector2xtensor(const std::vector<utype>& vec) {
1436 const std::vector<int> dim(1, vec.size());
1437 const xtensor<utype> tensor(dim);
1438 for (size_t i = 0; i < vec.size(); i++) {
1439 tensor[i + 1] = vec[i];
1440 }
1441 return tensor;
1442 }
1443#define AST_TEMPLATE(utype) template xtensor<utype> vector2xtensor(const std::vector<utype>&);
1445#undef AST_TEMPLATE
1446
1447 template <class utype> xtensor<utype> xvector2xtensor(const aurostd::xvector<utype>& xvec) {
1448 const std::vector<int> dim(1, xvec.rows);
1449 const xtensor<utype> tensor(dim);
1450 for (int i = 0; i < xvec.rows; i++) {
1451 tensor[i + 1] = xvec(xvec.lrows + i);
1452 }
1453 return tensor;
1454 }
1455#define AST_TEMPLATE(utype) template xtensor<utype> xvector2xtensor(const aurostd::xvector<utype>&);
1457#undef AST_TEMPLATE
1458
1459 template <class utype> xtensor<utype> xmatrix2xtensor(const aurostd::xmatrix<utype>& xmat) {
1460 std::vector<int> dim(2);
1461 dim[0] = xmat.rows;
1462 dim[1] = xmat.cols;
1463 const xtensor<utype> tensor(dim);
1464 for (int i = 0; i < xmat.rows; i++) {
1465 for (int j = 0; j < xmat.cols; j++) {
1466 tensor[i + 1][j + 1] = xmat(xmat.lrows + i, xmat.lcols + j);
1467 }
1468 }
1469 return tensor;
1470 }
1471#define AST_TEMPLATE(utype) template xtensor<utype> xmatrix2xtensor(const aurostd::xmatrix<utype>&);
1473#undef AST_TEMPLATE
1474
1476
1478 template <class utype> xtensor<utype> abs(xtensor<utype> tensor) {
1479 tensor.abs();
1480 return tensor;
1481 }
1482#define AST_TEMPLATE(utype) template xtensor<utype> abs(xtensor<utype>);
1484#undef AST_TEMPLATE
1485
1486 template <class utype> void xtensor<utype>::abs() {
1487 for (int i = 0; i < nelements; i++) {
1488 corpus[i] = aurostd::abs(corpus[i]);
1489 }
1490 }
1491#define AST_TEMPLATE(utype) template void xtensor<utype>::abs();
1493#undef AST_TEMPLATE
1494
1495 template <class utype> xtensor<utype> abs(const _subtensor<utype>& st) {
1496 const xtensor<utype> tensor_out(st);
1497 return abs(tensor_out);
1498 }
1499#define AST_TEMPLATE(utype) template xtensor<utype> abs(const _subtensor<utype>&);
1501#undef AST_TEMPLATE
1502
1503 template <class utype> xtensor<utype> ceil(xtensor<utype> tensor) {
1504 tensor.ceil();
1505 return tensor;
1506 }
1507#define AST_TEMPLATE(utype) template xtensor<utype> ceil(xtensor<utype>);
1509#undef AST_TEMPLATE
1510
1511 template <class utype> void xtensor<utype>::ceil() {
1512 for (int i = 0; i < nelements; i++) {
1513 corpus[i] = std::ceil(corpus[i]);
1514 }
1515 }
1516#define AST_TEMPLATE(utype) template void xtensor<utype>::ceil();
1518#undef AST_TEMPLATE
1519
1520 template <class utype> xtensor<utype> ceil(const _subtensor<utype>& st) {
1521 const xtensor<utype> tensor_out(st);
1522 return ceil(tensor_out);
1523 }
1524#define AST_TEMPLATE(utype) template xtensor<utype> ceil(const _subtensor<utype>&);
1526#undef AST_TEMPLATE
1527
1528 template <class utype> xtensor<utype> floor(xtensor<utype> tensor) {
1529 tensor.floor();
1530 return tensor;
1531 }
1532#define AST_TEMPLATE(utype) template xtensor<utype> floor(xtensor<utype>);
1534#undef AST_TEMPLATE
1535
1536 template <class utype> void xtensor<utype>::floor() {
1537 for (int i = 0; i < nelements; i++) {
1538 corpus[i] = std::floor(corpus[i]);
1539 }
1540 }
1541#define AST_TEMPLATE(utype) template void xtensor<utype>::floor();
1543#undef AST_TEMPLATE
1544
1545 template <class utype> xtensor<utype> floor(const _subtensor<utype>& st) {
1546 const xtensor<utype> tensor_out(st);
1547 return floor(tensor_out);
1548 }
1549#define AST_TEMPLATE(utype) template xtensor<utype> floor(const _subtensor<utype>&);
1551#undef AST_TEMPLATE
1552
1553 template <class utype> xtensor<utype> nint(xtensor<utype> tensor) {
1554 tensor.nint();
1555 return tensor;
1556 }
1557#define AST_TEMPLATE(utype) template xtensor<utype> nint(xtensor<utype>);
1559#undef AST_TEMPLATE
1560
1561 template <class utype> void xtensor<utype>::nint() {
1562 for (int i = 0; i < nelements; i++) {
1563 corpus[i] = aurostd::nint(corpus[i]);
1564 }
1565 }
1566#define AST_TEMPLATE(utype) template void xtensor<utype>::nint();
1568#undef AST_TEMPLATE
1569
1570 template <class utype> xtensor<utype> nint(const _subtensor<utype>& st) {
1571 const xtensor<utype> tensor_out(st);
1572 return nint(tensor_out);
1573 }
1574#define AST_TEMPLATE(utype) template xtensor<utype> nint(const _subtensor<utype>&);
1576#undef AST_TEMPLATE
1577
1578 template <class utype> xtensor<utype> round(xtensor<utype> tensor, const utype& tol) {
1579 tensor.round(tol);
1580 return tensor;
1581 }
1582#define AST_TEMPLATE(utype) template xtensor<utype> round(xtensor<utype>, const utype&);
1584#undef AST_TEMPLATE
1585
1586 template <class utype> void xtensor<utype>::round(const utype& tol) {
1587 for (int i = 0; i < nelements; i++) {
1588 corpus[i] = aurostd::roundoff(corpus[i], tol);
1589 }
1590 }
1591#define AST_TEMPLATE(utype) template void xtensor<utype>::round(const utype&);
1593#undef AST_TEMPLATE
1594
1595 template <class utype> xtensor<utype> round(const _subtensor<utype>& st, const utype& tol) {
1596 const xtensor<utype> tensor_out(st);
1597 return round(tensor_out, tol);
1598 }
1599#define AST_TEMPLATE(utype) template xtensor<utype> round(const _subtensor<utype>&, const utype&);
1601#undef AST_TEMPLATE
1602
1603 template <class utype> xtensor<utype> sign(xtensor<utype> tensor) {
1604 tensor.sign();
1605 return tensor;
1606 }
1607#define AST_TEMPLATE(utype) template xtensor<utype> sign(xtensor<utype>);
1609#undef AST_TEMPLATE
1610
1611 template <class utype> void xtensor<utype>::sign() {
1612 for (int i = 0; i < nelements; i++) {
1613 corpus[i] = aurostd::sign(corpus[i]);
1614 }
1615 }
1616#define AST_TEMPLATE(utype) template void xtensor<utype>::sign();
1618#undef AST_TEMPLATE
1619
1620 template <class utype> xtensor<utype> sign(const _subtensor<utype>& st) {
1621 const xtensor<utype> tensor_out(st);
1622 return sign(tensor_out);
1623 }
1624#define AST_TEMPLATE(utype) template xtensor<utype> sign(const _subtensor<utype>&);
1626#undef AST_TEMPLATE
1627
1628 template <class utype>
1629 // Creates an identity tensor of rank n
1630 xtensor<utype> identity_tensor(const utype& _type, int n) { // _type is needed to deduce utype
1631 if (_type) {
1632 ;
1633 } // to suppress compiler warninigs
1634 xtensor<utype> tensor(n);
1635 tensor.set((utype) 0.0); // In case the default initialization value is different from 0
1636 std::vector<int> diag(n);
1637 for (int i = 1; i <= n; i++) {
1638 for (int j = 0; j < n; j++) {
1639 diag[j] = i;
1640 }
1641 tensor(diag) = (utype) 1;
1642 }
1643 return tensor;
1644 }
1645#define AST_TEMPLATE(utype) template xtensor<utype> identity_tensor(const utype&, int);
1647#undef AST_TEMPLATE
1649
1651 template <class utype> utype max(xtensor<utype> tensor) {
1652 return tensor.max();
1653 }
1654#define AST_TEMPLATE(utype) template utype max(xtensor<utype>);
1656#undef AST_TEMPLATE
1657
1658 template <class utype> utype xtensor<utype>::max() {
1659 utype m = corpus[0];
1660 for (int i = 1; i < nelements; i++) {
1661 if (corpus[i] > m) {
1662 m = corpus[i];
1663 }
1664 }
1665 return m;
1666 }
1667#define AST_TEMPLATE(utype) template utype xtensor<utype>::max();
1669#undef AST_TEMPLATE
1670
1671 template <class utype> utype max(const _subtensor<utype>& st) {
1672 const xtensor<utype> tensor_out(st);
1673 return max(tensor_out);
1674 }
1675#define AST_TEMPLATE(utype) template utype max(const _subtensor<utype>&);
1677#undef AST_TEMPLATE
1678
1679 template <class utype> utype min(xtensor<utype> tensor) {
1680 return tensor.min();
1681 }
1682#define AST_TEMPLATE(utype) template utype min(xtensor<utype>);
1684#undef AST_TEMPLATE
1685
1686 template <class utype> utype xtensor<utype>::min() {
1687 utype m = corpus[0];
1688 for (int i = 1; i < nelements; i++) {
1689 if (corpus[i] < m) {
1690 m = corpus[i];
1691 }
1692 }
1693 return m;
1694 }
1695#define AST_TEMPLATE(utype) template utype xtensor<utype>::min();
1697#undef AST_TEMPLATE
1698
1699 template <class utype> utype min(const _subtensor<utype>& st) {
1700 const xtensor<utype> tensor_out(st);
1701 return min(tensor_out);
1702 }
1703#define AST_TEMPLATE(utype) template utype min(const _subtensor<utype>&);
1705#undef AST_TEMPLATE
1706
1707 template <class utype> utype sum(xtensor<utype> tensor) {
1708 return tensor.sum();
1709 }
1710#define AST_TEMPLATE(utype) template utype sum(xtensor<utype>);
1712#undef AST_TEMPLATE
1713
1714 template <class utype> utype xtensor<utype>::sum() {
1715 utype s = 0;
1716 for (int i = 0; i < nelements; i++) {
1717 s += corpus[i];
1718 }
1719 return s;
1720 }
1721#define AST_TEMPLATE(utype) template utype xtensor<utype>::sum();
1723#undef AST_TEMPLATE
1724
1725 template <class utype> utype sum(const _subtensor<utype>& st) {
1726 const xtensor<utype> tensor_out(st);
1727 return sum(tensor_out);
1728 }
1729#define AST_TEMPLATE(utype) template utype sum(const _subtensor<utype>&);
1731#undef AST_TEMPLATE
1732
1733 template <class utype> utype trace(const xtensor<utype>& tensor) {
1734 const bool LDEBUG = (false || XHOST.DEBUG || _DEBUG_XTENSOR_);
1735 if (LDEBUG) {
1736 std::cerr << _XTENSOR_ERR_PREFIX_ << "trace - Tensor shape:";
1737 for (uint i = 0; i < tensor.ndim; i++) {
1738 std::cerr << " " << tensor.shape[i];
1739 }
1740 std::cerr << std::endl;
1741 }
1742 utype trc = 0;
1743 if (tensor.is_cubic) {
1744 const uint n = tensor.ndim;
1745 std::vector<int> diag(n);
1746 for (uint i = 0; i < n; i++) {
1747 for (uint j = 0; j < n; j++) {
1748 diag[j] = i + tensor.lindex[j];
1749 }
1750 trc += tensor(diag);
1751 }
1752 return trc;
1753 } else {
1754 const std::string message = "Trace is only defined for cubic tensors.";
1756 }
1757 }
1758#define AST_TEMPLATE(utype) template utype trace(const xtensor<utype>&);
1760#undef AST_TEMPLATE
1761
1762 template <class utype> utype trace(const _subtensor<utype>& st) {
1763 const xtensor<utype> tensor_out(st);
1764 return trace(tensor_out);
1765 }
1766#define AST_TEMPLATE(utype) template utype trace(const _subtensor<utype>&);
1768#undef AST_TEMPLATE
1769
1771 // END non-member functions
1772
1773} // namespace aurostd
1774/******************************** END XTENSOR *******************************/
1775
1776/*********************************** EIJK ***********************************/
1777// eijk (Ricci Tensor) from old xtensor - used in aflow_xatom.cpp
1778namespace aurostd {
1779 int eijk(int i, int j, int k) {
1780 const int ii = (i - 1) % 3 + 1;
1781 const int jj = (j - 1) % 3 + 1;
1782 const int kk = (k - 1) % 3 + 1;
1783 if ((ii == 1) && (jj == 2) && (kk == 3)) {
1784 return 1;
1785 }
1786 if ((ii == 2) && (jj == 3) && (kk == 1)) {
1787 return 1;
1788 }
1789 if ((ii == 3) && (jj == 1) && (kk == 2)) {
1790 return 1;
1791 }
1792 if ((ii == 1) && (jj == 3) && (kk == 2)) {
1793 return -1;
1794 }
1795 if ((ii == 3) && (jj == 2) && (kk == 1)) {
1796 return -1;
1797 }
1798 if ((ii == 2) && (jj == 1) && (kk == 3)) {
1799 return -1;
1800 }
1801 return 0;
1802 }
1803
1805 return eijk(ijk[1], ijk[2], ijk[3]);
1806 }
1807
1808 int estarijk(int i, int j, int k) {
1809 const int ii = (i - 1) % 3 + 1;
1810 const int jj = (j - 1) % 3 + 1;
1811 const int kk = (k - 1) % 3 + 1;
1812 if ((ii == 1) && (jj == 2) && (kk == 3)) {
1813 return 1;
1814 }
1815 if ((ii == 2) && (jj == 3) && (kk == 1)) {
1816 return 1;
1817 }
1818 if ((ii == 3) && (jj == 1) && (kk == 2)) {
1819 return 1;
1820 }
1821 return 0;
1822 }
1823
1825 return estarijk(ijk[1], ijk[2], ijk[3]);
1826 }
1827} // namespace aurostd
1828/*********************************** EIJK ***********************************/
1829
1830#endif
1831//****************************************************************************
1832// * *
1833// * Aflow STEFANO CURTAROLO - Duke University 2003-2024 *
1834// * Aflow MARCO ESTERS - Duke University 2018-2021 *
1835// * *
1836//****************************************************************************
_XHOST XHOST
unsigned uint
Definition aurostd.h:39
#define __AFLOW_FILE__
Definition aurostd.h:44
#define __AFLOW_FUNC__
Definition aurostd.h:43
This file contains the preprocessor macros to ensure a proper instantiation of all aurostd functions.
#define AST_GEN_1(type_selection)
autogenerate 1D code based on AST_TEMPLATE
#define AST_UTYPE_NUM
#define _INDEX_BOUNDS_
#define _RUNTIME_ERROR_
#define _INDEX_ILLEGAL_
#define _ALLOC_ALLOCATE_
#define _INDEX_MISMATCH_
static const std::string _XTENSOR_ERR_PREFIX_
#define _DEBUG_XTENSOR_
static const std::string _SUBTENSOR_ERR_PREFIX_
_subtensor< utype > & operator[](const int &)
const xtensor< utype > & _tensor
_subtensor< utype > & operator*=(utype scalar)
_subtensor< utype > & operator()(const std::vector< int > &)
bool sameShape(const _subtensor< utype > &)
_subtensor(const int &, utype *, const xtensor< utype > &)
void set(const utype &)
utype get(const int &) const
_subtensor< utype > & operator-=(utype scalar)
_subtensor< utype > & operator+=(utype scalar)
_subtensor< utype > & operator=(const utype &)
_subtensor< utype > & operator/=(utype scalar)
_subtensor< utype > operator[](int) const
xtensor< utype > & operator-=(utype)
xtensor< utype > & operator+=(utype)
xtensor< utype > & operator/=(utype)
void set(const utype &)
xtensor< utype > & operator*=(utype)
bool checkInit(const std::vector< int > &, const std::vector< int > &)
void buildTensor(const std::vector< int > &, const std::vector< int > &)
utype get(const int &) const
xtensor< utype > operator=(const xtensor< utype > &)
_subtensor< utype > operator()(std::vector< int >) const
void round(const utype &)
bool sameShape(const xtensor< utype > &) const
xmatrix< utype > xtensor2xmatrix(xtensor< utype > &tensor)
xvector< utype > xtensor2xvector(xtensor< utype > &tensor)
int estarijk(int i, int j, int k)
void set(xmatrix< utype > &a, const utype &s)
xmatrix< utype > sign(const xmatrix< utype > &a)
xtensor< utype > xmatrix2xtensor(const aurostd::xmatrix< utype > &xmat)
utype abs(const xcomplex< utype > &x)
xtensor< utype > identity_tensor(const utype &_type, int n)
vector< utype > reset(vector< utype > &v)
xcomplex< utype > operator+(const xcomplex< utype > &x, const xcomplex< utype > &y)
std::vector< utype > xtensor2vector(xtensor< utype > &tensor)
xmatrix< utype > ceil(const xmatrix< utype > &a)
xmatrix< utype > floor(const xmatrix< utype > &a)
utype max(const vector< utype > vec)
xcomplex< utype > operator*(const xcomplex< utype > &x, const xcomplex< utype > &y)
xtensor< utype > xvector2xtensor(const aurostd::xvector< utype > &xvec)
int eijk(int i, int j, int k)
utype trace(const xmatrix< utype > &a)
utype min(const vector< utype > vec)
utype sum(const vector< utype > vec)
xmatrix< utype > nint(const xmatrix< utype > &a)
vector< utype > xvector2vector(const xvector< utype > &xvec)
xmatrix< utype > roundoff(const xmatrix< utype > &a, utype _tol_)
xcomplex< utype > operator-(const xcomplex< utype > &x, const xcomplex< utype > &y)
xcomplex< utype > operator/(const xcomplex< utype > &x, const xcomplex< utype > &y)
xtensor< utype > vector2xtensor(const std::vector< utype > &vec)
xmatrix< utype > round(const xmatrix< utype > &a)