/* *****************************************************
   THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT.
   *****************************************************

   Generated by:
     scitbx.source_generators.array_family.generate_algebras
 */

#ifndef SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_H
#define SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_H

#ifndef DOXYGEN_SHOULD_SKIP_THIS

#include <scitbx/array_family/small.h>

#if (defined(BOOST_MSVC) && BOOST_MSVC <= 1300) // VC++ 7.0
#define SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2 N1
#else
#define SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2 (N1<N2?N1:N2)
#endif


#include <scitbx/array_family/operator_traits_builtin.h>
#include <scitbx/array_family/detail/operator_functors.h>
#include <scitbx/array_family/detail/generic_array_functors.h>
#include <scitbx/array_family/detail/std_imports.h>
#include <scitbx/array_family/misc_functions.h>

namespace scitbx { namespace af {

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator-(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_negate<
          return_element_type,
          ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator!(small<ElementType, N> const& a) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_logical_not<
          return_element_type,
          ElementType>(), a.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator+(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_plus<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator+(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_plus<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator+(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_plus<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, N1>&
  operator+=(
    small<ElementType1, N1>& a1,
    small<ElementType2, N2> const& a2) {
    if (a1.size() != a2.size()) throw_range_error();
    array_operation_in_place_a_a(fn::functor_ip_plus<
        ElementType1,
        ElementType2>(),
      a1.begin(), a2.begin(), a1.size());
    return a1;
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>&
  operator+=(
    small<ElementType, N>& a1,
    ElementType const& a2) {
    array_operation_in_place_a_s(fn::functor_ip_plus<
        ElementType,
        ElementType>(),
      a1.begin(), a2, a1.size());
    return a1;
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator-(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_minus<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator-(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_minus<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator-(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_minus<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, N1>&
  operator-=(
    small<ElementType1, N1>& a1,
    small<ElementType2, N2> const& a2) {
    if (a1.size() != a2.size()) throw_range_error();
    array_operation_in_place_a_a(fn::functor_ip_minus<
        ElementType1,
        ElementType2>(),
      a1.begin(), a2.begin(), a1.size());
    return a1;
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>&
  operator-=(
    small<ElementType, N>& a1,
    ElementType const& a2) {
    array_operation_in_place_a_s(fn::functor_ip_minus<
        ElementType,
        ElementType>(),
      a1.begin(), a2, a1.size());
    return a1;
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator*(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_multiplies<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator*(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_multiplies<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator*(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_multiplies<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, N1>&
  operator*=(
    small<ElementType1, N1>& a1,
    small<ElementType2, N2> const& a2) {
    if (a1.size() != a2.size()) throw_range_error();
    array_operation_in_place_a_a(fn::functor_ip_multiplies<
        ElementType1,
        ElementType2>(),
      a1.begin(), a2.begin(), a1.size());
    return a1;
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>&
  operator*=(
    small<ElementType, N>& a1,
    ElementType const& a2) {
    array_operation_in_place_a_s(fn::functor_ip_multiplies<
        ElementType,
        ElementType>(),
      a1.begin(), a2, a1.size());
    return a1;
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator/(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_divides<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator/(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_divides<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator/(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_divides<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, N1>&
  operator/=(
    small<ElementType1, N1>& a1,
    small<ElementType2, N2> const& a2) {
    if (a1.size() != a2.size()) throw_range_error();
    array_operation_in_place_a_a(fn::functor_ip_divides<
        ElementType1,
        ElementType2>(),
      a1.begin(), a2.begin(), a1.size());
    return a1;
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>&
  operator/=(
    small<ElementType, N>& a1,
    ElementType const& a2) {
    array_operation_in_place_a_s(fn::functor_ip_divides<
        ElementType,
        ElementType>(),
      a1.begin(), a2, a1.size());
    return a1;
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator%(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_modulus<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator%(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_modulus<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  operator%(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_modulus<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, N1>&
  operator%=(
    small<ElementType1, N1>& a1,
    small<ElementType2, N2> const& a2) {
    if (a1.size() != a2.size()) throw_range_error();
    array_operation_in_place_a_a(fn::functor_ip_modulus<
        ElementType1,
        ElementType2>(),
      a1.begin(), a2.begin(), a1.size());
    return a1;
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>&
  operator%=(
    small<ElementType, N>& a1,
    ElementType const& a2) {
    array_operation_in_place_a_s(fn::functor_ip_modulus<
        ElementType,
        ElementType>(),
      a1.begin(), a2, a1.size());
    return a1;
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator&&(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_logical_and<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator&&(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_logical_and<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator&&(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_logical_and<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator||(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_logical_or<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator||(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_logical_or<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator||(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_logical_or<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator==(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_equal_to<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator==(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_equal_to<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator==(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_equal_to<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator!=(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_not_equal_to<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator!=(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_not_equal_to<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator!=(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_not_equal_to<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator>(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_greater<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator>(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_greater<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator>(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_greater<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator<(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_less<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator<(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_less<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator<(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_less<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator>=(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_greater_equal<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator>=(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_greater_equal<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator>=(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_greater_equal<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  operator<=(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_less_equal<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator<=(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_less_equal<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  operator<=(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_less_equal<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  absolute(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_absolute<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  pow2(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_pow2<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  acos(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_acos<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  cos(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_cos<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  tan(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_tan<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  asin(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_asin<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  cosh(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_cosh<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  tanh(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_tanh<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  atan(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_atan<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  exp(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_exp<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  sin(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_sin<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  fabs(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_fabs<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  log(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_log<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  sinh(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_sinh<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  ceil(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_ceil<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  floor(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_floor<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  log10(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_log10<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  sqrt(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_sqrt<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  abs(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_abs<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  conj(small<ElementType, N> const& a) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_conj<return_element_type, ElementType>(), a.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  fmod_positive(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_fmod_positive<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  fmod_positive(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_fmod_positive<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  fmod_positive(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_fmod_positive<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  fmod(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_fmod<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  fmod(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_fmod<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  fmod(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_fmod<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  pow(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_pow<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  pow(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  pow(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_pow<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  atan2(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_atan2<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  atan2(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_atan2<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  atan2(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_atan2<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  each_min(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_each_min<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  each_min(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_each_min<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  each_min(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_each_min<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, std::size_t N1,
    typename ElementType2, std::size_t N2>
  inline
  small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  each_max(
    small<ElementType1, N1> const& a1,
    small<ElementType2, N2> const& a2) {
    typedef small<ElementType1, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_each_max<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  each_max(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_each_max<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  each_max(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<ElementType, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_each_max<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  real(small<std::complex<ElementType>, N> const& a) {
    typedef small<ElementType, N> return_array_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_real<
          ElementType,
          std::complex<ElementType> >(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  imag(small<std::complex<ElementType>, N> const& a) {
    typedef small<ElementType, N> return_array_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_imag<
          ElementType,
          std::complex<ElementType> >(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  abs(small<std::complex<ElementType>, N> const& a) {
    typedef small<ElementType, N> return_array_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_abs<
          ElementType,
          std::complex<ElementType> >(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  arg(small<std::complex<ElementType>, N> const& a) {
    typedef small<ElementType, N> return_array_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_arg<
          ElementType,
          std::complex<ElementType> >(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<ElementType, N>
  norm(small<std::complex<ElementType>, N> const& a) {
    typedef small<ElementType, N> return_array_type;
    return return_array_type(a.size(),
      make_init_functor(make_array_functor_a(
        fn::functor_norm<
          ElementType,
          std::complex<ElementType> >(), a.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    small<std::complex<ElementType>, N> const& a1,
    small<int, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          int >(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    small<std::complex<ElementType>, N> const& a1,
    int const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          int >(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    std::complex<ElementType> const& a1,
    small<int, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          int >(), a1, a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    small<std::complex<ElementType>, N> const& a1,
    small<ElementType, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          ElementType >(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    small<std::complex<ElementType>, N> const& a1,
    ElementType const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          ElementType >(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    std::complex<ElementType> const& a1,
    small<ElementType, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          ElementType >(), a1, a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    small<std::complex<ElementType>, N> const& a1,
    small<std::complex<ElementType>, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          std::complex<ElementType> >(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    small<std::complex<ElementType>, N> const& a1,
    std::complex<ElementType> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          std::complex<ElementType> >(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    std::complex<ElementType> const& a1,
    small<std::complex<ElementType>, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          std::complex<ElementType> >(), a1, a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    small<ElementType, N> const& a1,
    small<std::complex<ElementType>, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_pow<
          std::complex<ElementType>,
          ElementType,
          std::complex<ElementType> >(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    small<ElementType, N> const& a1,
    std::complex<ElementType> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<
          std::complex<ElementType>,
          ElementType,
          std::complex<ElementType> >(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  pow(
    ElementType const& a1,
    small<std::complex<ElementType>, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_pow<
          std::complex<ElementType>,
          ElementType,
          std::complex<ElementType> >(), a1, a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  polar(
    small<ElementType, N> const& a1,
    small<ElementType, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_polar<
          std::complex<ElementType>,
          ElementType,
          ElementType >(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  polar(
    small<ElementType, N> const& a1,
    ElementType const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_polar<
          std::complex<ElementType>,
          ElementType,
          ElementType >(), a1.begin(), a2)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<std::complex<ElementType>, N>
  polar(
    ElementType const& a1,
    small<ElementType, N> const& a2) {
    typedef small<std::complex<ElementType>, N> return_array_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_polar<
          std::complex<ElementType>,
          ElementType,
          ElementType >(), a1, a2.begin())));
  }

  template<typename ElementType, std::size_t N1, std::size_t N2>
  inline
  small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
  approx_equal(
    small<ElementType, N1> const& a1,
    small<ElementType, N2> const& a2,
    ElementType const& tolerance) {
    typedef small<bool, SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_MIN_N1_N2>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_a_s(
        fn::functor_approx_equal<return_element_type,
          ElementType, ElementType, ElementType>(),
        a1.begin(), a2.begin(), tolerance)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  approx_equal(
    small<ElementType, N> const& a1,
    ElementType const& a2,
    ElementType const& tolerance) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.size(),
      make_init_functor(make_array_functor_a_s_s(
        fn::functor_approx_equal<return_element_type,
          ElementType, ElementType, ElementType>(),
        a1.begin(), a2, tolerance)));
  }

  template<typename ElementType, std::size_t N>
  inline
  small<bool, N>
  approx_equal(
    ElementType const& a1,
    small<ElementType, N> const& a2,
    ElementType const& tolerance) {
    typedef small<bool, N>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.size(),
      make_init_functor(make_array_functor_s_a_s(
        fn::functor_approx_equal<return_element_type,
          ElementType, ElementType, ElementType>(),
        a1, a2.begin(), tolerance)));
  }

}} // namespace scitbx::af

#endif // DOXYGEN_SHOULD_SKIP_THIS

#endif // SCITBX_ARRAY_FAMILY_SMALL_ALGEBRA_H
