//# ArrayMath.h: ArrayMath: Simple mathematics done on an entire array. //# Copyright (C) 1993,1994,1995,1996,1998,1999,2001,2003 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ #ifndef CASA_ARRAYMATH_2_H #define CASA_ARRAYMATH_2_H #include "Array.h" #include #include #include #include namespace casacore { //# NAMESPACE CASACORE - BEGIN // // Mathematical operations for Arrays. // // // // //
  • Array // // // // This file contains global functions which perform element by element // mathematical operations on arrays. // // // // These functions perform element by element mathematical operations on // arrays. The two arrays must conform. // // Furthermore it defines functions a la std::transform to transform one or // two arrays by means of a unary or binary operator. All math and logical // operations on arrays can be expressed by means of these transform functions. //
    It also defines an in-place transform function because for non-trivial // iterators it works faster than a transform where the result is an iterator // on the same data object as the left operand. //
    The transform functions distinguish between contiguous and non-contiguous // arrays because iterating through a contiguous array can be done in a faster // way. //
    Similar to the standard transform function these functions do not check // if the shapes match. The user is responsible for that. //
    // // // // Vector a(10); // Vector b(10); // Vector c(10); // . . . // c = a + b; // // This example sets the elements of c to (a+b). It checks if a and b have the // same shape. // The result of this operation is an Array. // // // // // c = arrayTransformResult (a, b, std::plus()); // // This example does the same as the previous example, but expressed using // the transform function (which, in fact, is used by the + operator above). // However, it is not checked if the shapes match. // // // // arrayContTransform (a, b, c, std::plus()); // // This example does the same as the previous example, but is faster because // the result array already exists and does not need to be allocated. // Note that the caller must be sure that c is contiguous. // // // // Vector a(10); // Vector b(10); // Vector c(10); // . . . // c = atan2 (a, b); // // This example sets the elements of c to atan2 (a,b). // The result of this operation is an Array. // // // // // Vector a(10); // int result; // . . . // result = sum (a); // // This example sums a. // // // // One wants to be able to perform mathematical operations on arrays. // // // // Array mathematical operations -- Mathematical operations for // Arrays. // // // // The myxtransform functions are defined to avoid a bug in g++-4.3. // That compiler generates incorrect code when only -g is used for // a std::transform with a bind1st or bind2nd for a complex. // So, for example, the multiplication of a std::complex array and std::complex scalar // would fail (see g++ bug 39678). // // sequence = scalar OP sequence template void myltransform(_InputIterator1 __first1, _InputIterator1 __last1, _OutputIterator __result, T left, _BinaryOperation __binary_op) { for ( ; __first1 != __last1; ++__first1, ++__result) *__result = __binary_op(left, *__first1); } // sequence = sequence OP scalar template void myrtransform(_InputIterator1 __first1, _InputIterator1 __last1, _OutputIterator __result, T right, _BinaryOperation __binary_op) { for ( ; __first1 != __last1; ++__first1, ++__result) *__result = __binary_op(*__first1, right); } // sequence OP= scalar template void myiptransform(_InputIterator1 __first1, _InputIterator1 __last1, T right, _BinaryOperation __binary_op) { for ( ; __first1 != __last1; ++__first1) *__first1 = __binary_op(*__first1, right); } // // Functions to apply a binary or unary operator to arrays. // They are modeled after std::transform. // They do not check if the shapes conform; as in std::transform the // user must take care that the operands conform. // // Transform left and right to a result using the binary operator. // Result MUST be a contiguous array. template inline void arrayContTransform (const Array& left, const Array& right, Array& result, BinaryOperator op) { assert (result.contiguousStorage()); if (left.contiguousStorage() && right.contiguousStorage()) { std::transform (left.cbegin(), left.cend(), right.cbegin(), result.cbegin(), op); } else { std::transform (left.begin(), left.end(), right.begin(), result.cbegin(), op); } } // Transform left and right to a result using the binary operator. // Result MUST be a contiguous array. template inline void arrayContTransform (const Array& left, R right, Array& result, BinaryOperator op) { assert (result.contiguousStorage()); if (left.contiguousStorage()) { myrtransform (left.cbegin(), left.cend(), result.cbegin(), right, op); //// std::transform (left.cbegin(), left.cend(), //// result.cbegin(), bind2nd(op, right)); } else { myrtransform (left.begin(), left.end(), result.cbegin(), right, op); //// std::transform (left.begin(), left.end(), //// result.cbegin(), bind2nd(op, right)); } } // Transform left and right to a result using the binary operator. // Result MUST be a contiguous array. template inline void arrayContTransform (L left, const Array& right, Array& result, BinaryOperator op) { assert (result.contiguousStorage()); if (right.contiguousStorage()) { myltransform (right.cbegin(), right.cend(), result.cbegin(), left, op); //// std::transform (right.cbegin(), right.cend(), //// result.cbegin(), bind1st(op, left)); } else { myltransform (right.begin(), right.end(), result.cbegin(), left, op); //// std::transform (right.begin(), right.end(), //// result.cbegin(), bind1st(op, left)); } } // Transform array to a result using the unary operator. // Result MUST be a contiguous array. template inline void arrayContTransform (const Array& arr, Array& result, UnaryOperator op) { assert (result.contiguousStorage()); if (arr.contiguousStorage()) { std::transform (arr.cbegin(), arr.cend(), result.cbegin(), op); } else { std::transform (arr.begin(), arr.end(), result.cbegin(), op); } } // Transform left and right to a result using the binary operator. // Result need not be a contiguous array. template void arrayTransform (const Array& left, const Array& right, Array& result, BinaryOperator op); // Transform left and right to a result using the binary operator. // Result need not be a contiguous array. template void arrayTransform (const Array& left, R right, Array& result, BinaryOperator op); // Transform left and right to a result using the binary operator. // Result need not be a contiguous array. template void arrayTransform (L left, const Array& right, Array& result, BinaryOperator op); // Transform array to a result using the unary operator. // Result need not be a contiguous array. template void arrayTransform (const Array& arr, Array& result, UnaryOperator op); // Transform left and right to a result using the binary operator. // The created and returned result array is contiguous. template Array arrayTransformResult (const Array& left, const Array& right, BinaryOperator op); // Transform left and right to a result using the binary operator. // The created and returned result array is contiguous. template Array arrayTransformResult (const Array& left, T right, BinaryOperator op); // Transform left and right to a result using the binary operator. // The created and returned result array is contiguous. template Array arrayTransformResult (T left, const Array& right, BinaryOperator op); // Transform array to a result using the unary operator. // The created and returned result array is contiguous. template Array arrayTransformResult (const Array& arr, UnaryOperator op); // Transform left and right in place using the binary operator. // The result is stored in the left array (useful for e.g. the += operation). template inline void arrayTransformInPlace (Array& left, const Array& right, BinaryOperator op) { if (left.contiguousStorage() && right.contiguousStorage()) { std::transform(left.cbegin(), left.cend(), right.cbegin(), left.cbegin(), op); } else { std::transform(left.begin(), left.end(), right.begin(), left.begin(), op); } } // Transform left and right in place using the binary operator. // The result is stored in the left array (useful for e.g. the += operation). template inline void arrayTransformInPlace (Array& left, R right, BinaryOperator op) { if (left.contiguousStorage()) { myiptransform (left.cbegin(), left.cend(), right, op); //// transformInPlace (left.cbegin(), left.cend(), bind2nd(op, right)); } else { myiptransform (left.begin(), left.end(), right, op); //// transformInPlace (left.begin(), left.end(), bind2nd(op, right)); } } // Transform the array in place using the unary operator. // E.g. doing arrayTransformInPlace(array, Sin()) is faster than // array=sin(array) as it does not need to create a temporary array. template inline void arrayTransformInPlace (Array& arr, UnaryOperator op) { if (arr.contiguousStorage()) { std::transform(arr.cbegin(), arr.cend(), arr.cbegin(), op); } else { std::transform(arr.begin(), arr.end(), arr.begin(), op); } } // // // Element by element arithmetic modifying left in-place. left and other // must be conformant. // template void operator+= (Array &left, const Array &other); template void operator-= (Array &left, const Array &other); template void operator*= (Array &left, const Array &other) { checkArrayShapes (left, other, "*="); arrayTransformInPlace (left, other, std::multiplies()); } template void operator/= (Array &left, const Array &other) { checkArrayShapes (left, other, "/="); arrayTransformInPlace (left, other, std::divides()); } template void operator%= (Array &left, const Array &other); template void operator&= (Array &left, const Array &other); template void operator|= (Array &left, const Array &other); template void operator^= (Array &left, const Array &other); // // // Element by element arithmetic modifying left in-place. The scalar "other" // behaves as if it were a conformant Array to left filled with constant values. // template void operator+= (Array &left, const T &other); template void operator-= (Array &left, const T &other); template void operator*= (Array &left, const T &other) { arrayTransformInPlace (left, other, std::multiplies()); } template void operator/= (Array &left, const T &other) { arrayTransformInPlace (left, other, std::divides()); } template void operator%= (Array &left, const T &other); template void operator&= (Array &left, const T &other); template void operator|= (Array &left, const T &other); template void operator^= (Array &left, const T &other); // // Unary arithmetic operation. // // template Array operator+(const Array &a); template Array operator-(const Array &a); template Array operator~(const Array &a); // // // Element by element arithmetic on two arrays, returning an array. // template Array operator+ (const Array &left, const Array &right); template Array operator- (const Array &left, const Array &right); template Array operator*(const Array &left, const Array &right) { checkArrayShapes (left, right, "*"); return arrayTransformResult (left, right, std::multiplies()); } template Array operator/ (const Array &left, const Array &right); template Array operator% (const Array &left, const Array &right); template Array operator| (const Array &left, const Array &right); template Array operator& (const Array &left, const Array &right); template Array operator^ (const Array &left, const Array &right); // // // Element by element arithmetic between an array and a scalar, returning // an array. // template Array operator+ (const Array &left, const T &right); template Array operator- (const Array &left, const T &right); template Array operator* (const Array &left, const T &right) { return arrayTransformResult (left, right, std::multiplies()); } template Array operator/ (const Array &left, const T &right); template Array operator% (const Array &left, const T &right); template Array operator| (const Array &left, const T &right); template Array operator& (const Array &left, const T &right); template Array operator^ (const Array &left, const T &right); // // // Element by element arithmetic between a scalar and an array, returning // an array. // template Array operator+ (const T &left, const Array &right); template Array operator- (const T &left, const Array &right); template Array operator* (const T &left, const Array &right) { return arrayTransformResult (left, right, std::multiplies()); } template Array operator/ (const T &left, const Array &right); template Array operator% (const T &left, const Array &right); template Array operator| (const T &left, const Array &right); template Array operator& (const T &left, const Array &right); template Array operator^ (const T &left, const Array &right); // // // Transcendental function that can be applied to essentially all numeric // types. Works on an element-by-element basis. // template Array cos(const Array &a); template Array cosh(const Array &a); template Array exp(const Array &a); template Array log(const Array &a); template Array log10(const Array &a); template Array pow(const Array &a, const Array &b); template Array pow(const T &a, const Array &b); template Array sin(const Array &a); template Array sinh(const Array &a); template Array sqrt(const Array &a); // // // Transcendental function applied to the array on an element-by-element // basis. Although a template function, this does not make sense for all // numeric types. // template Array acos(const Array &a); template Array asin(const Array &a); template Array atan(const Array &a); template Array atan2(const Array &y, const Array &x); template Array atan2(const T &y, const Array &x); template Array atan2(const Array &y, const T &x); template Array ceil(const Array &a); template Array fabs(const Array &a); template Array abs(const Array &a); template Array floor(const Array &a); template Array round(const Array &a); template Array sign(const Array &a); template Array fmod(const Array &a, const Array &b); template Array fmod(const T &a, const Array &b); template Array fmod(const Array &a, const T &b); template Array floormod(const Array &a, const Array &b); template Array floormod(const T &a, const Array &b); template Array floormod(const Array &a, const T &b); template Array pow(const Array &a, const double &b); template Array tan(const Array &a); template Array tanh(const Array &a); // N.B. fabs is deprecated. Use abs. template Array fabs(const Array &a); // // // // Find the minimum and maximum values of an array, including their locations. template void minMax(ScalarType &minVal, ScalarType &maxVal, IPosition &minPos, IPosition &maxPos, const Array &array); // The array is searched at locations where the mask equals valid. // (at least one such position must exist or an exception will be thrown). // MaskType should be an Array of bool. template void minMax(ScalarType &minVal, ScalarType &maxVal, IPosition &minPos, IPosition &maxPos, const Array &array, const Array &mask, bool valid=true); // The array * weight is searched template void minMaxMasked(ScalarType &minVal, ScalarType &maxVal, IPosition &minPos, IPosition &maxPos, const Array &array, const Array &weight); // // // The "min" and "max" functions require that the type "T" have comparison // operators. // // // This sets min and max to the minimum and maximum of the array to // avoid having to do two passes with max() and min() separately. template void minMax(T &min, T &max, const Array &a); // // The minimum element of the array. // Requires that the type "T" has comparison operators. template T min(const Array &a); // The maximum element of the array. // Requires that the type "T" has comparison operators. template T max(const Array &a); // "result" contains the maximum of "a" and "b" at each position. "result", // "a", and "b" must be conformant. template void max(Array &result, const Array &a, const Array &b); // "result" contains the minimum of "a" and "b" at each position. "result", // "a", and "b" must be conformant. template void min(Array &result, const Array &a, const Array &b); // Return an array that contains the maximum of "a" and "b" at each position. // "a" and "b" must be conformant. template Array max(const Array &a, const Array &b); template Array max(const T &a, const Array &b); // Return an array that contains the minimum of "a" and "b" at each position. // "a" and "b" must be conformant. template Array min(const Array &a, const Array &b); // "result" contains the maximum of "a" and "b" at each position. "result", // and "a" must be conformant. template void max(Array &result, const Array &a, const T &b); template inline void max(Array &result, const T &a, const Array &b) { max (result, b, a); } // "result" contains the minimum of "a" and "b" at each position. "result", // and "a" must be conformant. template void min(Array &result, const Array &a, const T &b); template inline void min(Array &result, const T &a, const Array &b) { min (result, b, a); } // Return an array that contains the maximum of "a" and "b" at each position. template Array max(const Array &a, const T &b); template inline Array max(const T &a, const Array &b) { return max(b, a); } // Return an array that contains the minimum of "a" and "b" at each position. template Array min(const Array &a, const T &b); template inline Array min(const T &a, const Array &b) { return min(b, a); } // // // Fills all elements of "array" with a sequence starting with "start" // and incrementing by "inc" for each element. The first axis varies // most rapidly. template void indgen(Array &a, T start, T inc); // // Fills all elements of "array" with a sequence starting with 0 // and ending with nelements() - 1. The first axis varies // most rapidly. template inline void indgen(Array &a) { indgen(a, T(0), T(1)); } // // Fills all elements of "array" with a sequence starting with start // incremented by one for each position in the array. The first axis varies // most rapidly. template inline void indgen(Array &a, T start) { indgen(a, start, T(1)); } // Create a Vector of the given length and fill it with the start value // incremented with inc for each element. template> inline Vector indgen(size_t length, T start, T inc) { Vector x(length); indgen(x, start, inc); return x; } // Sum of every element of the array. template T sum(const Array &a); // // Sum the square of every element of the array. template T sumsqr(const Array &a); // // Product of every element of the array. This could of course easily // overflow. template T product(const Array &a); // // The mean of "a" is the sum of all elements of "a" divided by the number // of elements of "a". template T mean(const Array &a); // The variance of "a" is the sum of (a(i) - mean(a))**2/(a.nelements() - ddof). // Similar to numpy the argument ddof (delta degrees of freedom) tells if the // population variance (ddof=0) or the sample variance (ddof=1) is taken. // The variance functions proper use ddof=1. //
    Note that for a complex valued T the absolute values are used; in that way // the variance is equal to the sum of the variances of the real and imaginary parts. // Hence the imaginary part in the return value is 0. template T variance(const Array &a); template T pvariance(const Array &a, size_t ddof=0); // Rather than using a computed mean, use the supplied value. template T variance(const Array &a, T mean); template T pvariance(const Array &a, T mean, size_t ddof=0); // The standard deviation of "a" is the square root of its variance. template T stddev(const Array &a); template T pstddev(const Array &a, size_t ddof=0); template T stddev(const Array &a, T mean); template T pstddev(const Array &a, T mean, size_t ddof=0); // // The average deviation of "a" is the sum of abs(a(i) - mean(a))/N. (N.B. // N, not N-1 in the denominator). template T avdev(const Array &a); // // The average deviation of "a" is the sum of abs(a(i) - mean(a))/N. (N.B. // N, not N-1 in the denominator). // Rather than using a computed mean, use the supplied value. template T avdev(const Array &a,T mean); // // The root-mean-square of "a" is the sqrt of sum(a*a)/N. template T rms(const Array &a); // The median of "a" is a(n/2). // If a has an even number of elements and the switch takeEvenMean is set, // the median is 0.5*(a(n/2) + a((n+1)/2)). // According to Numerical Recipes (2nd edition) it makes little sense to take // the mean if the array is large enough (> 100 elements). Therefore // the default for takeEvenMean is false if the array has > 100 elements, // otherwise it is true. //
    If "sorted"==true we assume the data is already sorted and we // compute the median directly. Otherwise the function GenSort::kthLargest // is used to find the median (kthLargest is about 6 times faster // than a full quicksort). //
    Finding the median means that the array has to be (partially) // sorted. By default a copy will be made, but if "inPlace" is in effect, // the data themselves will be sorted. That should only be used if the // data are used not thereafter. // The function kthLargest in class GenSortIndirect can be used to // obtain the index of the median in an array. // // TODO shouldn't take a const Array for in place sorting template T median(const Array &a, std::vector &scratch, bool sorted, bool takeEvenMean, bool inPlace=false); // TODO shouldn't take a const Array for in place sorting template T median(const Array &a, bool sorted, bool takeEvenMean, bool inPlace=false) { std::vector scratch; return median (a, scratch, sorted, takeEvenMean, inPlace); } template inline T median(const Array &a, bool sorted) { return median (a, sorted, (a.nelements() <= 100), false); } template inline T median(const Array &a) { return median (a, false, (a.nelements() <= 100), false); } // TODO shouldn't take a const Array for in place sorting template inline T medianInPlace(const Array &a, bool sorted=false) { return median (a, sorted, (a.nelements() <= 100), true); } // // The median absolute deviation from the median. Interface is as for // the median functions // // TODO shouldn't take a const Array for in place sorting template T madfm(const Array &a, std::vector &tmp, bool sorted, bool takeEvenMean, bool inPlace = false); // TODO shouldn't take a const Array for in place sorting template T madfm(const Array &a, bool sorted, bool takeEvenMean, bool inPlace=false) { std::vector tmp; return madfm(a, tmp, sorted, takeEvenMean, inPlace); } template inline T madfm(const Array &a, bool sorted) { return madfm(a, sorted, (a.nelements() <= 100), false); } template inline T madfm(const Array &a) { return madfm(a, false, (a.nelements() <= 100), false); } // TODO shouldn't take a const Array for in place sorting template inline T madfmInPlace(const Array &a, bool sorted=false) { return madfm(a, sorted, (a.nelements() <= 100), true); } // // Return the fractile of an array. // It returns the value at the given fraction of the array. // A fraction of 0.5 is the same as the median, be it that no mean of // the two middle elements is taken if the array has an even nr of elements. // It uses kthLargest if the array is not sorted yet. // The function kthLargest in class GenSortIndirect can be used to // obtain the index of the fractile in an array. // TODO shouldn't take a const Array for in place sorting template T fractile(const Array &a, std::vector &tmp, float fraction, bool sorted=false, bool inPlace=false); // TODO shouldn't take a const Array for in place sorting template T fractile(const Array &a, float fraction, bool sorted=false, bool inPlace=false) { std::vector tmp; return fractile (a, tmp, fraction, sorted, inPlace); } // Return the inter-fractile range of an array. // This is the full range between the bottom and the top fraction. // // TODO shouldn't take a const Array for in place sorting template T interFractileRange(const Array &a, std::vector &tmp, float fraction, bool sorted=false, bool inPlace=false); // TODO shouldn't take a const Array for in place sorting template T interFractileRange(const Array &a, float fraction, bool sorted=false, bool inPlace=false) { std::vector tmp; return interFractileRange(a, tmp, fraction, sorted, inPlace); } // // Return the inter-hexile range of an array. // This is the full range between the bottom sixth and the top sixth // of ordered array values. "The semi-interhexile range is very nearly // equal to the rms for a Gaussian distribution, but it is much less // sensitive to the tails of extended distributions." (Condon et al // 1998) // // TODO shouldn't take a const Array for in place sorting template T interHexileRange(const Array &a, std::vector &tmp, bool sorted=false, bool inPlace=false) { return interFractileRange(a, tmp, 1./6., sorted, inPlace); } // TODO shouldn't take a const Array for in place sorting template T interHexileRange(const Array &a, bool sorted=false, bool inPlace=false) { return interFractileRange(a, 1./6., sorted, inPlace); } // // Return the inter-quartile range of an array. // This is the full range between the bottom quarter and the top // quarter of ordered array values. // // TODO shouldn't take a const Array for in place sorting template T interQuartileRange(const Array &a, std::vector &tmp, bool sorted=false, bool inPlace=false) { return interFractileRange(a, tmp, 0.25, sorted, inPlace); } // TODO shouldn't take a const Array for in place sorting template T interQuartileRange(const Array &a, bool sorted=false, bool inPlace=false) { return interFractileRange(a, 0.25, sorted, inPlace); } // // Methods for element-by-element scaling of complex and real. // Note that std::complex and std::complex are typedefs for std::complex. // template void operator*= (Array, AllocC> &left, const Array &other) { checkArrayShapes (left, other, "*="); arrayTransformInPlace (left, other, [](std::complex left, T right) { return left*right; }); } template void operator*= (Array, Alloc> &left, const T &other) { arrayTransformInPlace (left, other, [](std::complex left, T right) { return left*right; }); } template void operator/= (Array, AllocC> &left, const Array &other) { checkArrayShapes (left, other, "/="); arrayTransformInPlace (left, other, [](std::complex left, T right) { return left/right; }); } template void operator/= (Array, Alloc> &left, const T &other) { arrayTransformInPlace (left, other, [](std::complex left, T right) { return left/right; }); } template Array, AllocC> operator* (const Array, AllocC> &left, const Array &right) { checkArrayShapes (left, right, "*"); Array, AllocC> result(left.shape()); arrayContTransform (left, right, result, [](std::complex left, T right) { return left*right; }); return result; } template Array > operator* (const Array, Alloc> &left, const T &other) { Array > result(left.shape()); arrayContTransform (left, other, result, [](std::complex left, T right) { return left*right; }); return result; } template Array > operator*(const std::complex &left, const Array &other) { Array > result(other.shape()); arrayContTransform (left, other, result, [](std::complex left, T right) { return left*right; }); return result; } template Array, AllocC> operator/ (const Array, AllocC> &left, const Array &right) { checkArrayShapes (left, right, "/"); Array, AllocC> result(left.shape()); arrayContTransform (left, right, result, [](std::complex l, T r) { return l/r; }); return result; } template Array, Alloc> operator/ (const Array, Alloc> &left, const T &other) { Array, Alloc> result(left.shape()); arrayContTransform (left, other, result, [](std::complex left, T right) { return left/right; }); return result; } template Array> operator/(const std::complex &left, const Array &other) { Array> result(other.shape()); arrayContTransform (left, other, result, [](std::complex left, T right) { return left/right; }); return result; } // // Returns the complex conjugate of a complex array. // Array> conj(const Array> &carray); Array> conj(const Array> &carray); // Modifies rarray in place. rarray must be conformant. void conj(Array> &rarray, const Array> &carray); void conj(Array> &rarray, const Array> &carray); //# The following are implemented to make the compiler find the right conversion //# more often. Matrix> conj(const Matrix> &carray); Matrix> conj(const Matrix> &carray); // // Form an array of complex numbers from the given real arrays. // Note that std::complex and std::complex are simply typedefs for std::complex // and std::complex, so the result is in fact one of these types. // template Array > makeComplex(const Array &real, const Array& imag); template Array > makeComplex(const T &real, const Array& imag); template Array > makeComplex(const Array &real, const T& imag); // // Set the real part of the left complex array to the right real array. template void setReal(Array &carray, const Array &rarray); // Set the imaginary part of the left complex array to right real array. template void setImag(Array &carray, const Array &rarray); // Extracts the real part of a complex array into an array of floats. // Array real(const Array> &carray); Array real(const Array> &carray); // Modifies rarray in place. rarray must be conformant. void real(Array &rarray, const Array> &carray); void real(Array &rarray, const Array> &carray); // // // Extracts the imaginary part of a complex array into an array of floats. // Array imag(const Array> &carray); Array imag(const Array> &carray); // Modifies rarray in place. rarray must be conformant. void imag(Array &rarray, const Array> &carray); void imag(Array &rarray, const Array> &carray); // // // Extracts the amplitude (i.e. sqrt(re*re + im*im)) from an array // of complex numbers. N.B. this is presently called "fabs" for a single // complex number. // Array amplitude(const Array> &carray); Array amplitude(const Array> &carray); // Modifies rarray in place. rarray must be conformant. void amplitude(Array &rarray, const Array> &carray); void amplitude(Array &rarray, const Array> &carray); // // // Extracts the phase (i.e. atan2(im, re)) from an array // of complex numbers. N.B. this is presently called "arg" // for a single complex number. // Array phase(const Array> &carray); Array phase(const Array> &carray); // Modifies rarray in place. rarray must be conformant. void phase(Array &rarray, const Array> &carray); void phase(Array &rarray, const Array> &carray); // // Copy an array of complex into an array of real,imaginary pairs. The // first axis of the real array becomes twice as long as the complex array. // In the future versions which work by reference will be available; presently // a copy is made. Array ComplexToReal(const Array> &carray); Array ComplexToReal(const Array> &carray); // Modify the array "rarray" in place. "rarray" must be the correct shape. // void ComplexToReal(Array &rarray, const Array> &carray); void ComplexToReal(Array &rarray, const Array> &carray); // // Copy an array of real,imaginary pairs into a complex array. The first axis // must have an even length. // In the future versions which work by reference will be available; presently // a copy is made. Array> RealToComplex(const Array &rarray); Array> RealToComplex(const Array &rarray); // Modify the array "carray" in place. "carray" must be the correct shape. // void RealToComplex(Array> &carray, const Array &rarray); void RealToComplex(Array> &carray, const Array &rarray); // // Make a copy of an array of a different type; for example make an array // of doubles from an array of floats. Arrays to and from must be conformant // (same shape). Also, it must be possible to convert a scalar of type U // to type T. template void convertArray(Array &to, const Array &from); // Returns an array where every element is squared. template Array square(const Array &val); // Returns an array where every element is cubed. template Array cube(const Array &val); // Helper function for expandArray using recursion for each axis. template T* expandRecursive (int axis, const IPosition& shp, const IPosition& mult, const IPosition& inSteps, const T* in, T* out, const IPosition& alternate) { if (axis == 0) { if (alternate[0]) { // Copy as 1,2,3 1,2,3, etc. for (ssize_t j=0; jmult is set to output/input. //
    The alternate argument determines how the values are expanded. // If a row contains values '1 2 3', they can be expanded "linearly" // as '1 1 2 2 3 3' or alternately as '1 2 3 1 2 3' // This choice can be made for each axis; a value 0 means linearly, // another value means alternately. If the length of alternate is less than // the dimensionality of the output array, the missing ones default to 0. template void expandArray (Array& out, const Array& in, const IPosition& alternate=IPosition()) { IPosition mult, inshp, outshp; IPosition alt = checkExpandArray (mult, inshp, in.shape(), out.shape(), alternate); Array incp(in); if (in.ndim() < inshp.size()) { incp.reference (in.reform(inshp)); } // Make sure output is contiguous. bool deleteIt; T* outPtr = out.getStorage (deleteIt); expandRecursive (out.ndim()-1, inshp, mult, incp.steps(), incp.data(), outPtr, alt); out.putStorage (outPtr, deleteIt); } // Check array shapes for expandArray. It returns the alternate argument, // where possibly missing values are appended (as 0). // It fills in mult and inshp (with possibly missing axes of length 1). //
    inShape defines the shape of the input array. //
    outShape defines the shape of the output array. //
    alternate tells per axis if value expansion uses alternation. //
    newInShape is the input shape with new axes (of length 1) added as needed //
    mult is the multiplication (expansion) factor per output axis // Returned is the alternation per output axis; new axes have value 0 (linear expansion) IPosition checkExpandArray (IPosition& mult, IPosition& newInShape, const IPosition& inShape, const IPosition& outShape, const IPosition& alternate); //
    } //# NAMESPACE CASACORE - END #include "ArrayMath.tcc" #endif