GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GNdarray.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GNdarray.cpp - N-dimensional array class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2016-2022 by Juergen Knoedlseder *
5  * ----------------------------------------------------------------------- *
6  * *
7  * This program 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 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * 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 program. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 /**
22  * @file GNdarray.cpp
23  * @brief N-dimensional array class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include "GTools.hpp"
32 #include "GException.hpp"
33 #include "GNdarray.hpp"
34 
35 
36 /* __ Method name definitions ____________________________________________ */
37 #define G_OP_ADD "GNdarray::operator+=(GNdarray&)"
38 #define G_OP_SUB "GNdarray::operator-=(GNdarray&)"
39 #define G_OP_MUL "GNdarray::operator*=(GNdarray&)"
40 #define G_OP_DIV "GNdarray::operator/=(GNdarray&)"
41 #define G_SHAPE "GNdarray::shape(std::vector<int>&)"
42 #define G_AT1 "GNdarray::at(int&)"
43 #define G_AT2 "GNdarray::at(int&, int&)"
44 #define G_AT3 "GNdarray::at(int&, int&, int&)"
45 #define G_ATN "GNdarray::at(std::vector<int>&)"
46 
47 
48 /*==========================================================================
49  = =
50  = Constructors/destructors =
51  = =
52  ==========================================================================*/
53 
54 /***********************************************************************//**
55  * @brief Void constructor
56  ***************************************************************************/
58 {
59  // Initialise class members
60  init_members();
61 
62  // Return
63  return;
64 }
65 
66 
67 /***********************************************************************//**
68  * @brief 1-dimensional constructor
69  *
70  * @param[in] nx Array dimension.
71  *
72  * Constructs a 1-dimensional array.
73  ***************************************************************************/
74 GNdarray::GNdarray(const int& nx)
75 {
76  // Initialise class members
77  init_members();
78 
79  // Set shape
80  m_shape.push_back(nx);
81 
82  // Set strides
83  m_strides.push_back(1);
84 
85  // Initialise data array with zeros
86  m_data.assign(nx, 0.0);
87 
88  // Return
89  return;
90 }
91 
92 
93 /***********************************************************************//**
94  * @brief 2-dimensional constructor
95  *
96  * @param[in] nx Array's first dimension.
97  * @param[in] ny Array's second dimension.
98  *
99  * Constructs a 2-dimensional array.
100  ***************************************************************************/
101 GNdarray::GNdarray(const int& nx, const int& ny)
102 {
103  // Initialise class members
104  init_members();
105 
106  // Compute size of array
107  int size = nx * ny;
108 
109  // Set shape
110  m_shape.push_back(nx);
111  m_shape.push_back(ny);
112 
113  // Set strides
114  m_strides.push_back(1);
115  m_strides.push_back(nx);
116 
117  // Initialise data array with zeros
118  m_data.assign(size, 0.0);
119 
120  // Return
121  return;
122 }
123 
124 
125 /***********************************************************************//**
126  * @brief 3-dimensional constructor
127  *
128  * @param[in] nx Array's first dimension.
129  * @param[in] ny Array's second dimension.
130  * @param[in] nz Array's third dimension.
131  *
132  * Constructs a 3-dimensional array.
133  ***************************************************************************/
134 GNdarray::GNdarray(const int& nx, const int& ny, const int& nz)
135 {
136  // Initialise class members
137  init_members();
138 
139  // Compute size of array
140  int size = nx * ny * nz;
141 
142  // Set shape
143  m_shape.push_back(nx);
144  m_shape.push_back(ny);
145  m_shape.push_back(nz);
146 
147  // Set strides
148  m_strides.push_back(1);
149  m_strides.push_back(nx);
150  m_strides.push_back(nx*ny);
151 
152  // Initialise data array with zeros
153  m_data.assign(size, 0.0);
154 
155  // Return
156  return;
157 }
158 
159 
160 /***********************************************************************//**
161  * @brief n-dimensional constructor
162  *
163  * @param[in] n Array dimensions.
164  *
165  * Constructs a n-dimensional array. If the array dimension vector @p n is
166  * empty an empty n-dimensional array is constructed (similar to the void
167  * constructor).
168  ***************************************************************************/
169 GNdarray::GNdarray(const std::vector<int>& n)
170 {
171  // Initialise class members
172  init_members();
173 
174  // Continue only if there are dimensions in vector
175  if (n.size() > 0) {
176 
177  // Compute size of array
178  int size = n[0];
179  for (int i = 1; i < n.size(); ++i) {
180  size *= n[i];
181  }
182 
183  // Set shape
184  m_shape = n;
185 
186  // Set strides
187  int stride = 1;
188  for (int i = 0; i < n.size(); ++i) {
189  m_strides.push_back(stride);
190  stride *= n[i];
191  }
192 
193  // Initialise data array with zeros
194  m_data.assign(size, 0.0);
195 
196  } // endif: there were dimensions in vector
197 
198  // Return
199  return;
200 }
201 
202 
203 /***********************************************************************//**
204  * @brief Copy constructor
205  *
206  * @param[in] array Array.
207  ***************************************************************************/
209 {
210  // Initialise class members
211  init_members();
212 
213  // Copy members
214  copy_members(array);
215 
216  // Return
217  return;
218 }
219 
220 
221 /***********************************************************************//**
222  * @brief Destructor
223  ***************************************************************************/
225 {
226  // Free members
227  free_members();
228 
229  // Return
230  return;
231 }
232 
233 
234 /*==========================================================================
235  = =
236  = Operators =
237  = =
238  ==========================================================================*/
239 
240 /***********************************************************************//**
241  * @brief Assignment operator
242  *
243  * @param[in] array Array.
244  * @return Array.
245  ***************************************************************************/
247 {
248  // Execute only if object is not identical
249  if (this != &array) {
250 
251  // Free members
252  free_members();
253 
254  // Initialise private members
255  init_members();
256 
257  // Copy members
258  copy_members(array);
259 
260  } // endif: object was not identical
261 
262  // Return this object
263  return *this;
264 }
265 
266 
267 /***********************************************************************//**
268  * @brief Equality operator
269  *
270  * @param[in] array Array.
271  * @return True if arrays are identical.
272  *
273  * Returns true if the arrays have identical shape and content.
274  ***************************************************************************/
275 bool GNdarray::operator==(const GNdarray& array) const
276 {
277  // Check of arrays have the same shape
278  bool identity = has_same_shape(array);
279 
280  // If the arrays have identical dimensions then check if all elements
281  // are identical. Break as soon as one array element differs.
282  if (identity) {
283  for (int i = 0; i < m_data.size(); ++i) {
284  if (m_data[i] != array.m_data[i]) {
285  identity = false;
286  break;
287  }
288  }
289  }
290 
291  // Return result
292  return identity;
293 }
294 
295 
296 /***********************************************************************//**
297  * @brief Non-equality operator
298  *
299  * @param[in] array Array.
300  * @return True if arrays are different.
301  *
302  * Returns true if the arrays have different shape or content.
303  ***************************************************************************/
304 bool GNdarray::operator!=(const GNdarray& array) const
305 {
306  // Get negated result of equality operation
307  bool difference = !(this->operator==(array));
308 
309  // Return result
310  return difference;
311 }
312 
313 
314 /***********************************************************************//**
315  * @brief Unary addition operator
316  *
317  * @param[in] array Array.
318  * @return Array.
319  *
320  * Adds an array to the current array.
321  ***************************************************************************/
323 {
324  // Throw an exception if the arrays have not the same shape
326 
327  // Add elements
328  for (int i = 0; i < m_data.size(); ++i) {
329  m_data[i] += array.m_data[i];
330  }
331 
332  // Return array
333  return *this;
334 }
335 
336 
337 /***********************************************************************//**
338  * @brief Unary multiplication operator
339  *
340  * @param[in] array Array.
341  * @return Array.
342  *
343  * Multiply an array by the current array.
344  ***************************************************************************/
346 {
347  // Throw an exception if the arrays have not the same shape
349 
350  // Multiply elements
351  for (int i = 0; i < m_data.size(); ++i) {
352  m_data[i] *= array.m_data[i];
353  }
354 
355  // Return array
356  return *this;
357 }
358 
359 
360 /***********************************************************************//**
361  * @brief Unary division operator
362  *
363  * @param[in] array Array.
364  * @return Array.
365  *
366  * Divide current array by array.
367  ***************************************************************************/
369 {
370  // Throw an exception if the arrays have not the same shape
372 
373  // Divide elements
374  for (int i = 0; i < m_data.size(); ++i) {
375 
376  // Only proceed if second array is non zero
377  if (array.m_data[i] != 0.0){
378  m_data[i] /= array.m_data[i];
379  }
380 
381  // ... otherwise set ratio to 0
382  else {
383  m_data[i] = 0.0;
384  }
385 
386  } // endfor: looped over array elements
387 
388  // Return array
389  return *this;
390 }
391 
392 
393 /***********************************************************************//**
394  * @brief Unary subtraction operator
395  *
396  * @param[in] array Array.
397  * @return Array.
398  *
399  * Subtracts an array from the current array.
400  ***************************************************************************/
402 {
403  // Throw an exception if the arrays have not the same shape
405 
406  // Subtract elements
407  for (int i = 0; i < m_data.size(); ++i) {
408  m_data[i] -= array.m_data[i];
409  }
410 
411  // Return array
412  return *this;
413 }
414 
415 
416 /***********************************************************************//**
417  * @brief Unary value addition operator
418  *
419  * @param[in] value Value.
420  * @return Array.
421  *
422  * Adds a value to all array elements.
423  ***************************************************************************/
424 GNdarray& GNdarray::operator+=(const double& value)
425 {
426  // Add value to elements
427  for (int i = 0; i < m_data.size(); ++i) {
428  m_data[i] += value;
429  }
430 
431  // Return array
432  return *this;
433 }
434 
435 
436 /***********************************************************************//**
437  * @brief Unary value subtraction operator
438  *
439  * @param[in] value Value.
440  * @return Array.
441  *
442  * Subtracts a value from all array elements.
443  ***************************************************************************/
444 GNdarray& GNdarray::operator-=(const double& value)
445 {
446  // Subtract value from elements
447  for (int i = 0; i < m_data.size(); ++i) {
448  m_data[i] -= value;
449  }
450 
451  // Return array
452  return *this;
453 }
454 
455 
456 /***********************************************************************//**
457  * @brief Unary multiplication operator
458  *
459  * @param[in] value Value.
460  * @return Array.
461  *
462  * Multiply all array elements by a value.
463  ***************************************************************************/
464 GNdarray& GNdarray::operator*=(const double& value)
465 {
466  // Multiply all elements
467  for (int i = 0; i < m_data.size(); ++i) {
468  m_data[i] *= value;
469  }
470 
471  // Return array
472  return *this;
473 }
474 
475 
476 /***********************************************************************//**
477  * @brief Unary division operator
478  *
479  * @param[in] value Value.
480  * @return Array.
481  *
482  * Divide all array elements by a value.
483  ***************************************************************************/
484 GNdarray& GNdarray::operator/=(const double& value)
485 {
486  // Divide all elements
487  for (int i = 0; i < m_data.size(); ++i) {
488  m_data[i] /= value;
489  }
490 
491  // Return array
492  return *this;
493 }
494 
495 
496 /***********************************************************************//**
497  * @brief Unary minus operator
498  *
499  * @return Array.
500  *
501  * Negate all array elements.
502  ***************************************************************************/
504 {
505  // Copy array
506  GNdarray result = *this;
507 
508  // Negate all elements
509  for (int i = 0; i < m_data.size(); ++i) {
510  result.m_data[i] = -result.m_data[i];
511  }
512 
513  // Return array
514  return result;
515 }
516 
517 
518 /*==========================================================================
519  = =
520  = Public methods =
521  = =
522  ==========================================================================*/
523 
524 /***********************************************************************//**
525  * @brief Clear array
526  ***************************************************************************/
527 void GNdarray::clear(void)
528 {
529  // Free members
530  free_members();
531 
532  // Initialise private members
533  init_members();
534 
535  // Return
536  return;
537 }
538 
539 
540 /***********************************************************************//**
541  * @brief Clone array
542  *
543  * @return Pointer to deep copy of array.
544  ***************************************************************************/
546 {
547  // Clone array
548  return new GNdarray(*this);
549 }
550 
551 
552 /***********************************************************************//**
553  * @brief Set shape of array
554  *
555  * @param[in] shape Shape vector.
556  *
557  * @exception GException::invalid_argument
558  * Invalid shape factorisation specified.
559  *
560  * Set the shape of the array. The shape specifies how the information is
561  * arranged in a n-dimensional array.
562  ***************************************************************************/
563 void GNdarray::shape(const std::vector<int>& shape)
564 {
565  // Computes the number of array elements
566  int nelements = 0;
567  if (shape.size() > 0) {
568  nelements = 1;
569  for (int i = 0; i < shape.size(); ++i) {
570  nelements *= shape[i];
571  }
572  }
573 
574  // Throw an exception if resulting number of elements is not equal to
575  // the existing number of elements
576  if (nelements != size()) {
577  std::string msg = "Number of elements "+gammalib::str(nelements)+
578  " in specified shape is not identical to the "
579  "number of elements "+gammalib::str(size())+
580  " in the array.";
582  }
583 
584  // Set shape
585  m_shape = shape;
586 
587  // Return
588  return;
589 }
590 
591 
592 /***********************************************************************//**
593  * @brief 1-dimensional array element access with range checking
594  * (const version)
595  *
596  * @param[in] ix Element index [0,...,shape(0)-1].
597  * @return Const reference to array element.
598  *
599  * @exception GException::invalid_value
600  * Array is not 1-dimensional.
601  * @exception GException::out_of_range
602  * Element index is out of range.
603  ***************************************************************************/
604 const double& GNdarray::at(const int& ix) const
605 {
606  // Throw an exception if the array is not 1-dimensional
607  if (m_shape.size() != 1) {
608  std::string msg = "Invalid access of "+
609  gammalib::str(m_shape.size())+"-dimensional array "
610  "with 1-dimensional access operator.";
611  throw GException::invalid_value(G_AT1, msg);
612  }
613 
614  // Throw an exception if the index is outside the valid range
615  if (ix < 0 || ix >= m_shape[0]) {
616  throw GException::out_of_range(G_AT1, "Array index", ix, m_shape[0]);
617  }
618 
619  // Return array element
620  return (*this)(ix);
621 }
622 
623 
624 /***********************************************************************//**
625  * @brief 2-dimensional array element access with range checking
626  * (const version)
627  *
628  * @param[in] ix Index in first dimension [0,...,shape(0)-1].
629  * @param[in] iy Index in second dimension [0,...,shape(1)-1].
630  * @return Const reference to array element.
631  *
632  * @exception GException::invalid_value
633  * Array is not 2-dimensional.
634  * @exception GException::out_of_range
635  * Element index is out of range.
636  ***************************************************************************/
637 const double& GNdarray::at(const int& ix, const int& iy) const
638 {
639  // Throw an exception if the array is not 2-dimensional
640  if (m_shape.size() != 2) {
641  std::string msg = "Invalid access of "+
642  gammalib::str(m_shape.size())+"-dimensional array "
643  "with 2-dimensional access operator.";
644  throw GException::invalid_value(G_AT2, msg);
645  }
646 
647  // Throw an exception if the indices are outside the valid range
648  if (ix < 0 || ix >= m_shape[0]) {
649  throw GException::out_of_range(G_AT2, "First array index", ix,
650  m_shape[0]);
651  }
652  if (iy < 0 || iy >= m_shape[1]) {
653  throw GException::out_of_range(G_AT2, "Second array index", iy,
654  m_shape[1]);
655  }
656 
657  // Return array element
658  return (*this)(ix,iy);
659 }
660 
661 
662 /***********************************************************************//**
663  * @brief 3-dimensional array element access with range checking
664  * (const version)
665  *
666  * @param[in] ix Index in first dimension [0,...,shape(0)-1].
667  * @param[in] iy Index in second dimension [0,...,shape(1)-1].
668  * @param[in] iz Index in third dimension [0,...,shape(2)-1].
669  * @return Const reference to array element.
670  *
671  * @exception GException::invalid_value
672  * Array is not 3-dimensional.
673  * @exception GException::out_of_range
674  * Element index is out of range.
675  ***************************************************************************/
676 const double& GNdarray::at(const int& ix, const int& iy, const int& iz) const
677 {
678  // Throw an exception if the array is not 2-dimensional
679  if (m_shape.size() != 3) {
680  std::string msg = "Invalid access of "+
681  gammalib::str(m_shape.size())+"-dimensional array "
682  "with 3-dimensional access operator.";
683  throw GException::invalid_value(G_AT3, msg);
684  }
685 
686  // Throw an exception if the indices are outside the valid range
687  if (ix < 0 || ix >= m_shape[0]) {
688  throw GException::out_of_range(G_AT3, "First array index", ix,
689  m_shape[0]);
690  }
691  if (iy < 0 || iy >= m_shape[1]) {
692  throw GException::out_of_range(G_AT3, "Second array index", iy,
693  m_shape[1]);
694  }
695  if (iz < 0 || iz >= m_shape[2]) {
696  throw GException::out_of_range(G_AT3, "Third array index", iz,
697  m_shape[2]);
698  }
699 
700  // Return array element
701  return (*this)(ix,iy,iz);
702 }
703 
704 
705 /***********************************************************************//**
706  * @brief n-dimensional array element access with range checking
707  * (const version)
708  *
709  * @param[in] i Index vector.
710  * @return Const reference to array element.
711  *
712  * @exception GException::invalid_value
713  * Array is not of correct dimension.
714  * @exception GException::out_of_range
715  * Element index is out of range.
716  ***************************************************************************/
717 const double& GNdarray::at(const std::vector<int>& i) const
718 {
719  // Throw an exception if the array is not 2-dimensional
720  if (m_shape.size() != i.size()) {
721  std::string msg = "Invalid access of "+
722  gammalib::str(m_shape.size())+"-dimensional array "
723  "with "+
724  gammalib::str(i.size())+"-dimensional access "
725  "operator.";
726  throw GException::invalid_value(G_ATN, msg);
727  }
728 
729  // Throw an exception if the indices are outside the valid range
730  for (int k = 0; k < m_shape.size(); ++k) {
731  if (i[k] < 0 || i[k] >= m_shape[k]) {
732  throw GException::out_of_range(G_ATN, "Dimension "+
733  gammalib::str(k)+" index",
734  i[k], m_shape[k]);
735  }
736  }
737 
738  // Return array element
739  return (*this)(i);
740 }
741 
742 
743 /***********************************************************************//**
744  * @brief Compute array element index
745  *
746  * @param[in] i Index vector.
747  * @return Array element index.
748  *
749  * Computes the array element index from an index vector. The method assumes
750  * that the index vector has the same dimension as the array. If this
751  * condition is not guaranteed, the condition needs to be checked before
752  * calling the method.
753  ***************************************************************************/
754 int GNdarray::index(const std::vector<int>& i) const
755 {
756  // Initialise element index
757  int index = 0;
758 
759  // Compute element index
760  for (int k = 0; k < m_shape.size(); ++k) {
761  index += m_strides[k] * i[k];
762  }
763 
764  // Return index
765  return index;
766 }
767 
768 
769 /***********************************************************************//**
770 * @brief Compute index vector
771 *
772 * @param[in] index Array element index.
773 * @return Index vector.
774 *
775 * Computes index vector from an array element index.
776 ***************************************************************************/
777 std::vector<int> GNdarray::index(const int& index) const
778 {
779  // Get number of array dimensions
780  int dim = m_shape.size();
781 
782  // Set working index
783  int inx = index;
784 
785  // Initialise index vector
786  std::vector<int> i(dim, 0);
787 
788  // Compute index vector
789  for (int k = dim-1; k >= 0; --k) {
790  int strides = m_strides[k];
791  i[k] = inx / strides;
792  inx -= strides * i[k];
793  }
794 
795  // Return index vector
796  return i;
797 }
798 
799 
800 /***********************************************************************//**
801  * @brief Print array information
802  *
803  * @param[in] chatter Chattiness.
804  * @return String containing array information.
805  ***************************************************************************/
806 std::string GNdarray::print(const GChatter& chatter) const
807 {
808  // Initialise result string
809  std::string result = "(";
810 
811  // Continue only if chatter is not silent
812  if (chatter != SILENT) {
813 
814  // Put all elements in string
815  for (int i = 0; i < m_data.size(); ++i) {
816  if (i > 0) {
817  result += ", ";
818  }
819  result += gammalib::str(m_data[i]);
820  }
821 
822  // Append closing parentheses
823  result += ")";
824 
825  } // endif: chatter was not silent
826 
827  // Return result
828  return result;
829 }
830 
831 
832 /*==========================================================================
833  = =
834  = Private methods =
835  = =
836  ==========================================================================*/
837 
838 /***********************************************************************//**
839  * @brief Initialise class members
840  ***************************************************************************/
842 {
843  // Initialise members
844  m_shape.clear();
845  m_strides.clear();
846  m_data.clear();
847 
848  // Actually reallocate the memory of m_data
849  std::vector<double>(m_data).swap(m_data);
850 
851  // Return
852  return;
853 }
854 
855 
856 /***********************************************************************//**
857  * @brief Copy class members
858  *
859  * @param[in] array Array.
860  ***************************************************************************/
862 {
863  // Copy members
864  m_shape = array.m_shape;
865  m_strides = array.m_strides;
866  m_data = array.m_data;
867 
868  // Return
869  return;
870 }
871 
872 
873 /***********************************************************************//**
874  * @brief Delete class members
875  ***************************************************************************/
877 {
878  // Return
879  return;
880 }
881 
882 
883 /***********************************************************************//**
884  * @brief Check if array has the same shape
885  *
886  * @param[in] array Array.
887  * @return True if the array has the same shape.
888  ***************************************************************************/
889 bool GNdarray::has_same_shape(const GNdarray& array) const
890 {
891  // Check if the array has the same dimension
892  bool identity = m_shape.size() == array.m_shape.size();
893 
894  // Check if the shape is identical. Break as soon as one shape value
895  // differs.
896  if (identity) {
897  for (int i = 0; i < m_shape.size(); ++i) {
898  if (m_shape[i] != array.m_shape[i]) {
899  identity = false;
900  break;
901  }
902  }
903  }
904 
905  // Return result
906  return identity;
907 }
908 
909 
910 /***********************************************************************//**
911  * @brief Throw exception if array shapes differ
912  *
913  * @param[in] method Method that throws exception.
914  * @param[in] array Array.
915  ***************************************************************************/
916 void GNdarray::require_same_shape(const std::string& method,
917  const GNdarray& array) const
918 {
919  // If the shape differs then throw an exception
920  if (!has_same_shape(array)) {
921 
922  // Compose exception message
923  std::string msg = "Incompatible array dimensions (";
924  for (int i = 0; i < m_shape.size(); ++i) {
925  if (i > 0) {
926  msg += ", ";
927  }
928  msg += gammalib::str(m_shape[i]);
929  }
930  msg += ") <=> (";
931  for (int i = 0; i < array.m_shape.size(); ++i) {
932  if (i > 0) {
933  msg += ", ";
934  }
935  msg += gammalib::str(array.m_shape[i]);
936  }
937  msg += ").";
938 
939  // Throw exception
940  throw GException::invalid_argument(method, msg);
941 
942  } // endif: array shapes differed
943 
944  // Return
945  return;
946 }
947 
948 
949 /*==========================================================================
950  = =
951  = Friends =
952  = =
953  ==========================================================================*/
954 
955 /***********************************************************************//**
956  * @brief Computes minimum array element
957  *
958  * @param[in] array Array.
959  * @return Minimum array element.
960  ***************************************************************************/
961 double min(const GNdarray& array)
962 {
963  // Initialises result
964  double result = 0.0;
965 
966  // Continue only if we have elements
967  if (array.m_data.size() > 0) {
968 
969  // Search for minimum
970  result = array.m_data[0];
971  for (int i = 1; i < array.m_data.size(); ++i) {
972  if (array.m_data[i] < result) {
973  result = array.m_data[i];
974  }
975  }
976 
977  } // endif: there were elements
978 
979  // Returns minimum
980  return result;
981 }
982 
983 
984 /***********************************************************************//**
985  * @brief Computes maximum array element
986  *
987  * @param[in] array Array.
988  * @return Maximum array element.
989  ***************************************************************************/
990 double max(const GNdarray& array)
991 {
992  // Initialises result
993  double result = 0.0;
994 
995  // Continue only if we have elements
996  if (array.m_data.size() > 0) {
997 
998  // Search for maximum
999  result = array.m_data[0];
1000  for (int i = 1; i < array.m_data.size(); ++i) {
1001  if (array.m_data[i] > result) {
1002  result = array.m_data[i];
1003  }
1004  }
1005 
1006  } // endif: there were elements
1007 
1008  // Returns maximum
1009  return result;
1010 }
1011 
1012 
1013 /***********************************************************************//**
1014  * @brief Computes array sum
1015  *
1016  * @param[in] array Array.
1017  * @return Sum of array elements.
1018  ***************************************************************************/
1019 double sum(const GNdarray& array)
1020 {
1021  // Compute sum
1022  double result = 0.0;
1023  for (int i = 0; i < array.m_data.size(); ++i) {
1024  result += array.m_data[i];
1025  }
1026 
1027  // Returns sum
1028  return result;
1029 }
1030 
1031 
1032 /***********************************************************************//**
1033  * @brief Computes arccos of array elements
1034  *
1035  * @param[in] array Array.
1036  * @return Array containing the arccos of every element.
1037  ***************************************************************************/
1038 GNdarray acos(const GNdarray& array)
1039 {
1040  // Initialise result array
1041  GNdarray result = array;
1042 
1043  // Evaluate each array element
1044  for (int i = 0; i < array.m_data.size(); ++i) {
1045  result.m_data[i] = std::acos(array.m_data[i]);
1046  }
1047 
1048  // Return array
1049  return result;
1050 }
1051 
1052 
1053 /***********************************************************************//**
1054  * @brief Computes acosh of array elements
1055  *
1056  * @param[in] array Array.
1057  * @return Array containing the acosh of every element.
1058  ***************************************************************************/
1059 GNdarray acosh(const GNdarray& array)
1060 {
1061  // Initialise result array
1062  GNdarray result = array;
1063 
1064  // Evaluate each array element
1065  for (int i = 0; i < array.m_data.size(); ++i) {
1066  result.m_data[i] = acosh(array.m_data[i]);
1067  }
1068 
1069  // Return array
1070  return result;
1071 }
1072 
1073 
1074 /***********************************************************************//**
1075  * @brief Computes arcsin of array elements
1076  *
1077  * @param[in] array Array.
1078  * @return Array containing the arcsin of every element.
1079  ***************************************************************************/
1080 GNdarray asin(const GNdarray& array)
1081 {
1082  // Initialise result array
1083  GNdarray result = array;
1084 
1085  // Evaluate each array element
1086  for (int i = 0; i < array.m_data.size(); ++i) {
1087  result.m_data[i] = std::asin(array.m_data[i]);
1088  }
1089 
1090  // Return array
1091  return result;
1092 }
1093 
1094 
1095 /***********************************************************************//**
1096  * @brief Computes asinh of array elements
1097  *
1098  * @param[in] array Array.
1099  * @return Array containing the asinh of every element.
1100  ***************************************************************************/
1101 GNdarray asinh(const GNdarray& array)
1102 {
1103  // Initialise result array
1104  GNdarray result = array;
1105 
1106  // Evaluate each array element
1107  for (int i = 0; i < array.m_data.size(); ++i) {
1108  result.m_data[i] = asinh(array.m_data[i]);
1109  }
1110 
1111  // Return array
1112  return result;
1113 }
1114 
1115 
1116 /***********************************************************************//**
1117  * @brief Computes arctan of array elements
1118  *
1119  * @param[in] array Array.
1120  * @return Array containing the arctan of every element.
1121  ***************************************************************************/
1122 GNdarray atan(const GNdarray& array)
1123 {
1124  // Initialise result array
1125  GNdarray result = array;
1126 
1127  // Evaluate each array element
1128  for (int i = 0; i < array.m_data.size(); ++i) {
1129  result.m_data[i] = std::atan(array.m_data[i]);
1130  }
1131 
1132  // Return array
1133  return result;
1134 }
1135 
1136 
1137 /***********************************************************************//**
1138  * @brief Computes atanh of array elements
1139  *
1140  * @param[in] array Array.
1141  * @return Array containing the atanh of every element.
1142  ***************************************************************************/
1143 GNdarray atanh(const GNdarray& array)
1144 {
1145  // Initialise result array
1146  GNdarray result = array;
1147 
1148  // Evaluate each array element
1149  for (int i = 0; i < array.m_data.size(); ++i) {
1150  result.m_data[i] = atanh(array.m_data[i]);
1151  }
1152 
1153  // Return array
1154  return result;
1155 }
1156 
1157 
1158 /***********************************************************************//**
1159  * @brief Computes cosine of array elements
1160  *
1161  * @param[in] array Array.
1162  * @return Array containing the cosine of every element.
1163  ***************************************************************************/
1164 GNdarray cos(const GNdarray& array)
1165 {
1166  // Initialise result array
1167  GNdarray result = array;
1168 
1169  // Evaluate each array element
1170  for (int i = 0; i < array.m_data.size(); ++i) {
1171  result.m_data[i] = std::cos(array.m_data[i]);
1172  }
1173 
1174  // Return array
1175  return result;
1176 }
1177 
1178 
1179 /***********************************************************************//**
1180  * @brief Computes cosh of array elements
1181  *
1182  * @param[in] array Array.
1183  * @return Array containing the cosh of every element.
1184  ***************************************************************************/
1185 GNdarray cosh(const GNdarray& array)
1186 {
1187  // Initialise result array
1188  GNdarray result = array;
1189 
1190  // Evaluate each array element
1191  for (int i = 0; i < array.m_data.size(); ++i) {
1192  result.m_data[i] = std::cosh(array.m_data[i]);
1193  }
1194 
1195  // Return array
1196  return result;
1197 }
1198 
1199 
1200 /***********************************************************************//**
1201  * @brief Computes exponential of array elements
1202  *
1203  * @param[in] array Array.
1204  * @return Array containing the exponential of every element.
1205  ***************************************************************************/
1206 GNdarray exp(const GNdarray& array)
1207 {
1208  // Initialise result array
1209  GNdarray result = array;
1210 
1211  // Evaluate each array element
1212  for (int i = 0; i < array.m_data.size(); ++i) {
1213  result.m_data[i] = std::exp(array.m_data[i]);
1214  }
1215 
1216  // Return array
1217  return result;
1218 }
1219 
1220 
1221 /***********************************************************************//**
1222  * @brief Computes absolute of array elements
1223  *
1224  * @param[in] array Array.
1225  * @return Array containing the absolute of every element.
1226  ***************************************************************************/
1227 GNdarray abs(const GNdarray& array)
1228 {
1229  // Initialise result array
1230  GNdarray result = array;
1231 
1232  // Evaluate each array element
1233  for (int i = 0; i < array.m_data.size(); ++i) {
1234  result.m_data[i] = std::abs(array.m_data[i]);
1235  }
1236 
1237  // Return array
1238  return result;
1239 }
1240 
1241 
1242 /***********************************************************************//**
1243  * @brief Computes natural logarithm of array elements
1244  *
1245  * @param[in] array Array.
1246  * @return Array containing the natural logarithm of every element.
1247  ***************************************************************************/
1248 GNdarray log(const GNdarray& array)
1249 {
1250  // Initialise result array
1251  GNdarray result = array;
1252 
1253  // Evaluate each array element
1254  for (int i = 0; i < array.m_data.size(); ++i) {
1255  result.m_data[i] = std::log(array.m_data[i]);
1256  }
1257 
1258  // Return array
1259  return result;
1260 }
1261 
1262 
1263 /***********************************************************************//**
1264  * @brief Computes sign of array elements
1265  *
1266  * @param[in] array Array.
1267  * @return Array containing the sign of every element.
1268  ***************************************************************************/
1269 GNdarray sign(const GNdarray& array)
1270 {
1271  // Initialise result array
1272  GNdarray result = array;
1273 
1274  // Evaluate each array element
1275  for (int i = 0; i < array.m_data.size(); ++i) {
1276 
1277  // Get array content
1278  double content = array.m_data[i];
1279 
1280  // Initialise sign
1281  double sign;
1282 
1283  // Handle the 3 cases
1284  if (content < 0.0) {
1285  sign = -1.0;
1286  }
1287  else if (content > 0.0) {
1288  sign = +1.0;
1289  }
1290  else {
1291  sign = 0.0;
1292  }
1293 
1294  // Store sign
1295  result.m_data[i] = sign;
1296 
1297  } // endfor: looped over all array elements
1298 
1299  // Return array
1300  return result;
1301 }
1302 
1303 
1304 /***********************************************************************//**
1305  * @brief Computes base10 logarithm of array elements
1306  *
1307  * @param[in] array Array.
1308  * @return Array containing the base10 logarithm of every element.
1309  ***************************************************************************/
1310 GNdarray log10(const GNdarray& array)
1311 {
1312  // Initialise result array
1313  GNdarray result = array;
1314 
1315  // Evaluate each array element
1316  for (int i = 0; i < array.m_data.size(); ++i) {
1317  result.m_data[i] = std::log10(array.m_data[i]);
1318  }
1319 
1320  // Return array
1321  return result;
1322 }
1323 
1324 
1325 /***********************************************************************//**
1326  * @brief Computes sine of array elements
1327  *
1328  * @param[in] array Array.
1329  * @return Array containing the sine of every element.
1330  ***************************************************************************/
1331 GNdarray sin(const GNdarray& array)
1332 {
1333  // Initialise result array
1334  GNdarray result = array;
1335 
1336  // Evaluate each array element
1337  for (int i = 0; i < array.m_data.size(); ++i) {
1338  result.m_data[i] = std::sin(array.m_data[i]);
1339  }
1340 
1341  // Return array
1342  return result;
1343 }
1344 
1345 
1346 /***********************************************************************//**
1347  * @brief Computes sinh of array elements
1348  *
1349  * @param[in] array Array.
1350  * @return Array containing the sinh of every element.
1351  ***************************************************************************/
1352 GNdarray sinh(const GNdarray& array)
1353 {
1354  // Initialise result array
1355  GNdarray result = array;
1356 
1357  // Evaluate each array element
1358  for (int i = 0; i < array.m_data.size(); ++i) {
1359  result.m_data[i] = std::sinh(array.m_data[i]);
1360  }
1361 
1362  // Return array
1363  return result;
1364 }
1365 
1366 
1367 /***********************************************************************//**
1368  * @brief Computes square root of array elements
1369  *
1370  * @param[in] array Array.
1371  * @return Array containing the square root of every element.
1372  ***************************************************************************/
1373 GNdarray sqrt(const GNdarray& array)
1374 {
1375  // Initialise result array
1376  GNdarray result = array;
1377 
1378  // Evaluate each array element
1379  for (int i = 0; i < array.m_data.size(); ++i) {
1380  result.m_data[i] = std::sqrt(array.m_data[i]);
1381  }
1382 
1383  // Return array
1384  return result;
1385 }
1386 
1387 
1388 /***********************************************************************//**
1389  * @brief Computes tangens of array elements
1390  *
1391  * @param[in] array Array.
1392  * @return Array containing the tangens of every element.
1393  ***************************************************************************/
1394 GNdarray tan(const GNdarray& array)
1395 {
1396  // Initialise result array
1397  GNdarray result = array;
1398 
1399  // Evaluate each array element
1400  for (int i = 0; i < array.m_data.size(); ++i) {
1401  result.m_data[i] = std::tan(array.m_data[i]);
1402  }
1403 
1404  // Return array
1405  return result;
1406 }
1407 
1408 
1409 /***********************************************************************//**
1410  * @brief Computes tanh of array elements
1411  *
1412  * @param[in] array Array.
1413  * @return Array containing the tanh of every element.
1414  ***************************************************************************/
1415 GNdarray tanh(const GNdarray& array)
1416 {
1417  // Initialise result array
1418  GNdarray result = array;
1419 
1420  // Evaluate each array element
1421  for (int i = 0; i < array.m_data.size(); ++i) {
1422  result.m_data[i] = std::tanh(array.m_data[i]);
1423  }
1424 
1425  // Return array
1426  return result;
1427 }
1428 
1429 
1430 /***********************************************************************//**
1431  * @brief Computes tanh of array elements
1432  *
1433  * @param[in] array Array.
1434  * @param[in] power Power.
1435  * @return Array containing the power of every element.
1436  ***************************************************************************/
1437 GNdarray pow(const GNdarray& array, const double& power)
1438 {
1439  // Initialise result array
1440  GNdarray result = array;
1441 
1442  // Evaluate each array element
1443  for (int i = 0; i < array.m_data.size(); ++i) {
1444  result.m_data[i] = std::pow(array.m_data[i], power);
1445  }
1446 
1447  // Return array
1448  return result;
1449 }
GVector acosh(const GVector &vector)
Computes acosh of vector elements.
Definition: GVector.cpp:1085
const std::vector< int > & strides(void) const
Return strides of array.
Definition: GNdarray.hpp:322
GVector sinh(const GVector &vector)
Computes sinh of vector elements.
Definition: GVector.cpp:1337
bool operator!=(const GNdarray &array) const
Non-equality operator.
Definition: GNdarray.cpp:304
void clear(void)
Clear array.
Definition: GNdarray.cpp:527
#define G_AT2
Definition: GNdarray.cpp:43
GVector abs(const GVector &vector)
Computes absolute of vector elements.
Definition: GVector.cpp:1253
#define G_OP_ADD
Definition: GNdarray.cpp:37
GVector cos(const GVector &vector)
Computes cosine of vector elements.
Definition: GVector.cpp:1190
void free_members(void)
Delete class members.
Definition: GNdarray.cpp:876
GNdarray * clone(void) const
Clone array.
Definition: GNdarray.cpp:545
#define G_OP_DIV
Definition: GNdarray.cpp:40
double sum(const GVector &vector)
Computes vector sum.
Definition: GVector.cpp:944
double acos(const double &arg)
Computes acos by avoiding NaN due to rounding errors.
Definition: GMath.cpp:69
Gammalib tools definition.
const std::vector< int > & shape(void) const
Return shape of array.
Definition: GNdarray.hpp:308
double min(const GVector &vector)
Computes minimum vector element.
Definition: GVector.cpp:886
#define G_ATN
Definition: GNdarray.cpp:45
std::vector< int > m_shape
Array dimensions.
Definition: GNdarray.hpp:136
void copy_members(const GNdarray &array)
Copy class members.
Definition: GNdarray.cpp:861
#define G_AT3
Definition: GNdarray.cpp:44
#define G_AT1
Definition: GNdarray.cpp:42
double & at(const int &ix)
1-dimensional array element access with range checking
Definition: GNdarray.hpp:335
GNdarray & operator-=(const GNdarray &array)
Unary subtraction operator.
Definition: GNdarray.cpp:401
std::vector< double > m_data
Array data.
Definition: GNdarray.hpp:138
GVector sqrt(const GVector &vector)
Computes square root of vector elements.
Definition: GVector.cpp:1358
GNdarray & operator/=(const GNdarray &array)
Unary division operator.
Definition: GNdarray.cpp:368
GNdarray & operator=(const GNdarray &array)
Assignment operator.
Definition: GNdarray.cpp:246
void require_same_shape(const std::string &method, const GNdarray &array) const
Throw exception if array shapes differ.
Definition: GNdarray.cpp:916
GVector tan(const GVector &vector)
Computes tangens of vector elements.
Definition: GVector.cpp:1379
N-dimensional array class interface definition.
#define G_OP_SUB
Definition: GNdarray.cpp:38
GVector log(const GVector &vector)
Computes natural logarithm of vector elements.
Definition: GVector.cpp:1274
GNdarray sign(const GNdarray &array)
Computes sign of array elements.
Definition: GNdarray.cpp:1269
std::string print(const GChatter &chatter=NORMAL) const
Print array information.
Definition: GNdarray.cpp:806
bool operator==(const GNdarray &array) const
Equality operator.
Definition: GNdarray.cpp:275
int size(void) const
Return number of elements in array.
Definition: GNdarray.hpp:294
GChatter
Definition: GTypemaps.hpp:33
GNdarray(void)
Void constructor.
Definition: GNdarray.cpp:57
N-dimensional array class.
Definition: GNdarray.hpp:44
double max(const GVector &vector)
Computes maximum vector element.
Definition: GVector.cpp:915
GVector asin(const GVector &vector)
Computes arcsin of vector elements.
Definition: GVector.cpp:1106
GNdarray & operator*=(const GNdarray &array)
Unary multiplication operator.
Definition: GNdarray.cpp:345
GVector tanh(const GVector &vector)
Computes tanh of vector elements.
Definition: GVector.cpp:1400
GVector atanh(const GVector &vector)
Computes atanh of vector elements.
Definition: GVector.cpp:1169
GVector cosh(const GVector &vector)
Computes cosh of vector elements.
Definition: GVector.cpp:1211
GVector asinh(const GVector &vector)
Computes asinh of vector elements.
Definition: GVector.cpp:1127
int index(const std::vector< int > &i) const
Compute array element index.
Definition: GNdarray.cpp:754
GVector pow(const GVector &vector, const double &power)
Computes tanh of vector elements.
Definition: GVector.cpp:1422
bool has_same_shape(const GNdarray &array) const
Check if array has the same shape.
Definition: GNdarray.cpp:889
GVector sin(const GVector &vector)
Computes sine of vector elements.
Definition: GVector.cpp:1316
Exception handler interface definition.
void init_members(void)
Initialise class members.
Definition: GNdarray.cpp:841
GVector exp(const GVector &vector)
Computes exponential of vector elements.
Definition: GVector.cpp:1232
GNdarray & operator+=(const GNdarray &array)
Unary addition operator.
Definition: GNdarray.cpp:322
virtual ~GNdarray(void)
Destructor.
Definition: GNdarray.cpp:224
int dim(void) const
Return dimension of array.
Definition: GNdarray.hpp:280
GVector atan(const GVector &vector)
Computes arctan of vector elements.
Definition: GVector.cpp:1148
#define G_OP_MUL
Definition: GNdarray.cpp:39
GNdarray operator-(void) const
Unary minus operator.
Definition: GNdarray.cpp:503
#define G_SHAPE
Definition: GNdarray.cpp:41
std::vector< int > m_strides
Steps in each dimension when traversing array.
Definition: GNdarray.hpp:137
GVector log10(const GVector &vector)
Computes base10 logarithm of vector elements.
Definition: GVector.cpp:1295
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489