#ifndef __MULTI_ARRAY_OP_H#define __MULTI_ARRAY_OP_H#include <boost/array.hpp>#include <boost/multi_array.hpp>#include <functional>#include "functions.h"namespace mimas {/** @defgroup arrayOp Operators for boost::multi_array and mimas::imageMimas has support for doing element-wise operations and convolutions on\c boost::multi_array as well as mimas::image.Implementations for element-wise operations on multi-dimensional arraysare provided. \c boost::multi_array is used to represent themultidimensional arrays.The supported operations are:\li Associative array-scalar operators: multiplication, plus and minus.\li Non-associative array-scalar operators: division, threshold.\li Array-array operators: multiplication, division, plus and minus.The following example demonstrates, how versatile the array-operatorsprovided by mimas are:\include arrayop/main.cc@author Jan Wedekind <jan@wedesoft.de>@author Haifeng Gong <hfgong at users.sourceforge.net>@date Thu Jul 06 14:13:05 UTC 2006@todo Does not compile under Solaris at the moment.@todo Add documentation of all available array operators.@todo Define boost-mpl templates for mimas::rgba to allow the use ofexpression templates (how?)@{ *////template<typename T1, typename T2, size_t NumDims, typename Allocator,template< typename, size_t, typename > class MultiArray>boost::multi_array< T1, NumDims, Allocator > empty_clone( const MultiArray< T2, NumDims, Allocator > &x ){boost::array< size_t, NumDims > shape;std::copy( x.shape(), x.shape() + NumDims, shape.begin() );boost::multi_array< T1, NumDims > retVal( shape );return retVal;}///template<typename T, class F>boost::detail::multi_array::sub_array< T, 1 > multi_apply( boost::detail::multi_array::sub_array< T, 1 > a, F f ) {for ( typename boost::detail::multi_array::sub_array< T, 1 >::iterator i = a.begin();i != a.end(); i++ )f( *i );return a;}///template<typename T, class F,template< typename, size_t > class MultiArray>MultiArray< T, 1 > &multi_apply( MultiArray< T, 1 > &a, F f ) {for ( typename MultiArray< T, 1 >::iterator i = a.begin();i != a.end(); i++ )f( *i );return a;}#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))///template<typename T, class F, typename Allocator,template< typename, size_t, typename > class MultiArray>MultiArray< T, 1, Allocator > &multi_apply( MultiArray< T, 1, Allocator > &a, F f ) {for ( typename MultiArray< T, 1, Allocator >::iterator i = a.begin();i != a.end(); i++ )f( *i );return a;}#endif///template<typename T, size_t NumDims, class F>boost::detail::multi_array::sub_array< T, NumDims > multi_apply( boost::detail::multi_array::sub_array< T, NumDims > a, F f ) {for ( typename boost::detail::multi_array::sub_array< T, NumDims >::iterator i = a.begin();i != a.end(); i++ )multi_apply( *i, f );return a;}///template<typename T, size_t NumDims, class F,template< typename, size_t > class MultiArray>MultiArray< T, NumDims > &multi_apply( MultiArray< T, NumDims > &a, F f ) {for ( typename MultiArray< T, NumDims >::iterator i = a.begin();i != a.end(); i++ )multi_apply( *i, f );return a;}#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))///template<typename T, size_t NumDims, class F, typename Allocator,template< typename, size_t, typename > class MultiArray>MultiArray< T, NumDims, Allocator > &multi_apply( MultiArray< T, NumDims, Allocator > &a, F f ) {for ( typename MultiArray< T, NumDims, Allocator >::iterator i = a.begin();i != a.end(); i++ )multi_apply( *i, f );return a;}#endif///template<typename T1, typename T2, class F, typename Allocator,template< typename, size_t, typename > class MultiArray>boost::detail::multi_array::sub_array< T1, 1 > multi_apply( boost::detail::multi_array::sub_array< T1, 1 > a,const MultiArray< T2, 1, Allocator > &b,F f ) {typename MultiArray< T2, 1, Allocator >::const_iterator j = b.begin();for ( typename boost::detail::multi_array::sub_array< T1, 1 >::iterator i = a.begin();i != a.end(); i++, j++ )f( *i, *j );return a;}///template<typename T1, typename T2, class F,typename Allocator2,template< typename, size_t > class MultiArray1,template< typename, size_t, typename > class MultiArray2>MultiArray1< T1, 1 > &multi_apply( MultiArray1< T1, 1 > &a,const MultiArray2< T2, 1, Allocator2 > &b, F f ) {typename MultiArray2< T2, 1, Allocator2 >::const_iterator j = b.begin();for ( typename MultiArray1< T1, 1 >::iterator i = a.begin();i != a.end(); i++, j++ )f( *i, *j );return a;}#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))///template<typename T1, typename T2, class F,typename Allocator1, typename Allocator2,template< typename, size_t, typename > class MultiArray1,template< typename, size_t, typename > class MultiArray2>MultiArray1< T1, 1, Allocator1 > &multi_apply( MultiArray1< T1, 1, Allocator1 > &a,const MultiArray2< T2, 1, Allocator2 > &b, F f ) {typename MultiArray2< T2, 1, Allocator2 >::const_iterator j = b.begin();for ( typename MultiArray1< T1, 1, Allocator1 >::iterator i = a.begin();i != a.end(); i++, j++ )f( *i, *j );return a;}#endif///template<typename T1, typename T2, size_t NumDims, class F, typename Allocator,template< typename, size_t, typename > class MultiArray>boost::detail::multi_array::sub_array< T1, NumDims > multi_apply( boost::detail::multi_array::sub_array< T1, NumDims > a,const MultiArray< T2, NumDims, Allocator > &b,F f ) {typename MultiArray< T2, NumDims, Allocator >::const_iterator j = b.begin();for ( typename boost::detail::multi_array::sub_array< T1, NumDims >::iterator i = a.begin();i != a.end(); i++, j++ )multi_apply( *i, *j, f );return a;}///template<typename T1, typename T2, size_t NumDims, class F,typename Allocator2,template< typename, size_t > class MultiArray1,template< typename, size_t, typename > class MultiArray2>MultiArray1< T1, NumDims > &multi_apply( MultiArray1< T1, NumDims > &a,const MultiArray2< T2, NumDims, Allocator2 > &b, F f ) {typename MultiArray2< T2, NumDims, Allocator2 >::const_iterator j = b.begin();for ( typename MultiArray1< T1, NumDims >::iterator i = a.begin();i != a.end(); i++, j++ )multi_apply( *i, *j, f );return a;}#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))///template<typename T1, typename T2, size_t NumDims, class F,typename Allocator1, typename Allocator2,template< typename, size_t, typename > class MultiArray1,template< typename, size_t, typename > class MultiArray2>MultiArray1< T1, NumDims, Allocator1 > &multi_apply( MultiArray1< T1, NumDims, Allocator1 > &a,const MultiArray2< T2, NumDims, Allocator2 > &b, F f ) {typename MultiArray2< T2, NumDims, Allocator2 >::const_iterator j = b.begin();for ( typename MultiArray1< T1, NumDims, Allocator1 >::iterator i = a.begin();i != a.end(); i++, j++ )multi_apply( *i, *j, f );return a;}#endif///template<typename T1, typename T2, typename T3, class F,typename Allocator2, typename Allocator3,template< typename, size_t, typename > class MultiArray2,template< typename, size_t, typename > class MultiArray3>boost::detail::multi_array::sub_array< T1, 1 > multi_apply( boost::detail::multi_array::sub_array< T1, 1 > a,const MultiArray2< T2, 1, Allocator2 > &b,const MultiArray3< T3, 1, Allocator3 > &c,F f ) {typename MultiArray2< T2, 1, Allocator2 >::const_iterator j = b.begin();typename MultiArray3< T3, 1, Allocator3 >::const_iterator k = c.begin();for ( typename boost::detail::multi_array::sub_array< T1, 1 >::iterator i = a.begin();i != a.end(); i++, j++, k++ )f( *i, *j, *k );return a;}///template<typename T1, typename T2, typename T3, class F,typename Allocator2, typename Allocator3,template< typename, size_t > class MultiArray1,template< typename, size_t, typename > class MultiArray2,template< typename, size_t, typename > class MultiArray3>MultiArray1< T1, 1 > &multi_apply( MultiArray1< T1, 1 > &a,const MultiArray2< T2, 1, Allocator2 > &b,const MultiArray3< T3, 1, Allocator3 > &c, F f ) {typename MultiArray2< T2, 1, Allocator2 >::const_iterator j = b.begin();typename MultiArray3< T3, 1, Allocator3 >::const_iterator k = c.begin();for ( typename MultiArray1< T1, 1 >::iterator i = a.begin();i != a.end(); i++, j++, k++ )f( *i, *j, *k );return a;}#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))///template<typename T1, typename T2, typename T3, class F,typename Allocator1, typename Allocator2, typename Allocator3,template< typename, size_t, typename > class MultiArray1,template< typename, size_t, typename > class MultiArray2,template< typename, size_t, typename > class MultiArray3>MultiArray1< T1, 1, Allocator1 > &multi_apply( MultiArray1< T1, 1, Allocator1 > &a,const MultiArray2< T2, 1, Allocator2 > &b,const MultiArray3< T3, 1, Allocator3 > &c, F f ) {typename MultiArray2< T2, 1, Allocator2 >::const_iterator j = b.begin();typename MultiArray3< T3, 1, Allocator3 >::const_iterator k = c.begin();for ( typename MultiArray1< T1, 1, Allocator1 >::iterator i = a.begin();i != a.end(); i++, j++, k++ )f( *i, *j, *k );return a;}#endif///template<typename T1, typename T2, typename T3, size_t NumDims, class F,typename Allocator2, typename Allocator3,template< typename, size_t, typename > class MultiArray2,template< typename, size_t, typename > class MultiArray3>boost::detail::multi_array::sub_array< T1, NumDims > multi_apply( boost::detail::multi_array::sub_array< T1, NumDims > a,const MultiArray2< T2, NumDims, Allocator2 > &b,const MultiArray3< T3, NumDims, Allocator3 > &c,F f ) {typename MultiArray2< T2, NumDims, Allocator2 >::const_iterator j = b.begin();typename MultiArray3< T3, NumDims, Allocator3 >::const_iterator k = c.begin();for ( typename boost::detail::multi_array::sub_array< T1, NumDims >::iterator i = a.begin();i != a.end(); i++, j++, k++ ) multi_apply( *i, *j, *k, f );return a;}///template<typename T1, typename T2, typename T3, size_t NumDims, class F,typename Allocator2, typename Allocator3,template< typename, size_t > class MultiArray1,template< typename, size_t, typename > class MultiArray2,template< typename, size_t, typename > class MultiArray3>MultiArray1< T1, NumDims > &multi_apply( MultiArray1< T1, NumDims > &a,const MultiArray2< T2, NumDims, Allocator2 > &b,const MultiArray3< T3, NumDims, Allocator3 > &c, F f ) {typename MultiArray2< T2, NumDims, Allocator2 >::const_iterator j = b.begin();typename MultiArray3< T3, NumDims, Allocator3 >::const_iterator k = c.begin();for ( typename MultiArray1< T1, NumDims >::iterator i = a.begin();i != a.end(); i++, j++, k++ )multi_apply( *i, *j, *k, f );return a;}#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))///template<typename T1, typename T2, typename T3, size_t NumDims, class F,typename Allocator1, typename Allocator2, typename Allocator3,template< typename, size_t, typename > class MultiArray1,template< typename, size_t, typename > class MultiArray2,template< typename, size_t, typename > class MultiArray3>MultiArray1< T1, NumDims, Allocator1 > &multi_apply( MultiArray1< T1, NumDims, Allocator1 > &a,const MultiArray2< T2, NumDims, Allocator2 > &b,const MultiArray3< T3, NumDims, Allocator3 > &c, F f ) {typename MultiArray2< T2, NumDims, Allocator2 >::const_iterator j = b.begin();typename MultiArray3< T3, NumDims, Allocator3 >::const_iterator k = c.begin();for ( typename MultiArray1< T1, NumDims, Allocator1 >::iterator i = a.begin();i != a.end(); i++, j++, k++ )multi_apply( *i, *j, *k, f );return a;}#endif///template< typename T1, typename T2, class F >struct _multi_help1{_multi_help1( F _f ): f(_f) {}T1 &operator()( T1 &x, const T2 &y ) const{ x = f( y ); return x; }F f;};///template< typename T1, typename T2, typename T3, class F >struct _multi_help2{_multi_help2( F _f ): f(_f) {}T1 &operator()( T1 &x, const T2 &y, const T3 &z ) const{ x = f( y, z ); return x; }F f;};///template<typename T1, typename T2, size_t NumDims, class F, typename Allocator,template< typename, size_t, typename > class MultiArray>boost::multi_array< T1, NumDims, Allocator > multi_func( const MultiArray< T2, NumDims, Allocator > &a, F f ) {boost::multi_array< T1, NumDims > retVal( empty_clone< T1 >( a ) );return multi_apply( retVal, a, _multi_help1< T1, T2, F >( f ) );}///template<typename T1, typename T2, typename T3, size_t NumDims, class F,typename Allocator1, typename Allocator2,template< typename, size_t, typename > class MultiArray1,template< typename, size_t, typename > class MultiArray2>boost::multi_array< T1, NumDims > multi_func( const MultiArray1< T2, NumDims, Allocator1 > &a,const MultiArray2< T3, NumDims, Allocator2 > &b, F f ) {boost::multi_array< T1, NumDims > retVal( empty_clone< T1 >( a ) );return multi_apply( retVal, a, b, _multi_help2< T1, T2, T3, F >( f ) );}///template<typename T1, typename T2, size_t NumDims, typename Allocator,template< typename, size_t, typename > class MultiArray>boost::multi_array< T1, NumDims, Allocator > multi_cast( const MultiArray< T2, NumDims, Allocator > &a ) {return multi_func< T1 >( a, std::_Identity< T2 >() );}///@}}#define __MIMASINTERNALARRAYFUNC operator*=#define __MIMASEXTERNALARRAYFUNC operator*#define __MIMASFUNCTIONOBJECT std::multiplies#include "multi_array_op_help.h"#define __MIMASINTERNALARRAYFUNC operator/=#define __MIMASEXTERNALARRAYFUNC operator/#define __MIMASFUNCTIONOBJECT std::divides#include "multi_array_op_help.h"#define __MIMASINTERNALARRAYFUNC operator+=#define __MIMASEXTERNALARRAYFUNC operator+#define __MIMASFUNCTIONOBJECT std::plus#include "multi_array_op_help.h"#define __MIMASINTERNALARRAYFUNC operator-=#define __MIMASEXTERNALARRAYFUNC operator-#define __MIMASFUNCTIONOBJECT std::minus#include "multi_array_op_help.h"#define __MIMASEXTERNALARRAYFUNC absolute#define __MIMASINTERNALARRAYFUNC absoluteIt#define __MIMASFUNCTIONOBJECT _abs#include "multi_array_op_help2.h"#define __MIMASEXTERNALARRAYFUNC conj#define __MIMASINTERNALARRAYFUNC conjIt#define __MIMASFUNCTIONOBJECT _conj#include "multi_array_op_help2.h"#define __MIMASEXTERNALARRAYFUNC sqr#define __MIMASINTERNALARRAYFUNC sqrIt#define __MIMASFUNCTIONOBJECT _sqr#include "multi_array_op_help2.h"#define __MIMASEXTERNALARRAYFUNC logarithm#define __MIMASINTERNALARRAYFUNC logarithmIt#define __MIMASFUNCTIONOBJECT _log#include "multi_array_op_help2.h"#define __MIMASEXTERNALARRAYFUNC squareRoot#define __MIMASINTERNALARRAYFUNC squareRootIt#define __MIMASFUNCTIONOBJECT _sqrt#include "multi_array_op_help2.h"#define __MIMASEXTERNALARRAYFUNC sumSquares#define __MIMASFUNCTIONOBJECT _sumsquares#include "multi_array_op_help3.h"#define __MIMASEXTERNALARRAYFUNC orientation#define __MIMASFUNCTIONOBJECT _orientation#include "multi_array_op_help3.h"namespace mimas {/** @addtogroup arrayOp@{ *////template <typename T1, typename T2, size_t NumDims, typename Allocator,template< typename, size_t, typename > class MultiArray>boost::multi_array< T1, NumDims, Allocator > norm( const MultiArray< T2, NumDims, Allocator > &a ){return multi_func< T1 >( a, _norm< T1, T2 >() );}///template <typename T1, typename T2, size_t NumDims, typename Allocator,template< typename, size_t, typename > class MultiArray>boost::multi_array< T1, NumDims, Allocator > arg( const MultiArray< T2, NumDims, Allocator > &a ){return multi_func< T1 >( a, _arg< T1, T2 >() );}///template <typename T, size_t NumDims, typename Allocator,template< typename, size_t, typename > class MultiArray>boost::multi_array< int, NumDims, Allocator > fastSqr( const MultiArray< T, NumDims, Allocator > &a ){return multi_func< int >( a, _fastsqr< T >() );}///@}}#endif