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

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

#ifndef SCITBX_ARRAY_FAMILY_VERSA_ALGEBRA_H
#define SCITBX_ARRAY_FAMILY_VERSA_ALGEBRA_H

#ifndef DOXYGEN_SHOULD_SKIP_THIS

#include <scitbx/array_family/versa.h>

#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, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator-(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_negate<
          return_element_type,
          ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator!(versa<ElementType, AccessorType> const& a) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_logical_not<
          return_element_type,
          ElementType>(), a.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, AccessorType1>
  operator+(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_plus<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator+(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_plus<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator+(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_plus<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>&
  operator+=(
    versa<ElementType1, AccessorType1>& a1,
    versa<ElementType2, AccessorType2> 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, typename AccessorType>
  inline
  versa<ElementType, AccessorType>&
  operator+=(
    versa<ElementType, AccessorType>& 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, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, AccessorType1>
  operator-(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_minus<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator-(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_minus<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator-(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_minus<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>&
  operator-=(
    versa<ElementType1, AccessorType1>& a1,
    versa<ElementType2, AccessorType2> 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, typename AccessorType>
  inline
  versa<ElementType, AccessorType>&
  operator-=(
    versa<ElementType, AccessorType>& 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, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, AccessorType1>
  operator*(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_multiplies<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator*(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_multiplies<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator*(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_multiplies<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>&
  operator*=(
    versa<ElementType1, AccessorType1>& a1,
    versa<ElementType2, AccessorType2> 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, typename AccessorType>
  inline
  versa<ElementType, AccessorType>&
  operator*=(
    versa<ElementType, AccessorType>& 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, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, AccessorType1>
  operator/(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_divides<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator/(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_divides<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator/(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_divides<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>&
  operator/=(
    versa<ElementType1, AccessorType1>& a1,
    versa<ElementType2, AccessorType2> 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, typename AccessorType>
  inline
  versa<ElementType, AccessorType>&
  operator/=(
    versa<ElementType, AccessorType>& 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, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<
    typename binary_operator_traits<
        ElementType1, ElementType2>::arithmetic, AccessorType1>
  operator%(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<
      typename binary_operator_traits<
          ElementType1, ElementType2>::arithmetic, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_modulus<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator%(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_modulus<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  operator%(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_modulus<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>&
  operator%=(
    versa<ElementType1, AccessorType1>& a1,
    versa<ElementType2, AccessorType2> 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, typename AccessorType>
  inline
  versa<ElementType, AccessorType>&
  operator%=(
    versa<ElementType, AccessorType>& 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, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  operator&&(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_logical_and<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator&&(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_logical_and<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator&&(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_logical_and<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  operator||(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_logical_or<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator||(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_logical_or<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator||(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_logical_or<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  operator==(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_equal_to<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator==(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_equal_to<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator==(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_equal_to<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  operator!=(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      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, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator!=(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_not_equal_to<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

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

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  operator>(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_greater<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator>(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_greater<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator>(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_greater<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  operator<(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_less<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator<(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_less<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator<(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_less<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  operator>=(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_greater_equal<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator>=(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_greater_equal<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator>=(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_greater_equal<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  operator<=(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_less_equal<
          return_element_type,
          ElementType1,
          ElementType2>(), a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator<=(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_less_equal<
          return_element_type,
          ElementType,
          ElementType>(), a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<bool, AccessorType>
  operator<=(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_less_equal<
          return_element_type,
          ElementType,
          ElementType>(), a1, a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  absolute(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_absolute<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  pow2(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_pow2<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  acos(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_acos<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  cos(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_cos<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  tan(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_tan<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  asin(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_asin<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  cosh(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_cosh<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  tanh(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_tanh<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  atan(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_atan<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  exp(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_exp<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  sin(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_sin<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  fabs(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_fabs<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  log(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_log<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  sinh(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_sinh<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  ceil(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_ceil<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  floor(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_floor<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  log10(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_log10<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  sqrt(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_sqrt<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  abs(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_abs<return_element_type, ElementType>(), a.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  conj(versa<ElementType, AccessorType> const& a) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a.accessor(),
      make_init_functor(make_array_functor_a(
        fn::functor_conj<return_element_type, ElementType>(), a.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>
  fmod_positive(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<ElementType1, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_fmod_positive<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  fmod_positive(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_fmod_positive<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  fmod_positive(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_fmod_positive<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>
  fmod(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<ElementType1, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_fmod<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  fmod(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_fmod<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  fmod(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_fmod<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>
  pow(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<ElementType1, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_pow<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  pow(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  pow(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_pow<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>
  atan2(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<ElementType1, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_atan2<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  atan2(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_atan2<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  atan2(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_atan2<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>
  each_min(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<ElementType1, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_each_min<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  each_min(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_each_min<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  each_min(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_each_min<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

  template<
    typename ElementType1, typename AccessorType1,
    typename ElementType2, typename AccessorType2>
  inline
  versa<ElementType1, AccessorType1>
  each_max(
    versa<ElementType1, AccessorType1> const& a1,
    versa<ElementType2, AccessorType2> const& a2) {
    typedef versa<ElementType1, AccessorType1>
    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.accessor(),
      make_init_functor(make_array_functor_a_a(
        fn::functor_each_max<return_element_type,
          ElementType1, ElementType2>(),
        a1.begin(), a2.begin())));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  each_max(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_each_max<return_element_type,
          ElementType, ElementType>(),
        a1.begin(), a2)));
  }

  template<typename ElementType, typename AccessorType>
  inline
  versa<ElementType, AccessorType>
  each_max(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<ElementType, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      make_init_functor(make_array_functor_s_a(
        fn::functor_each_max<return_element_type,
          ElementType, ElementType>(),
        a1, a2.begin())));
  }

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

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

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

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

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

  template<typename ElementType, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    versa<std::complex<ElementType>, AccessorType> const& a1,
    versa<int, AccessorType> const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.accessor(),
      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, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    versa<std::complex<ElementType>, AccessorType> const& a1,
    int const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          int >(), a1.begin(), a2)));
  }

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

  template<typename ElementType, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    versa<std::complex<ElementType>, AccessorType> const& a1,
    versa<ElementType, AccessorType> const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.accessor(),
      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, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    versa<std::complex<ElementType>, AccessorType> const& a1,
    ElementType const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<
          std::complex<ElementType>,
          std::complex<ElementType>,
          ElementType >(), a1.begin(), a2)));
  }

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

  template<typename ElementType, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    versa<std::complex<ElementType>, AccessorType> const& a1,
    versa<std::complex<ElementType>, AccessorType> const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.accessor(),
      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, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    versa<std::complex<ElementType>, AccessorType> const& a1,
    std::complex<ElementType> const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    return return_array_type(a1.accessor(),
      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, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    std::complex<ElementType> const& a1,
    versa<std::complex<ElementType>, AccessorType> const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    return return_array_type(a2.accessor(),
      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, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    versa<ElementType, AccessorType> const& a1,
    versa<std::complex<ElementType>, AccessorType> const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    if (a1.size() != a2.size()) throw_range_error();
    return return_array_type(a1.accessor(),
      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, typename AccessorType>
  inline
  versa<std::complex<ElementType>, AccessorType>
  pow(
    versa<ElementType, AccessorType> const& a1,
    std::complex<ElementType> const& a2) {
    typedef versa<std::complex<ElementType>, AccessorType> return_array_type;
    return return_array_type(a1.accessor(),
      make_init_functor(make_array_functor_a_s(
        fn::functor_pow<
          std::complex<ElementType>,
          ElementType,
          std::complex<ElementType> >(), a1.begin(), a2)));
  }

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

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

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

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

  template<
    typename ElementType, typename AccessorType1, typename AccessorType2>
  inline
  versa<bool, AccessorType1>
  approx_equal(
    versa<ElementType, AccessorType1> const& a1,
    versa<ElementType, AccessorType2> const& a2,
    ElementType const& tolerance) {
    typedef versa<bool, AccessorType1>
    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.accessor(),
      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, typename AccessorType>
  inline
  versa<bool, AccessorType>
  approx_equal(
    versa<ElementType, AccessorType> const& a1,
    ElementType const& a2,
    ElementType const& tolerance) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a1.accessor(),
      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, typename AccessorType>
  inline
  versa<bool, AccessorType>
  approx_equal(
    ElementType const& a1,
    versa<ElementType, AccessorType> const& a2,
    ElementType const& tolerance) {
    typedef versa<bool, AccessorType>
    return_array_type;
    typedef typename return_array_type::value_type return_element_type;
    return return_array_type(a2.accessor(),
      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_VERSA_ALGEBRA_H
