svMultiPhysics
Loading...
Searching...
No Matches
Array.h
1/* Copyright (c) Stanford University, The Regents of the University of California, and others.
2 *
3 * All Rights Reserved.
4 *
5 * See Copyright-SimVascular.txt for additional details.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject
13 * to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "Vector.h"
32#include "utils.h"
33
34#ifndef ARRAY_H
35#define ARRAY_H
36
37#include <algorithm>
38#include <array>
39#include <cstring>
40#include <float.h>
41#include <iostream>
42#include <math.h>
43#include <vector>
44
45// If set then check Array indexes.
46//
47#ifdef ENABLE_ARRAY_INDEX_CHECKING
48#define Array_check_enabled
49#endif
50
51/// @brief The Array template class implements a simple interface to 2D arrays.
52//
53template<typename T>
54class Array
55{
56 public:
57 // Some variables used to monitor Array object allocation.
58 static int id;
59 static int num_allocated;
60 static int active;
61 static bool show_index_check_message;
62 static double memory_in_use;
63 static double memory_returned;
64 static void memory(const std::string& prefix="");
65 static void stats(const std::string& prefix="");
66 static bool write_enabled;
67
68 Array()
69 {
70 id += 1;
71 nrows_ = 0;
72 ncols_ = 0;
73 size_ = 0;
74 data_ = nullptr;
75 num_allocated += 1;
76 active += 1;
77 };
78
79 Array(const int num_rows, const int num_cols)
80 {
81 // [NOTE] This is tfu but need to mimic fortran.
82 nrows_ = num_rows;
83 ncols_ = num_cols;
84
85 if ((num_rows <= 0) || (num_cols <= 0)) {
86 return;
87 }
88
89 allocate(num_rows, num_cols);
90 num_allocated += 1;
91 active += 1;
92 }
93
94 Array(const int num_rows, const int num_cols, T* data)
95 {
96 data_reference_ = true;
97 nrows_ = num_rows;
98 ncols_ = num_cols;
99 size_ = nrows_ * ncols_;
100 data_ = data;
101 }
102
103 Array(std::initializer_list<std::initializer_list<T>> lst)
104 {
105 int num_rows = 0;
106 int num_cols = 0;
107
108 for (auto &row : lst) {
109 num_rows += 1;
110 if (num_cols == 0) {
111 num_cols = row.size();
112 } else if (row.size() != num_cols) {
113 throw std::runtime_error("[Array initializer_list ctor] Column data is of unequal size.");
114 }
115 }
116
117 allocate(num_rows, num_cols);
118
119 int row = 0;
120
121 for (auto &row_data : lst) {
122 auto it = row_data.begin();
123 for (int col = 0; col < row_data.size(); col++, it++) {
124 data_[row + col*nrows_] = *it;
125 }
126 row += 1;
127 }
128
129 num_allocated += 1;
130 active += 1;
131 }
132
133 /// @brief Array copy
134 //
135 Array(const Array &rhs)
136 {
137 if ((rhs.nrows_ <= 0) || (rhs.ncols_ <= 0)) {
138 return;
139 }
140
141 allocate(rhs.nrows_, rhs.ncols_);
142
143 memcpy(data_, rhs.data_, size_*sizeof(T));
144 num_allocated += 1;
145 active += 1;
146 }
147
148 /// @brief Array assignment
149 //
150 Array& operator=(const Array& rhs)
151 {
152 if (this == &rhs) {
153 return *this;
154 }
155
156 if ((rhs.nrows_ <= 0) || (rhs.ncols_ <= 0)) {
157 return *this;
158 }
159
160 if ((nrows_ != rhs.nrows_) || (ncols_ != rhs.ncols_)) {
161 clear();
162 allocate(rhs.nrows_, rhs.ncols_);
163 }
164
165 memcpy(data_, rhs.data_, sizeof(T) * size_);
166 return *this;
167 }
168
169 Array& operator=(const double value)
170 {
171 for (int i = 0; i < size_; i++) {
172 data_[i] = value;
173 }
174 return *this;
175 }
176
177 ~Array()
178 {
179 if (data_ != nullptr) {
180 #if Array_gather_stats
181 memory_in_use -= sizeof(T)*size_;
182 memory_returned += sizeof(T)*size_;
183 active -= 1;
184 #endif
185 if (!data_reference_) {
186 delete [] data_;
187 }
188 data_ = nullptr;
189 size_ = 0;
190 id -= 1;
191 nrows_ = 0;
192 ncols_ = 0;
193 }
194 };
195
196 friend std::ostream& operator << (std::ostream& out, const Array<T>& lhs)
197 {
198 for (int i = 0; i < lhs.size(); i++) {
199 out << lhs.data_[i];
200 if (i != lhs.size()-1) {
201 out << ", ";
202 }
203 }
204 return out;
205 }
206
207 /// @brief Free the array data.
208 ///
209 /// This is to replicate the Fortran DEALLOCATE().
210 //
211 void clear()
212 {
213 if (data_ != nullptr) {
214 if (data_reference_) {
215 throw std::runtime_error("[Array] Can't clear an Array with reference data.");
216 }
217 delete [] data_;
218 #if Array_gather_stats
219 memory_in_use -= sizeof(T) * size_;;
220 memory_returned += sizeof(T) * size_;;
221 #endif
222 }
223 nrows_ = 0;
224 ncols_ = 0;
225 size_ = 0;
226 data_ = nullptr;
227 }
228
229 int ncols() const
230 {
231 return ncols_;
232 }
233
234 int nrows() const
235 {
236 return nrows_;
237 }
238
239 /// @brief Print by rows and columns.
240 //
241 void print(const std::string& label)
242 {
243 printf("%s %d x %d \n", label.c_str(), nrows_, ncols_);
244 for (int i = 0; i < nrows_; i++) {
245 printf("[ ");
246 for (int j = 0; j < ncols_; j++) {
247 printf("%.16e", value(i,j));
248 if (j == ncols_-1) {
249 printf(" ]");
250 } else {
251 printf(", ");
252 }
253 }
254 printf("\n");
255 }
256 }
257
258 /// @brief Resize the array.
259 //
260 void resize(const int num_rows, const int num_cols)
261 {
262 // [NOTE] This is tfu but need to mimic fortran.
263 nrows_ = num_rows;
264 ncols_ = num_cols;
265
266 if ((num_rows <= 0) || (num_cols <= 0)) {
267 return;
268 }
269
270 if (data_ != nullptr) {
271 if (data_reference_) {
272 throw std::runtime_error("[Array] Can't resize an Array with reference data.");
273 }
274 delete [] data_;
275 data_ = nullptr;
276 size_ = 0;
277 nrows_ = 0;
278 ncols_ = 0;
279 #if Array_gather_stats
280 memory_in_use -= sizeof(T) * size_;;
281 memory_returned += sizeof(T) * size_;;
282 #endif
283 }
284
285 allocate(num_rows, num_cols);
286 }
287
288 int size() const
289 {
290 return size_;
291 }
292
293 int msize() const
294 {
295 return size_ * sizeof(T);
296 }
297
298 /// @brief Test if an array has rows or columns set
299 /// but no data.
300 ///
301 /// [NOTE] This is tfu but need to mimic fortran.
302 //
303 bool allocated()
304 {
305 if ((nrows_ > 0) || (ncols_ > 0)) {
306 return true;
307 }
308
309 return false;
310 }
311
312 void read(const std::string& file_name)
313 {
314 auto fp = fopen(file_name.c_str(), "rb");
315 int size;
316 fread(&size, sizeof(int), 1, fp);
317 fread(data_, sizeof(double), size, fp);
318 fclose(fp);
319 }
320
321 void write(const std::string& label, bool memory=true, T offset={}) const
322 {
323 if (!write_enabled) {
324 return;
325 }
326
327 auto file_prefix = build_file_prefix(label);
328 auto file_name = file_prefix + "_cm.bin";
329
330 // Write binary file.
331 //
332 auto fp = fopen(file_name.c_str(), "wb");
333 fwrite(&size_, sizeof(int), 1, fp);
334 fwrite(data_, sizeof(T), size_, fp);
335 fclose(fp);
336 }
337
338 /// @brief Append data to a file.
339 //
340 void append(const std::string& label, bool memory=true, T offset={}) const
341 {
342 if (!write_enabled) {
343 return;
344 }
345
346 auto file_prefix = build_file_prefix(label);
347 auto file_name = file_prefix + "_cm.bin";
348
349 /// @brief Append binary file.
350 //
351 auto fp = fopen(file_name.c_str(), "ab");
352 fwrite(data_, sizeof(T), size_, fp);
353 fclose(fp);
354 }
355
356 const T& operator()(const int i) const
357 {
358 if (i >= size_) {
359 throw std::runtime_error("[Array(i)] Index " + std::to_string(i) + " is out of bounds.");
360 }
361 return data_[i];
362 }
363
364 T& operator()(const int i)
365 {
366 if (i >= size_) {
367 throw std::runtime_error("[Array(i)] Index " + std::to_string(i) + " is out of bounds.");
368 }
369 return data_[i];
370 }
371
372 /// @brief (i,j) operators
373 //
374 const T& operator()(const int row, const int col) const
375 {
376 #ifdef Array_check_enabled
377 check_index(row, col);
378 #endif
379 return data_[row + col*nrows_];
380 }
381
382 T& operator()(const int row, const int col)
383 {
384 #ifdef Array_check_enabled
385 check_index(row, col);
386 #endif
387 return data_[row + col*nrows_];
388 }
389
390 /// @brief Get a column from the array as a Vector.
391 //
392 Vector<T> col(const int col, const std::array<int,2>& range={-1,-1}) const
393 {
394 #ifdef Array_check_enabled
395 check_index(0, col);
396 #endif
397 int start_row, end_row;
398
399 if (range[0] != -1) {
400 start_row = range[0];
401 end_row = range[1];
402 #ifdef Array_check_enabled
403 check_index(start_row, col);
404 check_index(end_row, col);
405 #endif
406 } else {
407 start_row = 0;
408 end_row = nrows_;
409 }
410
411 Vector<T> values(nrows_);
412 for (int row = start_row; row < end_row; row++) {
413 values[row] = value(row,col);
414 }
415 return values;
416 }
417
418 Vector<T> rcol(const int col) const
419 {
420 Vector<T> vector_col(nrows_, &data_[col*nrows_]);
421 return vector_col;
422 }
423
424 /// @brief Return a pointer to the internal data for the given column.
425 //
426 T* col_data(const int col) {
427 return &data_[col*nrows_];
428 }
429
430 /// @brief Get one or more columns from the array as Vectors.
431 //
432 Vector<Vector<T>> cols(const Vector<int>& columns) const
433 {
434 Vector<Vector<T>> values(columns.size());
435
436 for (int i = 0; i < columns.size(); i++) {
437 int j = columns[i];
438 #ifdef Array_check_enabled
439 check_index(0, j);
440 #endif
441 values[i] = col(j);
442 }
443
444 return values;
445 }
446
447 /// @brief Get a row from the array as a Vector.
448 //
449 Vector<T> row(const int row, const std::array<int,2>& range={-1,-1})
450 {
451 #ifdef Array_check_enabled
452 check_index(row, 0);
453 #endif
454
455 Vector<T> values(ncols_);
456
457 for (int col = 0; col < ncols_; col++) {
458 values[col] = value(row,col);
459 }
460
461 return values;
462 }
463
464 /// @brief Get row values from the array using an index of columns.
465 //
466 Vector<T> rows(const int row, const Vector<int>& indexes) const
467 {
468 #ifdef Array_check_enabled
469 check_index(row, 0);
470 #endif
471
472 Vector<T> values(indexes.size());
473
474 for (int i = 0; i < indexes.size(); i++) {
475 int col = indexes[i];
476 #ifdef Array_check_enabled
477 check_index(row, col);
478 #endif
479 values[i] = value(row,col);
480 }
481
482 return values;
483 }
484
485 /// @brief Get a set of rows using a start and end row index.
486 //
487 Array<T> rows(const int start_row, const int end_row) const
488 {
489 #ifdef Array_check_enabled
490 check_index(start_row, 0);
491 check_index(end_row, 0);
492 #endif
493 int num_rows = end_row - start_row + 1;
494 Array<T> values(num_rows, ncols_ );
495
496 for (int row = 0; row < num_rows; row++) {
497 for (int col = 0; col < ncols_; col++) {
498 values(row,col) = data_[(row+start_row) + col*nrows_];
499 }
500 }
501 return values;
502 }
503
504 /// @brief Get a range of rows for the given column.
505 //
506 Vector<T> rows(const int start_row, const int end_row, const int col) const
507 {
508 #ifdef Array_check_enabled
509 check_index(start_row, 0);
510 check_index(end_row, 0);
511 #endif
512 int num_rows = end_row - start_row + 1;
513 Vector<T> values(num_rows);
514
515 for (int row = 0; row < num_rows; row++) {
516 values(row) = data_[(row+start_row) + col*nrows_];
517 }
518 return values;
519 }
520
521 /// @brief Return a vector of values for a range of rows and columns.
522 //
523 std::vector<T> values(const std::array<int,2>& rows, const std::array<int,2>& cols, const int stride=1) const
524 {
525 std::vector<T> values;
526
527 for (int i = rows[0]; i <= rows[1]; i += stride) {
528 for (int j = cols[0]; j <= cols[1]; j += stride) {
529 values.push_back(value(i,j));
530 }
531 }
532
533 return values;
534 }
535
536 /// @brief Set column values from a vector of values.
537 //
538 void set_col(const int col, const Vector<T>& values, const std::array<int,2>& range={-1,-1})
539 {
540 #ifdef Array_check_enabled
541 check_index(0, col);
542 #endif
543 int start_row, end_row;
544
545 if (range[0] != -1) {
546 start_row = range[0];
547 end_row = range[1];
548 #ifdef Array_check_enabled
549 check_index(start_row, col);
550 check_index(end_row, col);
551 #endif
552 } else {
553 start_row = 0;
554 end_row = nrows_;
555 }
556
557 for (int row = 0; row < values.size(); row++) {
558 data_[row + col*nrows_] = values[row];
559 }
560 }
561
562 /// @brief Set row values from a vector of values.
563 //
564 void set_row(const int row, const Vector<T>& values) const
565 {
566 #ifdef Array_check_enabled
567 check_index(row, 0);
568 #endif
569 for (int col = 0; col < values.size(); col++) {
570 data_[row + col*nrows_] = values[col];
571 }
572 }
573
574 /// @brief Set row values from an initializer list {}..
575 //
576 void set_row(const int row, std::initializer_list<T> row_data) const
577 {
578 auto it = row_data.begin();
579 for (int col = 0; col < ncols_; col++, it++) {
580 data_[row + col*nrows_] = *it;
581 }
582 }
583
584 /// @brief Set row values from a scalar.
585 //
586 void set_row(const int row, const T value) const
587 {
588 #ifdef Array_check_enabled
589 check_index(row, 0);
590 #endif
591 for (int col = 0; col < ncols_; col++) {
592 data_[row + col*nrows_] = value;
593 }
594 }
595
596 /// @brief Set row values from a vector of values at the given column offset.
597 //
598 void set_row(const int row, int offset, const Vector<T>& values) const
599 {
600 #ifdef Array_check_enabled
601 check_index(row, 0);
602 check_index(row, offset+values.size()-1);
603 #endif
604 for (int col = 0; col < values.size(); col++) {
605 int ocol = col + offset;
606 #ifdef Array_check_enabled
607 check_index(row, ocol);
608 #endif
609 data_[row + ocol*nrows_] = values[col];
610 }
611 }
612
613 /// @brief Set a set of rows using a start and end row index.
614 //
615 void set_rows(const int start_row, const int end_row, const Array<T>& values) const
616 {
617 #ifdef Array_check_enabled
618 check_index(start_row, 0);
619 check_index(end_row, 0);
620 #endif
621 int num_rows = end_row - start_row + 1;
622
623 if (ncols_ != values.ncols_) {
624 throw std::runtime_error("[Array set_rows] Arrays have different column sizes. ");
625 }
626
627 for (int row = 0; row < num_rows; row++) {
628 for (int col = 0; col < ncols_; col++) {
629 data_[(row+start_row) + col*nrows_] = values(row,col);;
630 }
631 }
632 }
633
634 ///////////////////////////////////////////////////
635 // M a t h e m a t i c a l o p e r a t o r s //
636 ///////////////////////////////////////////////////
637
638 T max() const
639 {
640 T max_v = data_[0];
641 for (int i = 1; i < size_; i++) {
642 if (data_[i] > max_v) {
643 max_v = data_[i];
644 }
645 }
646 return max_v;
647 }
648
649 T min() const
650 {
651 T min_v = data_[0];
652 for (int i = 1; i < size_; i++) {
653 if (data_[i] < min_v) {
654 min_v = data_[i];
655 }
656 }
657 return min_v;
658 }
659
660 /// @brief Add arrays.
661 //
662 Array<T> operator+(const Array<T>& array) const
663 {
664 if ((nrows_ != array.nrows_) || (ncols_ != array.ncols_)) {
665 throw std::runtime_error("[Array addition] Arrays have diffent shapes. ");
666 }
667 Array<T> result(nrows_, ncols_);
668 for (int j = 0; j < ncols_; j++) {
669 for (int i = 0; i < nrows_; i++) {
670 result(i, j) = data_[i + j*nrows_] + array(i,j);
671 }
672 }
673 return result;
674 }
675
676 /// @brief Subtract arrays.
677 //
678 Array<T> operator-(const Array<T>& array) const
679 {
680 if ((nrows_ != array.nrows_) || (ncols_ != array.ncols_)) {
681 throw std::runtime_error("[Array subtraction] Arrays have diffent shapes. ");
682 }
683 Array<T> result(nrows_, ncols_);
684 for (int j = 0; j < ncols_; j++) {
685 for (int i = 0; i < nrows_; i++) {
686 result(i, j) = data_[i + j*nrows_] - array(i,j);
687 }
688 }
689 return result;
690 }
691
692 /// @brief Multiply two arrays component-wise to reproduce Fortran.
693 /// C = A * B
694 //
695 Array<T> operator*(const Array<T>& array) const
696 {
697 if ((nrows_ != array.nrows_) || (ncols_ != array.ncols_)) {
698 throw std::runtime_error("[Array multiply] Arrays have diffent shapes. ");
699 }
700
701 Array<T> result(nrows_, ncols_);
702
703 for (int j = 0; j < ncols_; j++) {
704 for (int i = 0; i < nrows_; i++) {
705 result(i, j) = (*this)(i,j) * array(i,j);
706 }
707 }
708
709 return result;
710 }
711
712 /// @brief Divide one array by another component-wise.
713 /// C = A / B
714 //
715 Array<T> operator / (const Array<T>& array) const
716 {
717 Array<T> result(nrows_, array.ncols_);
718 if ((nrows_ != array.nrows_) || (ncols_ != array.ncols_)) {
719 throw std::runtime_error("[Array divide] Arrays number of columns or number of rows are not equal.");
720 }
721
722 for (int j = 0; j < ncols_; j++) {
723 for (int i = 0; i < nrows_; i++) {
724 result(i, j) = (*this)(i,j) / array(i,j);
725 }
726 }
727 return result;
728 }
729
730 /// @brief Compound add assignment.
731 //
732 Array<T> operator+=(const Array<T>& array) const
733 {
734 for (int j = 0; j < ncols_; j++) {
735 for (int i = 0; i < nrows_; i++) {
736 data_[i + j*nrows_] += array(i,j);
737 }
738 }
739 return *this;
740 }
741
742 /// @brief Compound subtract assignment.
743 //
744 Array<T> operator-=(const Array<T>& array) const
745 {
746 for (int j = 0; j < ncols_; j++) {
747 for (int i = 0; i < nrows_; i++) {
748 data_[i + j*nrows_] -= array(i,j);
749 }
750 }
751 return *this;
752 }
753
754 /// @brief Compound multiply assignment.
755 //
756 Array<T> operator*=(const Array<T>& array) const
757 {
758 for (int j = 0; j < ncols_; j++) {
759 for (int i = 0; i < nrows_; i++) {
760 data_[i + j*nrows_] *= array(i,j);
761 }
762 }
763 return *this;
764 }
765
766 /// @brief Multiply by a scalar.
767 //
768 Array<T> operator*(const T value) const
769 {
770 Array<T> result(nrows_, ncols_);
771 for (int j = 0; j < ncols_; j++) {
772 for (int i = 0; i < nrows_; i++) {
773 result(i,j) = value * data_[i + j*nrows_];
774 }
775 }
776 return result;
777 }
778
779 friend const Array<T> operator*(const T value, const Array& rhs)
780 {
781 Array<T> result(rhs.nrows_, rhs.ncols_);
782 for (int j = 0; j < rhs.ncols_; j++) {
783 for (int i = 0; i < rhs.nrows_; i++) {
784 result(i,j) = value * rhs.data_[i + j*rhs.nrows_];
785 }
786 }
787 return result;
788 }
789
790 /// @brief Divide by a scalar.
791 /// A / s
792 //
793 Array<T> operator / (const T value) const
794 {
795 if (value == 0.0) {
796 throw std::runtime_error(+"Array Divide by zero.");
797 }
798 Array<T> result(nrows_, ncols_);
799 for (int j = 0; j < ncols_; j++) {
800 for (int i = 0; i < nrows_; i++) {
801 result(i,j) = data_[i + j*nrows_] / value;
802 }
803 }
804 return result;
805 }
806
807 /// @brief Divide scalar by array.
808 /// s / A
809 //
810 friend const Array<T> operator / (const T value, const Array& rhs)
811 {
812 Array<T> result(rhs.nrows_, rhs.ncols_);
813 for (int j = 0; j < rhs.ncols_; j++) {
814 for (int i = 0; i < rhs.nrows_; i++) {
815 result(i,j) = value / rhs.data_[i + j*rhs.nrows_];
816 }
817 }
818 return result;
819 }
820
821 /// @brief Subtract a scalar.
822 /// A - s
823 //
824 Array<T> operator-(const T value) const
825 {
826 Array<T> result(nrows_, ncols_);
827 for (int j = 0; j < ncols_; j++) {
828 for (int i = 0; i < nrows_; i++) {
829 result(i,j) = data_[i + j*nrows_] - value;
830 }
831 }
832 return result;
833 }
834
835 /// @brief Compound add assignment.
836 //
837 Array<T> operator+=(const T value) const
838 {
839 for (int j = 0; j < ncols_; j++) {
840 for (int i = 0; i < nrows_; i++) {
841 data_[i + j*nrows_] += value;
842 }
843 }
844 return *this;
845 }
846
847 /// @brief negate
848 //
849 Array<T> operator-() const
850 {
851 Array<T> result(nrows_, ncols_);
852 for (int j = 0; j < ncols_; j++) {
853 for (int i = 0; i < nrows_; i++) {
854 result(i,j) = -(data_[i + j*nrows_]);
855 }
856 }
857 return result;
858 }
859
860 /// @brief Compound subtract assignment.
861 //
862 Array<T> operator-=(const T value) const
863 {
864 for (int j = 0; j < ncols_; j++) {
865 for (int i = 0; i < nrows_; i++) {
866 data_[i + j*nrows_] -= value;
867 }
868 }
869 return *this;
870 }
871
872 /// @brief Subtract a scalar.
873 /// s - A
874 //
875 friend const Array<T> operator-(const T value, const Array& rhs)
876 {
877 Array<T> result(rhs.nrows_, rhs.ncols_);
878 for (int j = 0; j < rhs.ncols_; j++) {
879 for (int i = 0; i < rhs.nrows_; i++) {
880 result(i,j) = value - rhs.data_[i + j*rhs.nrows_];
881 }
882 }
883 return result;
884 }
885
886 /// @brief absolute value
887 //
888 friend Array<T> abs(const Array& rhs)
889 {
890 Array<T> result(rhs.nrows_, rhs.ncols_);
891 for (int j = 0; j < rhs.ncols_; j++) {
892 for (int i = 0; i < rhs.nrows_; i++) {
893 result(i,j) = fabs(rhs.data_[i + j*rhs.nrows_]);
894 }
895 }
896 return result;
897 }
898
899 /// @brief maximum
900 //
901 friend T max(const Array& arg)
902 {
903 T max_v = arg.data_[0];
904 for (int i = 1; i < arg.size_; i++) {
905 if (arg.data_[i] > max_v) {
906 max_v = arg.data_[i];
907 }
908 }
909 return max_v;
910 }
911
912 /// @brief square root
913 //
914 friend Array<T> sqrt(const Array& arg)
915 {
916 Array<T> result(arg.nrows_, arg.ncols_);
917 for (int j = 0; j < arg.ncols_; j++) {
918 for (int i = 0; i < arg.nrows_; i++) {
919 result(i,j) = sqrt(arg.data_[i + j*arg.nrows_]);
920 }
921 }
922 return result;
923 }
924
925 /// @brief Compute the sum of a row of valuesr
926 //
927 T sum_row(const int row) const
928 {
929 #ifdef Array_check_enabled
930 check_index(row, 0);
931 #endif
932 T sum {};
933 for (int col = 0; col < ncols_; col++) {
934 sum += data_[row + col*nrows_];
935 }
936 return sum;
937 }
938
939 T* data() const {
940 return data_;
941 }
942
943 private:
944
945 /// @brief Allocate memory for array data.
946 //
947 void allocate(const int num_rows, const int num_cols)
948 {
949 data_reference_ = false;
950 nrows_ = num_rows;
951 ncols_ = num_cols;
952 size_ = nrows_ * ncols_;
953 #if Array_gather_stats
954 memory_in_use += sizeof(T)*size_;
955 #endif
956
957 if (data_ != nullptr) {
958 //throw std::runtime_error(+"[Array] Allocating when data is not nullptr.");
959 }
960
961 if (size_ != 0) {
962 data_ = new T [size_];
963 memset(data_, 0, sizeof(T)*size_);
964 }
965 }
966
967 /// @brief Get a value from data_[].
968 //
969 inline T value(const int row, const int col) const
970 {
971 return data_[row + col*nrows_];
972 }
973
974 void check_index(const int row, const int col) const
975 {
976 if (show_index_check_message) {
977 std::cout << "[Array] **********************************" << std::endl;
978 std::cout << "[Array] WARNING: Index checking is enabled " << std::endl;
979 std::cout << "[Array] **********************************" << std::endl;
980 show_index_check_message = false;
981 }
982
983 if (data_ == nullptr) {
984 //throw std::runtime_error(+"Accessing null data in Array.");
985 return;
986 }
987 if ((row < 0) || (row >= nrows_) || (col < 0) || (col >= ncols_)) {
988 auto nr_str = std::to_string(nrows_);
989 auto nc_str = std::to_string(ncols_);
990 auto dims = nr_str + " x " + nc_str;
991 auto index_str = " " + std::to_string(row) + "," + std::to_string(col) + " ";
992 throw std::runtime_error(+"Index (row,col)=" + index_str + " is out of bounds for " +
993 dims + " array.");
994 }
995 }
996
997 //-------------
998 // Member data
999 //-------------
1000 //
1001 int nrows_ = 0;
1002 int ncols_ = 0;
1003 int size_ = 0;
1004 bool data_reference_ = false;
1005 T *data_ = nullptr;
1006};
1007
1008#endif
1009
The Vector template class is used for storing int and double data.
Definition Vector.h:50