
// Array transformational functions.

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `remap', `shift', `skew', `multishift' and `writeHalo'.             //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<class T>
inline T broadcast(const Section0<T>& src) {
  Array0<T> dst ;
  Remap schedule(&dst, &src, sizeof(T)) ;

  schedule.execute(dst.dat(), src.dat()) ;

  return dst() ;
}

template<class T>
inline void remap(const Section0<T>& dst, const Section0<T>& src) {
  Remap schedule(&dst, &src, sizeof(T)) ;

  schedule.execute(dst.dat(), src.dat()) ;
}

template<int R, class T>
inline void remap(const Section_<R, T>& dst, const Section_<R, T>& src) {
  Remap schedule(&dst, &src, sizeof(T)) ;

  schedule.execute(dst.dat(), src.dat()) ;
}

template<int R, class T>
inline void shift(const Section_<R, T>& dst, const Section_<R, T>& src,
                  const int shift, const int dim, const Mode mode) {
  Shift schedule(&dst, &src, sizeof(T), shift, dim, mode) ;

  schedule.execute(dst.dat(), src.dat()) ;
}

template<int R, class T>
inline void skew(const Section_<R, T>& dst, const Section_<R, T>& src,
                 const Section_<R - 1, int>& shf,
                 const int dim, const Mode mode) {
  Skew schedule(&dst, &src, sizeof(T), &shf, shf.dat(), dim, mode) ;

  schedule.execute(dst.dat(), src.dat()) ;
}

template<int R, class T>
inline void multiShift(const Section_<R, T>& dst, const Section_<R, T>& src,
                       int* shifts, const Mode* modes) {
  MultiShift schedule(&dst, &src, sizeof(T), shifts, modes) ;

  schedule.execute(dst.dat(), src.dat()) ;
}

template<int R, class T>
inline void writeHalo(const Section_<R, T>& src,
                      const int* wlo, const int* whi, const Mode* modes = 0) {
  WriteHalo schedule(&src, sizeof(T), wlo, whi, modes) ;

  schedule.execute(src.dat()) ;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `gather', `scatter', `vecGather', `vecScatter' and `reshape'.       //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

// Simple gather

template<int R, class T>
inline void gather(const Section_<R, T>& b, const Section1<T>& a,
                   const Section_<R, int>& s_1) {
  Gather schedule(&b, &a, sizeof(T),
                  Seq1<const DAD*>(&s_1), Seq1<const int*>(s_1.dat()),
                  0, 0) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void gather(const Section_<R, T>& b, const Section2<T>& a,
                   const Section_<R, int>& s_1, const Section_<R, int>& s_2) {
  Gather schedule(&b, &a, sizeof(T),
                  Seq2<const DAD*>(&s_1, &s_2),
                  Seq2<const int*>(s_1.dat(), s_2.dat()),
                  0, 0) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void gather(const Section_<R, T>& b, const Section3<T>& a,
                   const Section_<R, int>& s_1, const Section_<R, int>& s_2,
                       const Section_<R, int>& s_3) {
  Gather schedule(&b, &a, sizeof(T),
                  Seq3<const DAD*>(&s_1, &s_2, &s_3),
                  Seq3<const int*>(s_1.dat(), s_2.dat(), s_3.dat()),
                  0, 0) ;

  schedule.execute(b.dat(), a.dat()) ;
}


// Masked gather

template<int R, class T>
inline void gather(const Section_<R, T>& b, const Section1<T>& a,
                   const Section_<R, int>& s_1,
                   const Section_<R, int>& msk) {
  Gather schedule(&b, &a, sizeof(T),
                  Seq1<const DAD*>(&s_1), Seq1<const int*>(s_1.dat()),
                  &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void gather(const Section_<R, T>& b, const Section2<T>& a,
                   const Section_<R, int>& s_1, const Section_<R, int>& s_2,
                   const Section_<R, int>& msk) {
  Gather schedule(&b, &a, sizeof(T),
                  Seq2<const DAD*>(&s_1, &s_2),
                  Seq2<const int*>(s_1.dat(), s_2.dat()),
                  &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void gather(const Section_<R, T>& b, const Section3<T>& a,
                   const Section_<R, int>& s_1, const Section_<R, int>& s_2,
                       const Section_<R, int>& s_3,
                   const Section_<R, int>& msk) {
  Gather schedule(&b, &a, sizeof(T),
                  Seq3<const DAD*>(&s_1, &s_2, &s_3),
                  Seq3<const int*>(s_1.dat(), s_2.dat(), s_3.dat()),
                  &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}


// Simple scatter

template<int R, class T>
inline void scatter(const Section_<R, T>& b, const Section1<T>& a,
                    const Section_<R, int>& s_1) {
  Scatter schedule(&b, &a, sizeof(T),
                   Seq1<const DAD*>(&s_1), Seq1<const int*>(s_1.dat()),
                   0, 0) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void scatter(const Section_<R, T>& b, const Section2<T>& a,
                    const Section_<R, int>& s_1, const Section_<R, int>& s_2) {
  Scatter schedule(&b, &a, sizeof(T),
                   Seq2<const DAD*>(&s_1, &s_2),
                   Seq2<const int*>(s_1.dat(), s_2.dat()),
                   0, 0) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void scatter(const Section_<R, T>& b, const Section3<T>& a,
                    const Section_<R, int>& s_1, const Section_<R, int>& s_2,
                    const Section_<R, int>& s_3) {
  Scatter schedule(&b, &a, sizeof(T),
                   Seq3<const DAD*>(&s_1, &s_2, &s_3),
                   Seq3<const int*>(s_1.dat(), s_2.dat(), s_3.dat()),
                   0, 0) ;

  schedule.execute(b.dat(), a.dat()) ;
}


// Masked scatter

template<int R, class T>
inline void scatter(const Section_<R, T>& b, const Section1<T>& a,
                    const Section_<R, int>& s_1,
                    const Section_<R, int>& msk) {
  Scatter schedule(&b, &a, sizeof(T),
                   Seq1<const DAD*>(&s_1), Seq1<const int*>(s_1.dat()),
                   &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void scatter(const Section_<R, T>& b, const Section2<T>& a,
                    const Section_<R, int>& s_1, const Section_<R, int>& s_2,
                    const Section_<R, int>& msk) {
  Scatter schedule(&b, &a, sizeof(T),
                   Seq2<const DAD*>(&s_1, &s_2),
                   Seq2<const int*>(s_1.dat(), s_2.dat()),
                   &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void scatter(const Section_<R, T>& b, const Section3<T>& a,
                    const Section_<R, int>& s_1, const Section_<R, int>& s_2,
                    const Section_<R, int>& s_3,
                    const Section_<R, int>& msk) {
  Scatter schedule(&b, &a, sizeof(T),
                   Seq3<const DAD*>(&s_1, &s_2, &s_3),
                   Seq3<const int*>(s_1.dat(), s_2.dat(), s_3.dat()),
                   &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}


// Combining scatter

template<int R, class T>
inline void scatterComb(const Section_<R, T>& b, const Section1<T>& a,
                        const Section_<R, int>& s_1,
                        void (*op)(void*, void*)) {
  ScatterComb schedule(&b, &a, sizeof(T),
                       Seq1<const DAD*>(&s_1), Seq1<const int*>(s_1.dat()),
                       0, 0,
                       op) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void scatterComb(const Section_<R, T>& b, const Section2<T>& a,
                        const Section_<R, int>& s_1,
                        const Section_<R, int>& s_2,
                        void (*op)(void*, void*)) {
  ScatterComb schedule(&b, &a, sizeof(T),
                       Seq2<const DAD*>(&s_1, &s_2),
                       Seq2<const int*>(s_1.dat(), s_2.dat()),
                       0, 0,
                       op) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void scatterComb(const Section_<R, T>& b, const Section3<T>& a,
                        const Section_<R, int>& s_1,
                        const Section_<R, int>& s_2,
                        const Section_<R, int>& s_3,
                        void (*op)(void*, void*)) {
  ScatterComb schedule(&b, &a, sizeof(T),
                       Seq3<const DAD*>(&s_1, &s_2, &s_3),
                       Seq3<const int*>(s_1.dat(), s_2.dat(), s_3.dat()),
                       0, 0,
                       op) ;

  schedule.execute(b.dat(), a.dat()) ;
}


// Masked combining scatter

template<int R, class T>
inline void scatterComb(const Section_<R, T>& b, const Section1<T>& a,
                        const Section_<R, int>& s_1,
                        void (*op)(void*, void*),
                        const Section_<R, int>& msk) {
  ScatterComb schedule(&b, &a, sizeof(T),
                       Seq1<const DAD*>(&s_1), Seq1<const int*>(s_1.dat()),
                       &msk, msk.dat(),
                       op) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void scatterComb(const Section_<R, T>& b, const Section2<T>& a,
                        const Section_<R, int>& s_1,
                        const Section_<R, int>& s_2,
                        void (*op)(void*, void*),
                        const Section_<R, int>& msk) {
  ScatterComb schedule(&b, &a, sizeof(T),
                       Seq2<const DAD*>(&s_1, &s_2),
                       Seq2<const int*>(s_1.dat(), s_2.dat()),
                       &msk, msk.dat(),
                       op) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<int R, class T>
inline void scatterComb(const Section_<R, T>& b, const Section3<T>& a,
                        const Section_<R, int>& s_1,
                        const Section_<R, int>& s_2,
                        const Section_<R, int>& s_3,
                        void (*op)(void*, void*),
                        const Section_<R, int>& msk) {
  ScatterComb schedule(&b, &a, sizeof(T),
                       Seq3<const DAD*>(s_1, s_2, s_3),
                       Seq3<const int*>(s_1.dat(), s_2.dat(), s_3.dat()),
                       &msk, msk.dat(),
                       op) ;

  schedule.execute(b.dat(), a.dat()) ;
}


// Vector subscript gather.

template<class T>
inline void vecGather(const Section1<T>& b, const Section1<T>& a,
                      const Section1<int>* s_1) {
  VecGather schedule(&b, &a, sizeof(T),
                     Seq1<const DAD*>(s_1),
                     Seq1<const int*>(s_1 ? s_1->dat() : 0)) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<class T>
inline void vecGather(const Section2<T>& b, const Section2<T>& a,
                      const Section1<int>* s_1, const Section1<int>* s_2) {
  VecGather schedule(&b, &a, sizeof(T),
                     Seq2<const DAD*>(s_1, s_2),
                     Seq2<const int*>(s_1 ? s_1->dat() : 0,
                                      s_2 ? s_2->dat() : 0)) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<class T>
inline void vecGather(const Section3<T>& b, const Section3<T>& a,
                      const Section1<int>* s_1, const Section1<int>* s_2,
                          const Section1<int>* s_3) {
  VecGather schedule(&b, &a, sizeof(T),
                     Seq3<const DAD*>(s_1, s_2, s_3),
                     Seq3<const int*>(s_1 ? s_1->dat() : 0,
                                      s_2 ? s_2->dat() : 0,
                                      s_3 ? s_3->dat() : 0)) ;

  schedule.execute(b.dat(), a.dat()) ;
}

// Masked vector subscript scatter

template<class T>
inline void vecGather(const Section1<T>& b, const Section1<T>& a,
                      const Section1<int>* s_1,
                      const Section1<int>& msk) {
  VecGatherMsk schedule(&b, &a, sizeof(T),
                        Seq1<const DAD*>(s_1),
                        Seq1<const int*>(s_1 ? s_1->dat() : 0),
                        &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<class T>
inline void vecGather(const Section2<T>& b, const Section2<T>& a,
                      const Section1<int>* s_1, const Section1<int>* s_2,
                      const Section2<int>& msk) {
  VecGatherMsk schedule(&b, &a, sizeof(T),
                        Seq2<const DAD*>(s_1, s_2),
                        Seq2<const int*>(s_1 ? s_1->dat() : 0,
                                         s_2 ? s_2->dat() : 0),
                        &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<class T>
inline void vecGather(const Section3<T>& b, const Section3<T>& a,
                      const Section1<int>* s_1, const Section1<int>* s_2,
                      const Section1<int>* s_3,
                      const Section3<int>& msk) {
  VecGatherMsk schedule(&b, &a, sizeof(T),
                        Seq3<const DAD*>(s_1, s_2, s_3),
                        Seq3<const int*>(s_1 ? s_1->dat() : 0,
                                         s_2 ? s_2->dat() : 0,
                                         s_3 ? s_3->dat() : 0),
                        &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

// Vector subscript scatter.

template<class T>
inline void vecScatter(const Section1<T>& b, const Section1<T>& a,
                       const Section1<int>* s_1) {
  VecScatter schedule(&b, &a, sizeof(T),
                      Seq1<const DAD*>(s_1),
                      Seq1<const int*>(s_1 ? s_1->dat() : 0)) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<class T>
inline void vecScatter(const Section2<T>& b, const Section2<T>& a,
                       const Section1<int>* s_1, const Section1<int>* s_2) {
  VecScatter schedule(&b, &a, sizeof(T),
                      Seq2<const DAD*>(s_1, s_2),
                      Seq2<const int*>(s_1 ? s_1->dat() : 0,
                                       s_2 ? s_2->dat() : 0)) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<class T>
inline void vecScatter(const Section3<T>& b, const Section3<T>& a,
                       const Section1<int>* s_1, const Section1<int>* s_2,
                           const Section1<int>* s_3) {
  VecScatter schedule(&b, &a, sizeof(T),
                      Seq3<const DAD*>(s_1, s_2, s_3),
                      Seq3<const int*>(s_1 ? s_1->dat() : 0,
                                       s_2 ? s_2->dat() : 0,
                                       s_3 ? s_3->dat() : 0)) ;

  schedule.execute(b.dat(), a.dat()) ;
}

// Masked vector subscript scatter

template<class T>
inline void vecScatter(const Section1<T>& b, const Section1<T>& a,
                       const Section1<int>* s_1,
                       const Section1<int>& msk) {
  VecScatterMsk schedule(&b, &a, sizeof(T),
                         Seq1<const DAD*>(s_1),
                         Seq1<const int*>(s_1 ? s_1->dat() : 0),
                         &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<class T>
inline void vecScatter(const Section2<T>& b, const Section2<T>& a,
                       const Section1<int>* s_1, const Section1<int>* s_2,
                       const Section2<int>& msk) {
  VecScatterMsk schedule(&b, &a, sizeof(T),
                         Seq2<const DAD*>(s_1, s_2),
                         Seq2<const int*>(s_1 ? s_1->dat() : 0,
                                          s_2 ? s_2->dat() : 0),
                         &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

template<class T>
inline void vecScatter(const Section3<T>& b, const Section3<T>& a,
                       const Section1<int>* s_1, const Section1<int>* s_2,
                       const Section1<int>* s_3,
                       const Section3<int>& msk) {
  VecScatterMsk schedule(&b, &a, sizeof(T),
                         Seq3<const DAD*>(s_1, s_2, s_3),
                         Seq3<const int*>(s_1 ? s_1->dat() : 0,
                                          s_2 ? s_2->dat() : 0,
                                          s_3 ? s_3->dat() : 0),
                         &msk, msk.dat()) ;

  schedule.execute(b.dat(), a.dat()) ;
}

// Reshape

template<int R, int S, class T>
inline void reshape(const Section_<R, T>& dst, const Section_<S, T>& src) {
  Reshape schedule(&dst, &src, sizeof(T)) ;

  schedule.execute(dst.dat(), src.dat()) ;
}

template<int R, int S, class T>
inline void reshape(const Section_<R, T>& dst, const Section_<S, T>& src,
                    const Section1<T>& pad) {
  int srcSize = 1 ;
  for(int d = 0 ; d < src.rnk() ; d++)
    srcSize *= src.rng(d).size() ;

  Reshape schedule(&dst, &src, sizeof(T)) ;
  ReshapePad padSchedule(&dst, srcSize, &pad, sizeof(T)) ;

  schedule.execute(dst.dat(), src.dat()) ;
  padSchedule.execute(dst.dat(), pad.dat()) ;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `maxval', `minval', `sum', ...                                      //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<int R, class T>
inline T maxval(const Section_<R, T>& src) {
  T res ;
  Maxval<T> schedule(&src) ;
  schedule.execute(&res, src.dat()) ;
  return res ;
}

template<int R, class T>
inline T maxval(const Section_<R, T>& src, const Section_<R, int>& msk) {
  T res ;
  MaxvalMsk<T> schedule(&src, &msk) ;
  schedule.execute(&res, src.dat(), msk.dat()) ;
  return res ;
}


template<int R, class T>
inline T minval(const Section_<R, T>& src) {
  T res ;
  Minval<T> schedule(&src) ;
  schedule.execute(&res, src.dat()) ;
  return res ;
}

template<int R, class T>
inline T minval(const Section_<R, T>& src, const Section_<R, int>& msk) {
  T res ;
  MinvalMsk<T> schedule(&src, &msk) ;
  schedule.execute(&res, src.dat(), msk.dat()) ;
  return res ;
}


template<int R, class T>
inline T sum(const Section_<R, T>& src) {
  T res ;
  Sum<T> schedule(&src) ;
  schedule.execute(&res, src.dat()) ;
  return res ;
}

template<int R, class T>
inline T sum(const Section_<R, T>& src, const Section_<R, int>& msk) {
  T res ;
  SumMsk<T> schedule(&src, &msk) ;
  schedule.execute(&res, src.dat(), msk.dat()) ;
  return res ;
}

template<int R, class T>
inline T product(const Section_<R, T>& src) {
  T res ;
  Product<T> schedule(&src) ;
  schedule.execute(&res, src.dat()) ;
  return res ;
}

template<int R, class T>
inline T product(const Section_<R, T>& src, const Section_<R, int>& msk) {
  T res ;
  ProductMsk<T> schedule(&src, &msk) ;
  schedule.execute(&res, src.dat(), msk.dat()) ;
  return res ;
}

template<int R>
inline int all(const Section_<R, int>& src) {
  int res ;
  All schedule(&src) ;
  schedule.execute(&res, src.dat()) ;
  return res ;
}

template<int R>
inline int any(const Section_<R, int>& src) {
  int res ;
  Any schedule(&src) ;
  schedule.execute(&res, src.dat()) ;
  return res ;
}

template<int R>
inline int count(const Section_<R, int>& src) {
  int res ;
  Count schedule(&src) ;
  schedule.execute(&res, src.dat()) ;
  return res ;
}


// Dot product variants

inline int dotProduct(const Section1<int>& a, const Section1<int>& b) {
  int res ;
  DotProduct<int, int, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section1<int>& a, const Section1<float>& b) {
  float res ;
  DotProduct<float, int, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section1<int>& a, const Section1<double>& b) {
  double res ;
  DotProduct<double, int, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section1<int>& a, const Section1<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, int, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section1<float>& a, const Section1<int>& b) {
  float res ;
  DotProduct<float, float, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section1<float>& a, const Section1<float>& b) {
  float res ;
  DotProduct<float, float, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section1<float>& a, const Section1<double>& b) {
  double res ;
  DotProduct<double, float, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section1<float>& a, const Section1<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, float, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section1<double>& a, const Section1<int>& b) {
  double res ;
  DotProduct<double, double, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section1<double>& a, const Section1<float>& b) {
  double res ;
  DotProduct<double, double, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section1<double>& a, const Section1<double>& b) {
  double res ;
  DotProduct<double, double, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section1<double>& a,
                          const Section1<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, double, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section1<COMPLEX>& a, const Section1<int>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section1<COMPLEX>& a,
                          const Section1<float>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section1<COMPLEX>& a,
                          const Section1<double>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section1<COMPLEX>& a,
                          const Section1<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline int boolDotProduct(const Section1<int>& a, const Section1<int>& b) {
  int res ;
  BoolDotProduct schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline int dotProduct(const Section2<int>& a, const Section2<int>& b) {
  int res ;
  DotProduct<int, int, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section2<int>& a, const Section2<float>& b) {
  float res ;
  DotProduct<float, int, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section2<int>& a, const Section2<double>& b) {
  double res ;
  DotProduct<double, int, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section2<int>& a, const Section2<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, int, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section2<float>& a, const Section2<int>& b) {
  float res ;
  DotProduct<float, float, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section2<float>& a, const Section2<float>& b) {
  float res ;
  DotProduct<float, float, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section2<float>& a, const Section2<double>& b) {
  double res ;
  DotProduct<double, float, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section2<float>& a, const Section2<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, float, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section2<double>& a, const Section2<int>& b) {
  double res ;
  DotProduct<double, double, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section2<double>& a, const Section2<float>& b) {
  double res ;
  DotProduct<double, double, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section2<double>& a, const Section2<double>& b) {
  double res ;
  DotProduct<double, double, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section2<double>& a,
                          const Section2<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, double, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section2<COMPLEX>& a, const Section2<int>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section2<COMPLEX>& a,
                          const Section2<float>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section2<COMPLEX>& a,
                          const Section2<double>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section2<COMPLEX>& a,
                          const Section2<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline int boolDotProduct(const Section2<int>& a, const Section2<int>& b) {
  int res ;
  BoolDotProduct schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline int dotProduct(const Section3<int>& a, const Section3<int>& b) {
  int res ;
  DotProduct<int, int, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section3<int>& a, const Section3<float>& b) {
  float res ;
  DotProduct<float, int, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section3<int>& a, const Section3<double>& b) {
  double res ;
  DotProduct<double, int, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section3<int>& a, const Section3<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, int, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section3<float>& a, const Section3<int>& b) {
  float res ;
  DotProduct<float, float, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline float dotProduct(const Section3<float>& a, const Section3<float>& b) {
  float res ;
  DotProduct<float, float, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section3<float>& a, const Section3<double>& b) {
  double res ;
  DotProduct<double, float, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section3<float>& a, const Section3<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, float, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section3<double>& a, const Section3<int>& b) {
  double res ;
  DotProduct<double, double, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section3<double>& a, const Section3<float>& b) {
  double res ;
  DotProduct<double, double, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline double dotProduct(const Section3<double>& a, const Section3<double>& b) {
  double res ;
  DotProduct<double, double, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section3<double>& a,
                          const Section3<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, double, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section3<COMPLEX>& a, const Section3<int>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, int> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section3<COMPLEX>& a,
                          const Section3<float>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, float> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section3<COMPLEX>& a,
                          const Section3<double>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, double> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline COMPLEX dotProduct(const Section3<COMPLEX>& a,
                          const Section3<COMPLEX>& b) {
  COMPLEX res ;
  DotProduct<COMPLEX, COMPLEX, COMPLEX> schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}

inline int boolDotProduct(const Section3<int>& a, const Section3<int>& b) {
  int res ;
  BoolDotProduct schedule(&a, &b) ;
  schedule.execute(&res, a.dat(), b.dat()) ;
  return res ;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `maxval', `minval', `sum', dimensional reductions                   //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<int R, class T>
inline void sum(const Section_<R, T>& res,
                const Section_<R + 1, T>& src, const int dim) {
  SumDim<T> schedule(&res, &src, dim) ;
  schedule.execute(res.dat(), src.dat()) ;
}

template<int R, class T>
inline void sum(const Section_<R, T>& res,
                const Section_<R + 1, T>& src, const int dim,
                const Section_<R + 1, int>& msk) {
  SumDimMsk<T> schedule(&res, &src, dim, &msk) ;
  schedule.execute(res.dat(), src.dat(), msk.dat()) ;
}

template<int R, class T>
inline void product(const Section_<R, T>& res,
                    const Section_<R + 1, T>& src, const int dim) {
  ProductDim<T> schedule(&res, &src, dim) ;
  schedule.execute(res.dat(), src.dat()) ;
}

template<int R, class T>
inline void product(const Section_<R, T>& res,
                    const Section_<R + 1, T>& src, const int dim,
                    const Section_<R + 1, int>& msk) {
  ProductDimMsk<T> schedule(&res, &src, dim, &msk) ;
  schedule.execute(res.dat(), src.dat(), msk.dat()) ;
}

template<int R, class T>
inline void maxval(const Section_<R, T>& res,
                   const Section_<R + 1, T>& src, const int dim) {
  MaxvalDim<T> schedule(&res, &src, dim) ;
  schedule.execute(res.dat(), src.dat()) ;
}

template<int R, class T>
inline void maxval(const Section_<R, T>& res,
                   const Section_<R + 1, T>& src, const int dim,
                   const Section_<R + 1, int>& msk) {
  MaxvalDimMsk<T> schedule(&res, &src, dim, &msk) ;
  schedule.execute(res.dat(), src.dat(), msk.dat()) ;
}

template<int R, class T>
inline void minval(const Section_<R, T>& res,
                   const Section_<R + 1, T>& src, const int dim) {
  MinvalDim<T> schedule(&res, &src, dim) ;
  schedule.execute(res.dat(), src.dat()) ;
}

template<int R, class T>
inline void minval(const Section_<R, T>& res,
                   const Section_<R + 1, T>& src, const int dim,
                   const Section_<R + 1, int>& msk) {
  MinvalDimMsk<T> schedule(&res, &src, dim, &msk) ;
  schedule.execute(res.dat(), src.dat(), msk.dat()) ;
}


template<int R>
inline void all(const Section_<R, int>& res,
                const Section_<R + 1, int>& src, const int dim) {
  AllDim schedule(&res, &src, dim) ;
  schedule.execute(res.dat(), src.dat()) ;
}

template<int R>
inline void any(const Section_<R, int>& res,
                const Section_<R + 1, int>& src, const int dim) {
  AnyDim schedule(&res, &src, dim) ;
  schedule.execute(res.dat(), src.dat()) ;
}

template<int R>
inline void count(const Section_<R, int>& res,
                  const Section_<R + 1, int>& src, const int dim) {
  CountDim schedule(&res, &src, dim) ;
  schedule.execute(res.dat(), src.dat()) ;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `maxloc', `minloc'                                                  //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<int R, class T>
inline void maxloc(T* val, int* loc, const Section_<R, T>& src) {
  Maxloc<T> schedule(&src) ;
  schedule.execute(val, loc, src.dat()) ;
}

template<int R, class T>
inline void maxloc(T* val, int* loc,
                   const Section_<R, T>& src, const Section_<R, int>& msk) {
  MaxlocMsk<T> schedule(&src, &msk) ;
  schedule.execute(val, loc, src.dat(), msk.dat()) ;
}

template<int R, class T>
inline void minloc(T* val, int* loc, const Section_<R, T>& src) {
  Minloc<T> schedule(&src) ;
  schedule.execute(val, loc, src.dat()) ;
}

template<int R, class T>
inline void minloc(T* val, int* loc,
                   const Section_<R, T>& src, const Section_<R, int>& msk) {
  MinlocMsk<T> schedule(&src, &msk) ;
  schedule.execute(val, loc, src.dat(), msk.dat()) ;
}

template<int R, class T>
inline void maxloc(const Section_<R, T>& val, const Section_<R, int>& loc,
                   const Section_<R + 1, T>& src, const int dim) {
  MaxlocDim<T> schedule(&val, &loc, &src, dim) ;
  schedule.execute(val.dat(), loc.dat(), src.dat()) ;
}

template<int R, class T>
inline void maxloc(const Section_<R, T>& val, const Section_<R, int>& loc,
                   const Section_<R + 1, T>& src, const int dim,
                   const Section_<R + 1, int>& msk) {
  MaxlocDimMsk<T> schedule(&val, &loc, &src, dim, &msk) ;
  schedule.execute(val.dat(), loc.dat(), src.dat(), msk.dat()) ;
}

template<int R, class T>
inline void minloc(const Section_<R, T>& val, const Section_<R, int>& loc,
                   const Section_<R + 1, T>& src, const int dim) {
  MinlocDim<T> schedule(&val, &loc, &src, dim) ;
  schedule.execute(val.dat(), loc.dat(), src.dat()) ;
}

template<int R, class T>
inline void minloc(const Section_<R, T>& val, const Section_<R, int>& loc,
                   const Section_<R + 1, T>& src, const int dim,
                   const Section_<R + 1, int>& msk) {
  MinlocDimMsk<T> schedule(&val, &loc, &src, dim, &msk) ;
  schedule.execute(val.dat(), loc.dat(), src.dat(), msk.dat()) ;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `copy'                                                              //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<int R, class T>
inline void copy(const Section_<R, T>& dst, const Section_<R, T>& src) {
  Copy<T> schedule(&dst, &src) ;

  schedule.execute(dst.dat(), src.dat()) ;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `init'                                                              //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<int R, class T>
inline void init(const Section_<R, T>& dst, const T src) {
  Init<T> schedule(&dst) ;

  schedule.execute(dst.dat(), src) ;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `spread'                                                            //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<int R, class T>
inline void spread(const Section_<R, T>& dst, const Section_<R - 1, T>& src,
                   const int dim) {
  Spread<T> schedule(&dst, &src, dim) ;

  schedule.execute(dst.dat(), src.dat()) ;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// `matmul'                                                            //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<class S, class T, class U>
inline void matmul(const Section2<S>& res,
                   const Section2<T>& src1, const Section2<U>& src2) {
  
  matmul((DAD*) &res, res.dat(),
         (DAD*) &src1, src1.dat(), (DAD*) &src2, src2.dat()) ;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
//                                                                     //
// Transpose.                                                          //
//                                                                     //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

template<class T>
void inline transpose(const Section2<T>& dst, const Section2<T>& src) {
  Section2<T> exc(src.rng(1), src.rng(0), src.grp(),
                  src.str(1), src.str(0), src.dat()) ;

  remap(dst, exc) ;
}


// -------------------------------------------------------------
// Things to do
//
//   Eliminate various uses of `Seq' in favour of explicit declaration
//   of local vectors?


