//# ArrayMath.cc: Arithmetic functions defined on Arrays //# Copyright (C) 1993,1994,1995,1996,1997,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_TCC #define CASA_ARRAYMATH_2_TCC #include "ArrayMath.h" #include "Array.h" #include "ArrayIter.h" #include "ArrayUtil.h" #include "VectorIter.h" #include "ArrayError.h" #include "ElementFunctions.h" #include #include #include #include namespace casacore { //# NAMESPACE CASACORE - BEGIN template void arrayTransform (const Array& left, const Array& right, Array& result, BinaryOperator op) { if (result.contiguousStorage()) { arrayContTransform (left, right, result, op); } else { if (left.contiguousStorage() && right.contiguousStorage()) { std::transform (left.cbegin(), left.cend(), right.cbegin(), result.begin(), op); } else { std::transform (left.begin(), left.end(), right.begin(), result.begin(), op); } } } template void arrayTransform (const Array& left, R right, Array& result, BinaryOperator op) { if (result.contiguousStorage()) { arrayContTransform (left, right, result, op); } else { if (left.contiguousStorage()) { myrtransform (left.cbegin(), left.cend(), result.begin(), right, op); } else { myrtransform (left.begin(), left.end(), result.begin(), right, op); } } } template void arrayTransform (L left, const Array& right, Array& result, BinaryOperator op) { if (result.contiguousStorage()) { arrayContTransform (left, right, result, op); } else { if (right.contiguousStorage()) { myltransform (right.cbegin(), right.cend(), result.begin(), left, op); } else { myltransform (right.begin(), right.end(), result.begin(), left, op); } } } template void arrayTransform (const Array& arr, Array& result, UnaryOperator op) { if (result.contiguousStorage()) { arrayContTransform (arr, result, op); } else { if (arr.contiguousStorage()) { std::transform (arr.cbegin(), arr.cend(), result.begin(), op); } else { std::transform (arr.begin(), arr.end(), result.begin(), op); } } } template Array arrayTransformResult (const Array& left, const Array& right, BinaryOperator op) { Array res(left.shape()); arrayContTransform (left, right, res, op); return res; } template Array arrayTransformResult (const Array& left, T right, BinaryOperator op) { Array res(left.shape()); arrayContTransform (left, right, res, op); return res; } template Array arrayTransformResult (T left, const Array& right, BinaryOperator op) { Array res(right.shape()); arrayContTransform (left, right, res, op); return res; } template Array arrayTransformResult (const Array& arr, UnaryOperator op) { Array res(arr.shape()); arrayContTransform (arr, res, op); return res; } // // ArrayError // template void minMax(T &minVal, T &maxVal, IPosition &minPos, IPosition &maxPos, const Array &array) { size_t n = array.nelements(); if (n == 0) { throw(ArrayError("void minMax(T &min, T &max, IPosition &minPos," "IPosition &maxPos, const Array &array) - " "Array has no elements")); } size_t minp = 0; size_t maxp = 0; T minv = array.data()[0]; T maxv = minv; if (array.contiguousStorage()) { typename Array::const_contiter iter = array.cbegin(); for (size_t i=0; i maxv) { maxv = *iter; maxp = i; } } } else { typename Array::const_iterator iter = array.begin(); for (size_t i=0; i maxv) { maxv = *iter; maxp = i; } } } minPos.resize (array.ndim()); maxPos.resize (array.ndim()); minPos = toIPositionInArray (minp, array.shape()); maxPos = toIPositionInArray (maxp, array.shape()); minVal = minv; maxVal = maxv; } // // ArrayError // template void minMaxMasked(T &minVal, T &maxVal, IPosition &minPos, IPosition &maxPos, const Array &array, const Array &weight) { size_t n = array.nelements(); if (n == 0) { throw(ArrayError("void minMax(T &min, T &max, IPosition &minPos," "IPosition &maxPos, const Array &array) - " "const Array &weight) - " "Array has no elements")); } if (! array.shape().isEqual (weight.shape())) { throw(ArrayConformanceError("void minMaxMasked(T &min, T &max," "IPosition &minPos, IPosition &maxPos, " "const Array &array, " "const Array &weight) - array " "and weight do not have the same shape()")); } size_t minp = 0; size_t maxp = 0; T minv = array.data()[0] * weight.data()[0]; T maxv = minv; if (array.contiguousStorage() && weight.contiguousStorage()) { typename Array::const_contiter iter = array.cbegin(); typename Array::const_contiter witer = weight.cbegin(); for (size_t i=0; i maxv) { maxv = tmp; maxp = i; } } } else { typename Array::const_iterator iter = array.begin(); typename Array::const_iterator witer = weight.begin(); for (size_t i=0; i maxv) { maxv = tmp; maxp = i; } } } minPos.resize (array.ndim()); maxPos.resize (array.ndim()); minPos = toIPositionInArray (minp, array.shape()); maxPos = toIPositionInArray (maxp, array.shape()); minVal = minv; maxVal = maxv; } // // ArrayError // AipsError // template void minMax(T &minVal, T &maxVal, IPosition &minPos, IPosition &maxPos, const Array &array, const Array &mask, bool valid) { size_t n = array.nelements(); if (n == 0) { throw(ArrayError("void minMax(T &min, T &max, IPosition &minPos," "IPosition &maxPos, const Array &array, " "const Array &mask) - " "Array has no elements")); } if (! array.shape().isEqual (mask.shape())) { throw(ArrayConformanceError("void minMax(T &min, T &max," "IPosition &minPos, IPosition &maxPos," "const Array &array, " "const Array &mask) - " "array and mask do not have the same shape()")); } size_t minp; size_t maxp; T minv = T(); T maxv = T(); if (array.contiguousStorage() && mask.contiguousStorage()) { typename Array::const_contiter iter = array.cbegin(); typename Array::const_contiter miter = mask.cbegin(); size_t i=0; for (; i maxv) { maxv = *iter; maxp = i; } } } } else { typename Array::const_iterator iter = array.begin(); typename Array::const_iterator miter = mask.begin(); size_t i=0; for (; i maxv) { maxv = *iter; maxp = i; } } } } if (minp ==n) { throw(std::runtime_error("void minMax(T &min, T &max," "IPosition &minPos, IPosition &maxPos," "const Array &array, " "const Array &mask) - no valid array elements")); } minPos.resize (array.ndim()); maxPos.resize (array.ndim()); minPos = toIPositionInArray (minp, array.shape()); maxPos = toIPositionInArray (maxp, array.shape()); minVal = minv; maxVal = maxv; } // // ArrayConformanceError // template void operator+= (Array &left, const Array &other) { checkArrayShapes (left, other, "+="); arrayTransformInPlace (left, other, std::plus()); } template T min(const Array &a) { T Min, Max; minMax(Min, Max, a); return Min; } template T max(const Array &a) { T Min, Max; minMax(Min, Max, a); return Max; } template void operator+= (Array &left, const T &other) { arrayTransformInPlace (left, other, std::plus()); } // // ArrayConformanceError // template void operator-= (Array &left, const Array &other) { checkArrayShapes (left, other, "-="); arrayTransformInPlace (left, other, std::minus()); } template void operator-= (Array &left, const T &other) { arrayTransformInPlace (left, other, std::minus()); } // // ArrayConformanceError // template void operator%= (Array &left, const Array &other) { checkArrayShapes (left, other, "%="); arrayTransformInPlace (left, other, std::modulus()); } template void operator%= (Array &left, const T &other) { arrayTransformInPlace (left, other, std::modulus()); } // // ArrayConformanceError // template void operator&= (Array &left, const Array &other) { checkArrayShapes (left, other, "&="); arrayTransformInPlace (left, other, [](T a, T b){ return a&b; }); } template void operator&= (Array &left, const T &other) { arrayTransformInPlace (left, other, [](T a, T b){ return a&b; }); } // // ArrayConformanceError // template void operator|= (Array &left, const Array &other) { checkArrayShapes (left, other, "|="); arrayTransformInPlace (left, other, [](T a, T b){ return a|b; }); } template void operator|= (Array &left, const T &other) { arrayTransformInPlace (left, other, [](T a, T b){ return a|b; }); } // // ArrayConformanceError // template void operator^= (Array &left, const Array &other) { checkArrayShapes (left, other, "^="); arrayTransformInPlace (left, other, [](T a, T b){ return a^b; }); } template void operator^= (Array &left, const T &other) { arrayTransformInPlace (left, other, [](T a, T b){ return a^b; }); } template Array operator+(const Array &a) { return a.copy(); } template Array operator-(const Array &a) { return arrayTransformResult (a, std::negate()); } template Array operator~(const Array &a) { return arrayTransformResult (a, [](T val) { return ~val; }); // bit_not would be nicer, but is C++14 } // // ArrayConformanceError // template Array operator+(const Array &left, const Array &right) { checkArrayShapes (left, right, "+"); return arrayTransformResult (left, right, std::plus()); } // // ArrayConformanceError // template Array operator-(const Array &left, const Array &right) { checkArrayShapes (left, right, "-"); return arrayTransformResult (left, right, std::minus()); } // // ArrayConformanceError // template Array operator/(const Array &left, const Array &right) { checkArrayShapes (left, right, "/"); return arrayTransformResult (left, right, std::divides()); } template Array operator%(const Array &left, const Array &right) { checkArrayShapes (left, right, "%"); return arrayTransformResult (left, right, std::modulus()); } template Array operator&(const Array &left, const Array &right) { checkArrayShapes (left, right, "%"); return arrayTransformResult (left, right, [](T a, T b){ return a&b; }); } template Array operator|(const Array &left, const Array &right) { checkArrayShapes (left, right, "%"); return arrayTransformResult (left, right, [](T a, T b){ return a|b; }); } template Array operator^(const Array &left, const Array &right) { checkArrayShapes (left, right, "%"); return arrayTransformResult (left, right, [](T a, T b){ return a^b; }); } template Array operator+ (const Array &left, const T &right) { return arrayTransformResult (left, right, std::plus()); } template Array operator- (const Array &left, const T &right) { return arrayTransformResult (left, right, std::minus()); } template Array operator/ (const Array &left, const T &right) { return arrayTransformResult (left, right, std::divides()); } template Array operator% (const Array &left, const T &right) { return arrayTransformResult (left, right, std::modulus()); } template Array operator& (const Array &left, const T &right) { return arrayTransformResult (left, right, [](T a, T b){ return a&b; }); } template Array operator| (const Array &left, const T &right) { return arrayTransformResult (left, right, [](T a, T b){ return a|b; }); } template Array operator^ (const Array &left, const T &right) { return arrayTransformResult (left, right, [](T a, T b){ return a^b; }); } template Array operator+ (const T &left, const Array &right) { return arrayTransformResult (left, right, std::plus()); } template Array operator- (const T &left, const Array &right) { return arrayTransformResult (left, right, std::minus()); } template Array operator/ (const T &left, const Array &right) { return arrayTransformResult (left, right, std::divides()); } template Array operator% (const T &left, const Array &right) { return arrayTransformResult (left, right, std::modulus()); } template Array operator& (const T &left, const Array &right) { return arrayTransformResult (left, right, [](T a, T b){ return a&b; }); } template Array operator| (const T &left, const Array &right) { return arrayTransformResult (left, right, [](T a, T b){ return a|b; }); } template Array operator^ (const T &left, const Array &right) { return arrayTransformResult (left, right, [](T a, T b){ return a^b; }); } // // ArrayError // template void minMax(T &minVal, T &maxVal, const Array &array) { if (array.nelements() == 0) { throw(ArrayError("void minMax(T &min, T &max, const Array &array) - " "Array has no elements")); } if (array.contiguousStorage()) { // minimal scope as some compilers may spill onto stack otherwise T minv = array.data()[0]; T maxv = minv; typename Array::const_contiter iterEnd = array.cend(); for (typename Array::const_contiter iter = array.cbegin(); iter!=iterEnd; ++iter) { if (*iter < minv) { minv = *iter; } // no else allows compiler to use branchless instructions if (*iter > maxv) { maxv = *iter; } } maxVal = maxv; minVal = minv; } else { T minv = array.data()[0]; T maxv = minv; typename Array::const_iterator iterEnd = array.end(); for (typename Array::const_iterator iter = array.begin(); iter!=iterEnd; ++iter) { if (*iter < minv) { minv = *iter; } if (*iter > maxv) { maxv = *iter; } } maxVal = maxv; minVal = minv; } } // // ArrayConformanceError // template void max(Array &result, const Array &a, const Array &b) { checkArrayShapes (a, b, "max"); checkArrayShapes (a, result, "max"); arrayTransform (a, b, result, [](T l, T r){ return std::max(l, r); }); } // // ArrayConformanceError // template void min(Array &result, const Array &a, const Array &b) { checkArrayShapes (a, b, "min"); checkArrayShapes (a, result, "min"); arrayTransform (a, b, result, [](T l, T r){ return std::min(l, r); }); } template Array max(const Array &a, const Array &b) { Array result(a.shape()); max(result, a, b); return result; } template Array min(const Array &a, const Array &b) { Array result(a.shape()); min(result, a, b); return result; } // // ArrayConformanceError // template void max(Array &result, const Array &a, const T &b) { checkArrayShapes (a, result, "max"); arrayTransform (a, b, result, [](T a, T b){ return std::max(a, b); }); } // // ArrayConformanceError // template void min(Array &result, const Array &a, const T &b) { checkArrayShapes (a, result, "min"); arrayTransform (a, b, result, [](T a, T b){ return std::min(a, b); }); } template Array max(const Array &a, const T &b) { Array result(a.shape()); max(result, a, b); return result; } template Array min(const Array &a, const T &b) { Array result(a.shape()); min(result, a, b); return result; } template void indgen(Array &a, T start, T inc) { if (a.contiguousStorage()) { typename Array::contiter aend = a.cend(); for (typename Array::contiter iter=a.cbegin(); iter!=aend; ++iter) { *iter = start; start += inc; } } else { typename Array::iterator aend = a.end(); for (typename Array::iterator iter=a.begin(); iter!=aend; ++iter) { *iter = start; start += inc; } } } template Array cos(const Array &a) { return arrayTransformResult (a, [](T v){ return std::cos(v); }); } template Array cosh(const Array &a) { return arrayTransformResult (a, [](T v){ return std::cosh(v); }); } template Array exp(const Array &a) { return arrayTransformResult (a, [](T v){ return std::exp(v); }); } template Array log(const Array &a) { return arrayTransformResult (a, [](T v){ return std::log(v); }); } template Array log10(const Array &a) { return arrayTransformResult (a, [](T v){ return std::log10(v); }); } template Array sin(const Array &a) { return arrayTransformResult (a, [](T v){ return std::sin(v); }); } template Array sinh(const Array &a) { return arrayTransformResult (a, [](T v){ return std::sinh(v); }); } template Array sqrt(const Array &a) { return arrayTransformResult (a, [](T a){ return std::sqrt(a);}); } template Array square(const Array &a) { return arrayTransformResult (a, [](T a){ return a*a; }); } template Array cube(const Array &a) { return arrayTransformResult (a, [](T a){ return a*a*a; }); } template Array acos(const Array &a) { return arrayTransformResult (a, [](T a){ return std::acos(a); }); } template Array asin(const Array &a) { return arrayTransformResult (a, [](T a){ return std::asin(a); }); } template Array atan(const Array &a) { return arrayTransformResult (a, [](T a){ return std::atan(a); }); } template Array ceil(const Array &a) { return arrayTransformResult (a, [](T val) { return std::ceil(val);}); } template Array fabs(const Array &a) { return arrayTransformResult (a, [](T t){ return std::abs(t); }); } template Array abs(const Array &a) { return arrayTransformResult (a, [](T t){ return std::abs(t); }); } template Array floor(const Array &a) { return arrayTransformResult (a, [](T t){ return std::floor(t); }); } template Array round(const Array &a) { return arrayTransformResult (a, [](T t){ return std::round(t); }); } template Array sign(const Array &a) { return arrayTransformResult (a, [](T value) { return (value<0 ? -1 : (value>0 ? 1:0));}); } template Array tan(const Array &a) { return arrayTransformResult (a, [](T t){ return std::tan(t); }); } template Array tanh(const Array &a) { return arrayTransformResult (a, [](T t){ return std::tanh(t); }); } // // ArrayConformanceError // template Array pow(const Array &a, const Array &b) { checkArrayShapes (a, b, "pow"); return arrayTransformResult (a, b, [](T l, T r) { return std::pow(l, r); }); } template Array pow(const T &a, const Array &b) { return arrayTransformResult (a, b, [](T l, T r) { return std::pow(l, r); }); } template Array pow(const Array &a, const double &b) { Array result(a.shape()); arrayContTransform (a, b, result, [](T l, T r) { return std::pow(l, r); }); return result; } // // ArrayConformanceError // template Array atan2(const Array &a, const Array &b) { checkArrayShapes (a, b, "atan2"); return arrayTransformResult (a, b, [](T l, T r) { return std::atan2(l,r);}); } template Array atan2(const T &a, const Array &b) { return arrayTransformResult (a, b, [](T l, T r) { return std::atan2(l,r);}); } template Array atan2(const Array &a, const T &b) { return arrayTransformResult (a, b, [](T l, T r) { return std::atan2(l,r);}); } // // ArrayConformanceError // template Array fmod(const Array &a, const Array &b) { checkArrayShapes (a, b, "fmod"); return arrayTransformResult (a, b, [](T l, T r) { return std::fmod(l,r);}); } template Array fmod(const T &a, const Array &b) { return arrayTransformResult (a, b, [](T l, T r) { return std::fmod(l,r);}); } template Array fmod(const Array &a, const T &b) { return arrayTransformResult (a, b, [](T l, T r) { return std::fmod(l,r);}); } // // ArrayConformanceError // template Array floormod(const Array &a, const Array &b) { checkArrayShapes (a, b, "floormod"); return arrayTransformResult (a, b, static_cast(arrays_internal::floormod)); } template Array floormod(const T &a, const Array &b) { return arrayTransformResult (a, b, static_cast(arrays_internal::floormod)); } template Array floormod(const Array &a, const T &b) { return arrayTransformResult (a, b, static_cast(arrays_internal::floormod)); } // // ArrayError // template T sum(const Array &a) { return a.contiguousStorage() ? std::accumulate(a.cbegin(), a.cend(), T(), std::plus()) : std::accumulate(a.begin(), a.end(), T(), std::plus()); } template T sumsqr(const Array &a) { auto sumsqr = [](T left, T right) { return left + right*right;}; return a.contiguousStorage() ? std::accumulate(a.cbegin(), a.cend(), T(), sumsqr) : std::accumulate(a.begin(), a.end(), T(), sumsqr); } // // ArrayError // template T product(const Array &a) { if (a.empty()) { return T(); } // Get first element, because T(1) may not work for all types. T prod = *a.data(); if (a.contiguousStorage()) { typename Array::const_contiter iter(a.cbegin()); ++iter; return std::accumulate(iter, a.cend(), prod, std::multiplies()); } else { typename Array::const_iterator iter(a.begin()); ++iter; return std::accumulate(iter, a.end(), prod, std::multiplies()); } } // // ArrayError // template T mean(const Array &a) { if (a.empty()) { throw(ArrayError("::mean(const Array &) - 0 element array")); } return T(sum(a)/T(1.0*a.nelements())); } // // ArrayError // // Similar to numpy the ddof argument can be used to get the population // variance (ddof=0) or the sample variance (ddof=1). template T pvariance(const Array &a, T mean, size_t ddof) { if (a.nelements() < ddof+1) { throw(ArrayError("::variance(const Array &) - Need at least " + std::to_string(ddof+1) + " elements")); } T sum = a.contiguousStorage() ? std::accumulate(a.cbegin(), a.cend(), T(), arrays_internal::SumSqrDiff(mean)) : std::accumulate(a.begin(), a.end(), T(), arrays_internal::SumSqrDiff(mean)); return T(sum/T(1.0*a.nelements() - ddof)); } template T variance(const Array &a, T mean) { return pvariance (a, mean, 1); } template T pvariance(const Array &a, size_t ddof) { return pvariance(a, mean(a), ddof); } template T variance(const Array &a) { return pvariance(a, mean(a), 1); } // // ArrayError // template T pstddev(const Array &a, T mean, size_t ddof) { if (a.nelements() < ddof+1) { throw(ArrayError("::stddev(const Array &) - Need at least " + std::to_string(ddof+1) + " elements")); } return std::sqrt(pvariance(a, mean, ddof)); } template T stddev(const Array &a, T mean) { return pstddev (a, mean, 1); } template T pstddev(const Array &a, size_t ddof) { return pstddev (a, mean(a), ddof); } template T stddev(const Array &a) { return pstddev (a, mean(a), 1); } // // ArrayError // template T avdev(const Array &a) { if (a.nelements() < 1) { throw(ArrayError("::avdev(const Array &,) - Need at least 1 " "element")); } return avdev(a, mean(a)); } // // ArrayError // template T avdev(const Array &a, T mean) { if (a.nelements() < 1) { throw(ArrayError("::avdev(const Array &,T) - Need at least 1 " "element")); } auto sumabsdiff = [mean](T left, T right) { return left + std::abs(right-mean); }; T sum = a.contiguousStorage() ? std::accumulate(a.cbegin(), a.cend(), T(), sumabsdiff) : std::accumulate(a.begin(), a.end(), T(), sumabsdiff); return T(sum/T(1.0*a.nelements())); } // // ArrayError // template T rms(const Array &a) { if (a.nelements() < 1) { throw(ArrayError("::rms(const Array &) - Need at least 1 " "element")); } auto sumsqr = [](T left, T right) { return left + right*right; }; T sum = a.contiguousStorage() ? std::accumulate(a.cbegin(), a.cend(), T(), sumsqr) : std::accumulate(a.begin(), a.end(), T(), sumsqr); return T(std::sqrt(sum/T(1.0*a.nelements()))); } // // ArrayError // template T median(const Array &a, std::vector& scratch, bool sorted, bool takeEvenMean, bool inPlace) { T medval=T(); size_t nelem = a.nelements(); if (nelem < 1) { throw(ArrayError("::median(T*) - array needs at least 1 element")); } //# Mean does not have to be taken for odd number of elements. if (nelem%2 != 0) { takeEvenMean = false; } // A copy is needed if not contiguous or if not in place. const T* storage; if (!a.contiguousStorage() || !inPlace) { a.tovector(scratch); storage = scratch.data(); } else { storage = a.data(); } T* data = const_cast(storage); size_t n2 = (nelem - 1)/2; if (!sorted) { std::nth_element(data, data+n2, data+nelem); medval = data[n2]; if (takeEvenMean) { std::nth_element(data, data+n2+1, data+nelem); medval = T(0.5 * (medval + data[n2+1])); } } else { if (takeEvenMean) { medval = T(0.5 * (data[n2] + data[n2+1])); } else { medval = data[n2]; } } return medval; } // // ArrayError // template T madfm(const Array &a, std::vector& scratch, bool sorted, bool takeEvenMean, bool inPlace) { T med = median(a, scratch, sorted, takeEvenMean, inPlace); Array atmp; if (inPlace && a.contiguousStorage()) { atmp.reference (a); // remove constness } else { // A copy of a has been made to scratch. // Using it saves computing. // (this was changed for array2: sharing storage is no longer possible) assert(a.size() == scratch.size()); atmp.resize(a.shape()); atmp.assign_conforming (Array(a.shape(), scratch.data())); } T* aptr = atmp.data(); for (size_t i=0; i // ArrayError // template T fractile(const Array &a, std::vector& scratch, float fraction, bool sorted, bool inPlace) { if (fraction < 0 || fraction > 1) { throw(ArrayError("::fractile(const Array&) - fraction <0 or >1 ")); } size_t nelem = a.nelements(); if (nelem < 1) { throw(ArrayError("::fractile(const Array&) - Need at least 1 " "elements")); } // A copy is needed if not contiguous or if not in place. const T* storage = a.data(); if (!a.contiguousStorage() || !inPlace) { a.tovector(scratch); storage = scratch.data(); } T* data = const_cast(storage); size_t n2 = size_t((nelem - 1) * double(fraction) + 0.01); if (!sorted) { std::nth_element(data, data+n2, data+nelem); } return data[n2]; } // // ArrayError // template T interFractileRange(const Array &a, std::vector& scratch, float fraction, bool sorted, bool inPlace) { if (!(fraction>0 && fraction<0.5)) throw std::runtime_error("interFractileRange: invalid parameter"); T hex1, hex2; hex1 = fractile(a, scratch, fraction, sorted, inPlace); if (inPlace && a.contiguousStorage()) { hex2 = fractile(a, scratch, 1-fraction, sorted, inPlace); } else { // In this case a copy of a has been made to scratch. // Using it saves making another copy. if (a.size() != scratch.size()) throw std::runtime_error("interFractileRange: array sizes don't match"); Array atmp(a.shape(), scratch.data(), SHARE); hex2 = fractile(atmp, scratch, 1-fraction, sorted, inPlace); } return (hex2 - hex1); } template Array > makeComplex(const Array &left, const Array& right) { checkArrayShapes (left, right, "makeComplex"); Array > res(left.shape()); arrayContTransform (left, right, res, [](T r, T i) { return std::complex(r, i);}); return res; } template Array > makeComplex(const T &left, const Array& right) { Array > res(right.shape()); arrayContTransform (left, right, res, [](T r, T i) { return std::complex(r, i);}); return res; } template Array > makeComplex(const Array &left, const T& right) { Array > res(left.shape()); arrayContTransform (left, right, res, [](T r, T i) { return std::complex(r, i);}); return res; } template void setReal(Array &carray, const Array &rarray) { checkArrayShapes (carray, rarray, "setReal"); // Cannot be done in place, because imag is taken from second operand. arrayTransform (rarray, carray, carray, [](R l, C r)->C { return C(l, std::imag(r)); }); } template void setImag(Array &carray, const Array &rarray) { checkArrayShapes (carray, rarray, "setImag"); arrayTransformInPlace (carray, rarray, [](C l, R r)->C { return C(std::real(l), r); }); } template void convertArray(Array &to, const Array &from) { if (to.nelements() == 0 && from.nelements() == 0) { return; } if (to.shape() != from.shape()) { throw(ArrayConformanceError("void ::convertArray(Array &to, " "const Array &from)" " - arrays do not conform")); } if (to.contiguousStorage() && from.contiguousStorage()) { typename Array::const_contiter endFrom = from.cend(); typename Array::const_contiter iterFrom = from.cbegin(); for (typename Array::contiter iterTo = to.cbegin(); iterFrom != endFrom; ++iterFrom, ++iterTo) { arrays_internal::convertScalar (*iterTo, *iterFrom); } } else { typename Array::const_iterator endFrom = from.end(); typename Array::const_iterator iterFrom = from.begin(); for (typename Array::iterator iterTo = to.begin(); iterFrom != endFrom; ++iterFrom, ++iterTo) { arrays_internal::convertScalar (*iterTo, *iterFrom); } } } } //# NAMESPACE CASACORE - END #endif