/*
Copyright 2014 Rogier van Dalen.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/** \file
Contain templated helpers for testing math::sequence.
By instantiating these tests once for math::left and once for math::right,
compiling takes a lot less memory and time.
*/

#ifndef MATH_TEST_MATH_TEST_SEQUENCE_TESTS_FAST_HPP_INCLUDED
#define MATH_TEST_MATH_TEST_SEQUENCE_TESTS_FAST_HPP_INCLUDED

#include "math/sequence.hpp"

#include <string>

#include <boost/mpl/assert.hpp>

template <class Direction, class Opposite> void test_sequence_spot() {
    typedef math::sequence <char, Direction> sequence;
    typedef math::empty_sequence <char, Direction> empty_sequence;
    typedef math::optional_sequence <char, Direction> optional_sequence;
    typedef math::single_sequence <char, Direction> single_sequence;
    typedef math::sequence_annihilator <char, Direction>
        sequence_annihilator;

    typedef math::sequence <char, Opposite> opposite_sequence;

    // Conversion.
    {
        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <sequence, opposite_sequence>));

        empty_sequence e;
        single_sequence s ('a');
        // This must be possible without throwing.
        optional_sequence o_e (e);
        optional_sequence o_s ('b');

        sequence_annihilator a;

        // It is impossible to disable conversions from, say, empty_sequence
        // to single_sequence, since the compiler will convert to sequence, and
        // then call the explicit constructor anyway.
        // But these transparently wrong constructors should throw!

        // From empty_sequence.
        BOOST_MPL_ASSERT ((
            std::is_convertible <empty_sequence, empty_sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <empty_sequence, empty_sequence>));

        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <empty_sequence, single_sequence>));
        BOOST_CHECK_THROW (
            single_sequence s (e), math::magma_not_convertible);

        BOOST_MPL_ASSERT ((
            std::is_convertible <empty_sequence, optional_sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <optional_sequence, empty_sequence>));

        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <empty_sequence, sequence_annihilator>));
        BOOST_CHECK_THROW (
            sequence_annihilator a2 (e), math::magma_not_convertible);

        BOOST_MPL_ASSERT ((
            std::is_convertible <empty_sequence, sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <sequence, empty_sequence>));

        // From single_sequence.
        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <single_sequence, empty_sequence>));
        BOOST_CHECK_THROW (empty_sequence e2 (s), math::magma_not_convertible);

        BOOST_MPL_ASSERT ((
            std::is_convertible <single_sequence, single_sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <single_sequence, single_sequence>));

        BOOST_MPL_ASSERT ((
            std::is_convertible <single_sequence, optional_sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <optional_sequence, single_sequence>));

        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <single_sequence, sequence_annihilator>));
        BOOST_CHECK_THROW (
            sequence_annihilator e2 (s), math::magma_not_convertible);

        BOOST_MPL_ASSERT ((std::is_convertible <single_sequence, sequence>));
        BOOST_MPL_ASSERT ((std::is_constructible <sequence, single_sequence>));

        // From optional_sequence.
        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <optional_sequence, empty_sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <optional_sequence, empty_sequence>));
        {
            empty_sequence e2 (o_e);
            BOOST_CHECK_THROW (
                empty_sequence e3 (o_s), math::magma_not_convertible);
        }

        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <optional_sequence, single_sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <single_sequence, optional_sequence>));
        {
            single_sequence s2 (o_s);
            BOOST_CHECK_THROW (
                single_sequence s3 (o_e), math::magma_not_convertible);
        }

        BOOST_MPL_ASSERT ((
            std::is_convertible <optional_sequence, optional_sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <optional_sequence, optional_sequence>));

        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <optional_sequence, sequence_annihilator>));
        BOOST_CHECK_THROW (
            sequence_annihilator e2 (s), math::magma_not_convertible);

        BOOST_MPL_ASSERT ((std::is_convertible <optional_sequence, sequence>));
        BOOST_MPL_ASSERT ((std::is_constructible <
            sequence, optional_sequence>));
        {
            sequence s_o_e (o_e);
            sequence s_o_s (o_s);
        }

        // From sequence_annihilator.
        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <sequence_annihilator, empty_sequence>));
        BOOST_CHECK_THROW (empty_sequence s (a), math::magma_not_convertible);

        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <sequence_annihilator, single_sequence>));
        BOOST_CHECK_THROW (
            single_sequence s (a), math::magma_not_convertible);

        BOOST_MPL_ASSERT ((
            std::is_convertible <sequence_annihilator, sequence_annihilator>));
        BOOST_MPL_ASSERT ((std::is_constructible <
            sequence_annihilator, sequence_annihilator>));

        BOOST_MPL_ASSERT ((
            std::is_convertible <sequence_annihilator, sequence>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <sequence, sequence_annihilator>));

        sequence s_e (e);
        sequence s_s (s);
        sequence s_a (a);
        sequence s_m (std::string ("abc"));

        // Converting from a sequence into anything else: only possible if the
        // sequence contains the right number of elements.
        BOOST_MPL_ASSERT_NOT ((std::is_convertible <sequence, empty_sequence>));
        BOOST_MPL_ASSERT ((std::is_constructible <empty_sequence, sequence>));
        {
            empty_sequence e1 (s_e);
            BOOST_CHECK_THROW (
                empty_sequence e2 (s_s), math::magma_not_convertible);
            BOOST_CHECK_THROW (
                empty_sequence e3 (s_a), math::magma_not_convertible);
            BOOST_CHECK_THROW (
                empty_sequence e4 (s_m), math::magma_not_convertible);
        }

        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <sequence, single_sequence>));
        BOOST_MPL_ASSERT ((std::is_constructible <single_sequence, sequence>));
        {
            BOOST_CHECK_THROW (
                single_sequence e1 (s_e), math::magma_not_convertible);
            single_sequence e2 (s_s);
            BOOST_CHECK_EQUAL (e2.symbol(), 'a');
            BOOST_CHECK_THROW (
                single_sequence e3 (s_a), math::magma_not_convertible);
            BOOST_CHECK_THROW (
                single_sequence e4 (s_m), math::magma_not_convertible);
        }

        BOOST_MPL_ASSERT_NOT ((
            std::is_convertible <sequence, sequence_annihilator>));
        BOOST_MPL_ASSERT ((
            std::is_constructible <sequence_annihilator, sequence>));
        {
            BOOST_CHECK_THROW (
                sequence_annihilator e1 (s_e), math::magma_not_convertible);
            BOOST_CHECK_THROW (
                sequence_annihilator e2 (s_s), math::magma_not_convertible);
            sequence_annihilator e3 (s_a);
            BOOST_CHECK_THROW (
                sequence_annihilator e4 (s_m), math::magma_not_convertible);
        }

        BOOST_MPL_ASSERT ((std::is_convertible <sequence, sequence>));
        BOOST_MPL_ASSERT ((std::is_constructible <sequence, sequence>));
        {
            sequence s1 (s_e);
            sequence s2 (s_s);
            sequence s3 (s_a);
            sequence s4 (s_m);
        }
    }

    BOOST_MPL_ASSERT_NOT ((
        math::has <math::callable::non_member <sequence>()>));
    BOOST_MPL_ASSERT ((math::has <math::callable::is_member (sequence)>));

    BOOST_MPL_ASSERT ((math::has <math::callable::equal (sequence, sequence)>));
    BOOST_MPL_ASSERT ((
        math::has <math::callable::approximately_equal (sequence, sequence)>));

    // Properties of times.
    BOOST_MPL_ASSERT ((math::has <math::callable::times (sequence, sequence)>));
    BOOST_MPL_ASSERT_NOT ((math::is::approximate <
        math::callable::times (sequence, sequence)>));
    BOOST_MPL_ASSERT ((math::has <
        math::callable::identity <sequence, math::callable::times>()>));
    BOOST_CHECK (range::empty (math::one <sequence>().symbols()));
    // Annihilator.
    BOOST_MPL_ASSERT ((math::has <
        math::callable::annihilator <sequence, math::callable::times>()>));
    BOOST_CHECK ((math::annihilator <sequence, math::callable::times>()
        .is_annihilator()));

    BOOST_MPL_ASSERT ((
        math::is::associative <math::callable::times, sequence>));
    BOOST_MPL_ASSERT_NOT ((
        math::is::commutative <math::callable::times, sequence>));

    BOOST_MPL_ASSERT ((math::has <
        math::callable::reverse<> (math::callable::times, sequence)>));

    // Properties of plus.
    BOOST_MPL_ASSERT ((math::has <math::callable::plus (sequence, sequence)>));
    BOOST_MPL_ASSERT_NOT ((math::is::approximate <
        math::callable::plus (sequence, sequence)>));
    BOOST_MPL_ASSERT ((math::has <
        math::callable::identity <sequence, math::callable::plus>()>));
    BOOST_MPL_ASSERT ((math::has <math::callable::zero <sequence>()>));
    BOOST_CHECK (math::zero <sequence>().is_annihilator());
    BOOST_MPL_ASSERT_NOT ((math::has <
        math::callable::annihilator <sequence, math::callable::plus>()>));

    BOOST_MPL_ASSERT ((
        math::is::associative <math::callable::plus, sequence>));
    BOOST_MPL_ASSERT ((
        math::is::commutative <math::callable::plus, sequence>));

    BOOST_MPL_ASSERT ((math::is::idempotent <math::callable::plus, sequence>));
    BOOST_MPL_ASSERT_NOT ((
        math::is::path_operation <math::callable::plus, sequence>));

    // Properties of choose.
    BOOST_MPL_ASSERT ((math::has <
        math::callable::choose (sequence, sequence)>));
    BOOST_MPL_ASSERT_NOT ((math::is::approximate <
        math::callable::choose (sequence, sequence)>));
    BOOST_MPL_ASSERT ((math::has <
        math::callable::identity <sequence, math::callable::choose>()>));
    BOOST_CHECK (math::identity <sequence> (math::choose).is_annihilator());
    BOOST_MPL_ASSERT_NOT ((math::has <
        math::callable::annihilator <sequence, math::callable::choose>()>));

    BOOST_MPL_ASSERT ((
        math::is::associative <math::callable::choose, sequence>));
    BOOST_MPL_ASSERT ((
        math::is::commutative <math::callable::choose, sequence>));

    BOOST_MPL_ASSERT ((
        math::is::idempotent <math::callable::choose, sequence>));
    BOOST_MPL_ASSERT ((
        math::is::path_operation <math::callable::choose, sequence>));

    // Properties of divide.
    BOOST_MPL_ASSERT_NOT ((math::has <
        math::callable::divide<> (sequence, sequence)>));
    BOOST_MPL_ASSERT ((math::has <
        math::callable::divide <Direction> (sequence, sequence)>));
    BOOST_MPL_ASSERT_NOT ((math::is::approximate <
        math::callable::divide <Direction> (sequence, sequence)>));
    BOOST_MPL_ASSERT_NOT ((math::has <
        math::callable::divide <Opposite> (sequence, sequence)>));
    BOOST_MPL_ASSERT ((math::is::throw_if_undefined <
        math::callable::divide <Direction> (sequence, sequence)>));

    // Distributivity with plus: only in one direction.
    BOOST_MPL_ASSERT_NOT ((math::is::distributive <math::either,
        math::callable::times, math::callable::plus, sequence>));
    BOOST_MPL_ASSERT ((math::is::distributive <Direction,
        math::callable::times, math::callable::plus, sequence>));
    BOOST_MPL_ASSERT_NOT ((math::is::distributive <Opposite,
        math::callable::times, math::callable::plus, sequence>));

    // Distributivity with choose: in either direction.
    BOOST_MPL_ASSERT ((math::is::distributive <math::either,
        math::callable::times, math::callable::choose, sequence>));
    BOOST_MPL_ASSERT ((math::is::distributive <Direction,
        math::callable::times, math::callable::choose, sequence>));
    BOOST_MPL_ASSERT ((math::is::distributive <Opposite,
        math::callable::times, math::callable::choose, sequence>));

    // Semiring with plus: only in one direction.
    BOOST_MPL_ASSERT_NOT ((math::is::semiring <math::either,
        math::callable::times, math::callable::plus, sequence>));
    BOOST_MPL_ASSERT ((math::is::semiring <Direction,
        math::callable::times, math::callable::plus, sequence>));
    BOOST_MPL_ASSERT_NOT ((math::is::semiring <Opposite,
        math::callable::times, math::callable::plus, sequence>));

    // Semiring with choose: in either direction.
    BOOST_MPL_ASSERT ((math::is::semiring <math::either,
        math::callable::times, math::callable::choose, sequence>));
    BOOST_MPL_ASSERT ((math::is::semiring <Direction,
        math::callable::times, math::callable::choose, sequence>));
    BOOST_MPL_ASSERT ((math::is::semiring <Opposite,
        math::callable::times, math::callable::choose, sequence>));
}

#endif // MATH_TEST_MATH_TEST_SEQUENCE_TESTS_FAST_HPP_INCLUDED


#include <boost/test/unit_test.hpp>
#include <metaSMT/support/cardinality/Evaluator.hpp>
#include <vector>
#include <metaSMT/support/cardinality.hpp>
#include <metaSMT/frontend/Logic.hpp>

#include <boost/assign/std/vector.hpp>

using namespace std;
using namespace metaSMT;
using namespace metaSMT::solver;
using namespace metaSMT::logic;
using namespace metaSMT::cardinality;
using namespace boost::assign;
namespace proto = boost::proto;

BOOST_FIXTURE_TEST_SUITE(cardinality_t, Solver_Fixture )

BOOST_AUTO_TEST_CASE( test_one_hot ) {
  set_option( ctx, "cardinality", "bdd" );

  predicate a = new_variable();
  predicate b = new_variable();
  predicate c = new_variable();
  predicate d = new_variable();
  predicate e = new_variable();
  bool ad, bd, cd, dd, ed;

  std::vector<ContextType::result_type> vec;

  // one predicate
  vec.push_back( evaluate(ctx, a) );
  assumption(ctx, one_hot(ctx, vec) );
  BOOST_REQUIRE( solve(ctx) );
  ad = read_value(ctx, a);
  BOOST_CHECK_EQUAL(ad, true);

  // two predicate
  vec.push_back( evaluate(ctx, b) );
  assumption(ctx, one_hot(ctx, vec) );
  BOOST_REQUIRE( solve(ctx) );
  ad = read_value(ctx, a);
  bd = read_value(ctx, b);
  BOOST_REQUIRE(   (ad == 1 && bd == 0)
                 | (ad == 0 && bd == 1) );

  // five predicates
  vec.push_back( evaluate(ctx, c) );
  vec.push_back( evaluate(ctx, d) );
  vec.push_back( evaluate(ctx, e) );
  assumption(ctx, one_hot(ctx, vec) );
  BOOST_REQUIRE( solve(ctx) );

  ad = read_value(ctx, a);
  bd = read_value(ctx, b);
  cd = read_value(ctx, c);
  dd = read_value(ctx, d);
  ed = read_value(ctx, e);

  BOOST_REQUIRE(   (ad == 1 && bd == 0 && cd == 0 && dd == 0 && ed == 0)
                 | (ad == 0 && bd == 1 && cd == 0 && dd == 0 && ed == 0)
                 | (ad == 0 && bd == 0 && cd == 1 && dd == 0 && ed == 0)
                 | (ad == 0 && bd == 0 && cd == 0 && dd == 1 && ed == 0)
                 | (ad == 0 && bd == 0 && cd == 0 && dd == 0 && ed == 1) );
}

BOOST_AUTO_TEST_CASE( test_cardinality_eq )
{
  set_option( ctx, "cardinality", "bdd" );

  predicate a = new_variable();
  predicate b = new_variable();
  predicate c = new_variable();
  predicate d = new_variable();
  predicate e = new_variable();
  bool ad, bd, cd, dd, ed;

  std::vector<ContextType::result_type> vec;

  // one predicate
  vec.push_back( evaluate(ctx, a) );
  assumption(ctx, cardinality_eq(ctx, vec, 1) );;
  BOOST_REQUIRE( solve(ctx) );
  ad = read_value(ctx, a);
  std::cout << "a = " << ad << std::endl;
  BOOST_CHECK_EQUAL(ad, true);

  // two predicate
  vec.push_back( evaluate(ctx, b) );
  assumption(ctx, cardinality_eq(ctx, vec, 1) );
  BOOST_REQUIRE( solve(ctx) );
  ad = read_value(ctx, a);
  bd = read_value(ctx, b);
  std::cout << "a = " << ad << std::endl;
  std::cout << "b = " << bd << std::endl;
  BOOST_REQUIRE(   (ad == 1 && bd == 0)
                 | (ad == 0 && bd == 1) );

  // five predicates
  vec.push_back( evaluate(ctx, c) );
  vec.push_back( evaluate(ctx, d) );
  vec.push_back( evaluate(ctx, e) );
  assumption(ctx, cardinality_eq(ctx, vec, 1) );
  BOOST_REQUIRE( solve(ctx) );
  ad = read_value(ctx, a);
  bd = read_value(ctx, b);
  cd = read_value(ctx, c);
  dd = read_value(ctx, d);
  ed = read_value(ctx, e);
  std::cout << "a = " << ad << std::endl;
  std::cout << "b = " << bd << std::endl;
  std::cout << "c = " << cd << std::endl;
  std::cout << "d = " << dd << std::endl;
  std::cout << "e = " << ed << std::endl;
  BOOST_REQUIRE(   (ad == 1 && bd == 0 && cd == 0 && dd == 0 && ed == 0)
                 | (ad == 0 && bd == 1 && cd == 0 && dd == 0 && ed == 0)
                 | (ad == 0 && bd == 0 && cd == 1 && dd == 0 && ed == 0)
                 | (ad == 0 && bd == 0 && cd == 0 && dd == 1 && ed == 0)
                 | (ad == 0 && bd == 0 && cd == 0 && dd == 0 && ed == 1) );

  //
  assumption(ctx, nequal(cardinality_eq(ctx, vec, 1), one_hot(ctx, vec)) );
  BOOST_REQUIRE( !solve(ctx) );
}

template <typename Context, typename Boolean>
void assumeFromUnsigned(Context &ctx, std::vector<Boolean> const &vec, unsigned u) {
  for (unsigned q = 0; q < vec.size(); ++q) {
    if (u & (1 << q)) {
      assumption(ctx, equal(vec[q], True));
    } else {
      assumption(ctx, equal(vec[q], False));
    }
  }
}

template <typename Context>
void checkAllCombinations(Context &ctx) {

  unsigned const width = 8;
  std::vector<predicate> vec;
  for (unsigned u = 0; u < width; ++u) {
    vec.push_back(new_variable());
  }

  for (unsigned u = 0; u < (1 << width); ++u) {
    unsigned count_u = 0;
    for (unsigned v = u; v != 0; v >>= 1) {
      count_u += v & 1;
    }
    for (unsigned r = 0; r <= width; ++r) {
      assumeFromUnsigned(ctx, vec, u);
      assumption(ctx, cardinality_geq(ctx, vec, r));
      BOOST_REQUIRE_EQUAL( solve(ctx), count_u >= r );

      assumeFromUnsigned(ctx, vec, u);
      assumption(ctx, cardinality_leq(ctx, vec, r));
      BOOST_REQUIRE_EQUAL( solve(ctx), count_u <= r );

      assumeFromUnsigned(ctx, vec, u);
      assumption(ctx, cardinality_gt(ctx, vec, r));
      BOOST_REQUIRE_EQUAL( solve(ctx), count_u > r );

      assumeFromUnsigned(ctx, vec, u);
      assumption(ctx, cardinality_lt(ctx, vec, r));
      BOOST_REQUIRE_EQUAL( solve(ctx), count_u < r );

      assumeFromUnsigned(ctx, vec, u);
      assumption(ctx, cardinality_eq(ctx, vec, r));
      BOOST_REQUIRE_EQUAL( solve(ctx), count_u == r );
    }
  }
}

BOOST_AUTO_TEST_CASE( test_bdd_cardinality_with_bv ) {
  set_option( ctx, "cardinality", "bdd" );
  checkAllCombinations(ctx);
}

BOOST_AUTO_TEST_CASE( test_adder_cardinality_with_bv ) {
  set_option( ctx, "cardinality", "adder" );
  checkAllCombinations(ctx);
}

BOOST_AUTO_TEST_SUITE_END() //Solver

//  vim: ft=cpp:ts=2:sw=2:expandtab


#define BOOST_TEST_MODULE WeightsTest
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <sstream>
#include <string>
#include "sparse_vector.h"
#include "fdict.h"

using namespace std;

BOOST_AUTO_TEST_CASE(Dot) {
  SparseVector<double> x;
  SparseVector<double> y;
  x.set_value(1,0.8);
  y.set_value(1,5);
  x.set_value(2,-2);
  y.set_value(2,1);
  x.set_value(3,80);
  BOOST_CHECK_CLOSE(x.dot(y), 2.0, 1e-9);
}

BOOST_AUTO_TEST_CASE(Equality) {
  SparseVector<double> x;
  SparseVector<double> y;
  x.set_value(1,-1);
  y.set_value(1,-1);
  BOOST_CHECK(x == y);
}

BOOST_AUTO_TEST_CASE(Division) {
  SparseVector<double> x;
  SparseVector<double> y;
  x.set_value(1,1);
  y.set_value(1,-1);
  BOOST_CHECK(!(x == y));
  x /= -1;
  BOOST_CHECK(x == y);
}

BOOST_AUTO_TEST_CASE(Serialization) {
  string arc;
  FD::dict_.clear();
  {
    SparseVector<double> x;
    x.set_value(FD::Convert("Feature1"), 1.0);
    x.set_value(FD::Convert("Pi"), 3.14);
    ostringstream os;
    boost::archive::text_oarchive oa(os);
    oa << x;
    arc = os.str();
  }
  FD::dict_.clear();
  FD::Convert("SomeNewString");
  {
    SparseVector<double> x;
    istringstream is(arc);
    boost::archive::text_iarchive ia(is);
    ia >> x;
    cerr << x << endl;
    BOOST_CHECK_CLOSE(x.get(FD::Convert("Pi")), 3.14, 1e-9);
    BOOST_CHECK_CLOSE(x.get(FD::Convert("Feature1")), 1.0, 1e-9);
  }
}


// Copyright (C) 2009-2012 Lorenzo Caminiti
// Distributed under the Boost Software License, Version 1.0
// (see accompanying file LICENSE_1_0.txt or a copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Home at http://www.boost.org/libs/local_function

#include <boost/config.hpp>
#ifdef BOOST_NO_VARIADIC_MACROS
#   error "variadic macros required"
#else

#include <boost/local_function.hpp>
#include <boost/function.hpp>
#include <boost/typeof/typeof.hpp>
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
#include <boost/detail/lightweight_test.hpp>

BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function, 1)

boost::function<int (int)> derivative(boost::function<int (int)>& f, int dx) {
    int BOOST_LOCAL_FUNCTION(bind& f, const bind dx, int x) {
        return (f(x + dx) - f(x)) / dx;
    } BOOST_LOCAL_FUNCTION_NAME(deriv)

    return deriv;
}

int main(void) {
    int BOOST_LOCAL_FUNCTION(int x) {
        return x + 4;
    } BOOST_LOCAL_FUNCTION_NAME(add2)

    boost::function<int (int)> a2 = add2; // Reference valid where closure used.
    boost::function<int (int)> d2 = derivative(a2, 2);
    BOOST_TEST(d2(6) == 1);
    return boost::report_errors();
}

#endif // VARIADIC_MACROS


#ifndef MATHTOOLBOX_KERNEL_FUNCTIONS_HPP
#define MATHTOOLBOX_KERNEL_FUNCTIONS_HPP

#include <Eigen/Core>
#include <functional>

namespace mathtoolbox
{
    using Kernel = std::function<double(const Eigen::VectorXd&, const Eigen::VectorXd&, const Eigen::VectorXd&)>;
    using KernelThetaDerivative =
        std::function<Eigen::VectorXd(const Eigen::VectorXd&, const Eigen::VectorXd&, const Eigen::VectorXd&)>;
    using KernelThetaIDerivative =
        std::function<double(const Eigen::VectorXd&, const Eigen::VectorXd&, const Eigen::VectorXd&, const int)>;
    using KernelFirstArgDerivative =
        std::function<Eigen::VectorXd(const Eigen::VectorXd&, const Eigen::VectorXd&, const Eigen::VectorXd&)>;

    double GetArdSquaredExpKernel(const Eigen::VectorXd& x_a, const Eigen::VectorXd& x_b, const Eigen::VectorXd& theta);

    Eigen::VectorXd GetArdSquaredExpKernelThetaDerivative(const Eigen::VectorXd& x_a,
                                                          const Eigen::VectorXd& x_b,
                                                          const Eigen::VectorXd& theta);

    double GetArdSquaredExpKernelThetaIDerivative(const Eigen::VectorXd& x_a,
                                                  const Eigen::VectorXd& x_b,
                                                  const Eigen::VectorXd& theta,
                                                  const int              index);

    Eigen::VectorXd GetArdSquaredExpKernelFirstArgDerivative(const Eigen::VectorXd& x_a,
                                                             const Eigen::VectorXd& x_b,
                                                             const Eigen::VectorXd& theta);

    double GetArdMatern52Kernel(const Eigen::VectorXd& x_a, const Eigen::VectorXd& x_b, const Eigen::VectorXd& theta);

    Eigen::VectorXd GetArdMatern52KernelThetaDerivative(const Eigen::VectorXd& x_a,
                                                        const Eigen::VectorXd& x_b,
                                                        const Eigen::VectorXd& theta);

    double GetArdMatern52KernelThetaIDerivative(const Eigen::VectorXd& x_a,
                                                const Eigen::VectorXd& x_b,
                                                const Eigen::VectorXd& theta,
                                                const int              index);

    Eigen::VectorXd GetArdMatern52KernelFirstArgDerivative(const Eigen::VectorXd& x_a,
                                                           const Eigen::VectorXd& x_b,
                                                           const Eigen::VectorXd& theta);
} // namespace mathtoolbox

#endif // MATHTOOLBOX_KERNEL_FUNCTIONS_HPP


//
// Copyright (c) 2019-2020 Kris Jusiak (kris at jusiak dot net)
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/ut.hpp>

constexpr auto sum = [](auto... args) { return (0 + ... + args); };

int main() {
  using namespace boost::ut::operators::terse;
  using namespace boost::ut::literals;
  using namespace boost::ut::spec;

  describe("sum") = [] {
    it("should be 0") = [] { sum() == 0_i; };
    it("should add all args") = [] { sum(1, 2, 3) == 6_i; };
  };
}


// Boost.Geometry (aka GGL, Generic Geometry Library)
// QuickBook Example

// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//[svg_mapper
//` Shows the usage of svg_mapper

#include <iostream>
#include <fstream>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>

int main()
{
    // Specify the basic type
    typedef boost::geometry::model::d2::point_xy<double> point_type;

    // Declare some geometries and set their values
    point_type a;
    boost::geometry::assign_values(a, 3, 6);

    boost::geometry::model::polygon<point_type> b;
    boost::geometry::read_wkt("POLYGON((0 0,0 7,4 2,2 0,0 0))", b);

    boost::geometry::model::linestring<point_type> c;
    c.push_back(point_type(3, 4));
    c.push_back(point_type(4, 5));

    // Declare a stream and an SVG mapper
    std::ofstream svg("my_map.svg");
    boost::geometry::svg_mapper<point_type> mapper(svg, 400, 400);

    // Add geometries such that all these geometries fit on the map
    mapper.add(a);
    mapper.add(b);
    mapper.add(c);

    // Draw the geometries on the SVG map, using a specific SVG style
    mapper.map(a, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2", 5);
    mapper.map(b, "fill-opacity:0.3;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
    mapper.map(c, "opacity:0.4;fill:none;stroke:rgb(212,0,0);stroke-width:5");

    // Destructor of map will be called - adding </svg>
    // Destructor of stream will be called, closing the file

    return 0;
}

//]

//[svg_mapper_output
/*`
Output:

[$img/io/svg_mapper.png]
*/
//]


/* ----------------------------------------------------------------------------

 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)

 * See LICENSE for the license information

 * -------------------------------------------------------------------------- */

/**
 * @file   GaussianBayesNet.cpp
 * @brief  Chordal Bayes Net, the result of eliminating a factor graph
 * @author Frank Dellaert
 */

#include <gtsam/linear/GaussianBayesNet.h>
#include <gtsam/linear/GaussianFactorGraph.h>
#include <gtsam/linear/VectorValues.h>
#include <gtsam/inference/BayesNet-inl.h>

#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/tuple/tuple.hpp>

#include <stdarg.h>

using namespace std;
using namespace gtsam;

// trick from some reading group
#define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL)
#define REVERSE_FOREACH_PAIR( KEY, VAL, COL) BOOST_REVERSE_FOREACH (boost::tie(KEY,VAL),COL)

namespace gtsam {

// Explicitly instantiate so we don't have to include everywhere
template class BayesNet<GaussianConditional>;

/* ************************************************************************* */
GaussianBayesNet scalarGaussian(Index key, double mu, double sigma) {
	GaussianBayesNet bn;
	GaussianConditional::shared_ptr
		conditional(new GaussianConditional(key, Vector_(1,mu)/sigma, eye(1)/sigma, ones(1)));
	bn.push_back(conditional);
	return bn;
}

/* ************************************************************************* */
GaussianBayesNet simpleGaussian(Index key, const Vector& mu, double sigma) {
	GaussianBayesNet bn;
	size_t n = mu.size();
	GaussianConditional::shared_ptr
		conditional(new GaussianConditional(key, mu/sigma, eye(n)/sigma, ones(n)));
	bn.push_back(conditional);
	return bn;
}

/* ************************************************************************* */
void push_front(GaussianBayesNet& bn, Index key, Vector d, Matrix R,
		Index name1, Matrix S, Vector sigmas) {
	GaussianConditional::shared_ptr cg(new GaussianConditional(key, d, R, name1, S, sigmas));
	bn.push_front(cg);
}

/* ************************************************************************* */
void push_front(GaussianBayesNet& bn, Index key, Vector d, Matrix R,
		Index name1, Matrix S, Index name2, Matrix T, Vector sigmas) {
	GaussianConditional::shared_ptr cg(new GaussianConditional(key, d, R, name1, S, name2, T, sigmas));
	bn.push_front(cg);
}

/* ************************************************************************* */
boost::shared_ptr<VectorValues> allocateVectorValues(const GaussianBayesNet& bn) {
  vector<size_t> dimensions(bn.size());
  Index var = 0;
  BOOST_FOREACH(const boost::shared_ptr<const GaussianConditional> conditional, bn) {
    dimensions[var++] = conditional->dim();
  }
  return boost::shared_ptr<VectorValues>(new VectorValues(dimensions));
}

/* ************************************************************************* */
VectorValues optimize(const GaussianBayesNet& bn) {
	VectorValues x = *allocateVectorValues(bn);
	optimizeInPlace(bn, x);
	return x;
}

/* ************************************************************************* */
// (R*x)./sigmas = y by solving x=inv(R)*(y.*sigmas)
void optimizeInPlace(const GaussianBayesNet& bn, VectorValues& x) {
	/** solve each node in turn in topological sort order (parents first)*/
	BOOST_REVERSE_FOREACH(const boost::shared_ptr<const GaussianConditional> cg, bn) {
		// i^th part of R*x=y, x=inv(R)*y
		// (Rii*xi + R_i*x(i+1:))./si = yi <-> xi = inv(Rii)*(yi.*si - R_i*x(i+1:))
		cg->solveInPlace(x);
	}
}

/* ************************************************************************* */
VectorValues backSubstitute(const GaussianBayesNet& bn, const VectorValues& input) {
  VectorValues output = input;
  BOOST_REVERSE_FOREACH(const boost::shared_ptr<const GaussianConditional> cg, bn) {
    const Index key = *(cg->beginFrontals());
    Vector xS = internal::extractVectorValuesSlices(output, cg->beginParents(), cg->endParents());
    xS = input[key] - cg->get_S() * xS;
    output[key] = cg->get_R().triangularView<Eigen::Upper>().solve(xS);
  }

  BOOST_FOREACH(const boost::shared_ptr<const GaussianConditional> cg, bn) {
    cg->scaleFrontalsBySigma(output);
  }

  return output;
}

/* ************************************************************************* */
// gy=inv(L)*gx by solving L*gy=gx.
// gy=inv(R'*inv(Sigma))*gx
// gz'*R'=gx', gy = gz.*sigmas
VectorValues backSubstituteTranspose(const GaussianBayesNet& bn,
		const VectorValues& gx) {

	// Initialize gy from gx
	// TODO: used to insert zeros if gx did not have an entry for a variable in bn
	VectorValues gy = gx;

	// we loop from first-eliminated to last-eliminated
	// i^th part of L*gy=gx is done block-column by block-column of L
	BOOST_FOREACH(const boost::shared_ptr<const GaussianConditional> cg, bn)
		cg->solveTransposeInPlace(gy);

	// Scale gy
	BOOST_FOREACH(GaussianConditional::shared_ptr cg, bn)
		cg->scaleFrontalsBySigma(gy);

	return gy;
}

/* ************************************************************************* */
VectorValues optimizeGradientSearch(const GaussianBayesNet& Rd) {
  tic(0, "Allocate VectorValues");
  VectorValues grad = *allocateVectorValues(Rd);
  toc(0, "Allocate VectorValues");

  optimizeGradientSearchInPlace(Rd, grad);

  return grad;
}

/* ************************************************************************* */
void optimizeGradientSearchInPlace(const GaussianBayesNet& Rd, VectorValues& grad) {
  tic(1, "Compute Gradient");
  // Compute gradient (call gradientAtZero function, which is defined for various linear systems)
  gradientAtZero(Rd, grad);
  double gradientSqNorm = grad.dot(grad);
  toc(1, "Compute Gradient");

  tic(2, "Compute R*g");
  // Compute R * g
  FactorGraph<JacobianFactor> Rd_jfg(Rd);
  Errors Rg = Rd_jfg * grad;
  toc(2, "Compute R*g");

  tic(3, "Compute minimizing step size");
  // Compute minimizing step size
  double step = -gradientSqNorm / dot(Rg, Rg);
  toc(3, "Compute minimizing step size");

  tic(4, "Compute point");
  // Compute steepest descent point
  scal(step, grad);
  toc(4, "Compute point");
}

/* ************************************************************************* */
pair<Matrix,Vector> matrix(const GaussianBayesNet& bn)  {

  // add the dimensions of all variables to get matrix dimension
  // and at the same time create a mapping from keys to indices
  size_t N=0; map<Index,size_t> mapping;
  BOOST_FOREACH(GaussianConditional::shared_ptr cg,bn) {
  	GaussianConditional::const_iterator it = cg->beginFrontals();
  	for (; it != cg->endFrontals(); ++it) {
  		mapping.insert(make_pair(*it,N));
  		N += cg->dim(it);
  	}
  }

  // create matrix and copy in values
  Matrix R = zeros(N,N);
  Vector d(N);
  Index key; size_t I;
  FOREACH_PAIR(key,I,mapping) {
    // find corresponding conditional
    boost::shared_ptr<const GaussianConditional> cg = bn[key];

    // get sigmas
    Vector sigmas = cg->get_sigmas();

    // get RHS and copy to d
    GaussianConditional::const_d_type d_ = cg->get_d();
    const size_t n = d_.size();
    for (size_t i=0;i<n;i++)
      d(I+i) = d_(i)/sigmas(i);

    // get leading R matrix and copy to R
    GaussianConditional::const_r_type R_ = cg->get_R();
    for (size_t i=0;i<n;i++)
      for(size_t j=0;j<n;j++)
      	R(I+i,I+j) = R_(i,j)/sigmas(i);

    // loop over S matrices and copy them into R
    GaussianConditional::const_iterator keyS = cg->beginParents();
    for (; keyS!=cg->endParents(); keyS++) {
      Matrix S = cg->get_S(keyS);                   // get S matrix
      const size_t m = S.rows(), n = S.cols(); // find S size
      const size_t J = mapping[*keyS];     // find column index
      for (size_t i=0;i<m;i++)
      	for(size_t j=0;j<n;j++)
      		R(I+i,J+j) = S(i,j)/sigmas(i);
    } // keyS

  } // keyI

  return make_pair(R,d);
}

/* ************************************************************************* */
double determinant(const GaussianBayesNet& bayesNet) {
	double logDet = 0.0;

	BOOST_FOREACH(boost::shared_ptr<const GaussianConditional> cg, bayesNet){
		logDet += cg->get_R().diagonal().unaryExpr(ptr_fun<double,double>(log)).sum();
	}

	return exp(logDet);
}

/* ************************************************************************* */
VectorValues gradient(const GaussianBayesNet& bayesNet, const VectorValues& x0) {
  return gradient(GaussianFactorGraph(bayesNet), x0);
}

/* ************************************************************************* */
void gradientAtZero(const GaussianBayesNet& bayesNet, VectorValues& g) {
  gradientAtZero(GaussianFactorGraph(bayesNet), g);
}

/* ************************************************************************* */

} // namespace gtsam


#pragma once
#include <vector>
#include <set>
#include <algorithm>
#include <boost/range/irange.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/algorithm/cxx11/all_of.hpp>
#include "Sudoku.hpp"
#include "CommonDefinitions.hpp"

namespace
{
    template<typename T>
    bool hasUniqueElements(const std::vector<T>& vec)
    {
        return vec.size() == std::set<T>(vec.cbegin(), vec.cend()).size();
    }
}

class SudokuChecker
{
public:
    SudokuChecker() = default;

    bool isSudokuCorrect(const Sudoku& sudoku) const
    {
        return boost::algorithm::all_of(boost::irange(0u, gridSize),
                                        [this, &sudoku](uint index)
                                        {
                                            return nthRowIsCorrect(sudoku, index) and
                                                   nthColIsCorrect(sudoku, index) and
                                                   nthSqrIsCorrect(sudoku, index);
                                        });
    }
private:
    static constexpr uint latinSqrSize{3};

    bool nthRowIsCorrect(const Sudoku& sudoku, uint rowIndex) const
    {
        return hasUniqueElements(
                   sudoku.getFilledElements(
                       boost::irange(gridSize * rowIndex, gridSize * (rowIndex + 1))));
    }

    bool nthColIsCorrect(const Sudoku& sudoku, uint colIndex) const
    {
        return hasUniqueElements(
                   sudoku.getFilledElements(
                       boost::irange(colIndex, gridElements, gridSize)));
    }

    bool nthSqrIsCorrect(const Sudoku& sudoku, uint sqrIndex) const
    {
        using namespace boost::adaptors;
        auto nthSqr = [this, sqrIndex](uint index)
        {
            auto row = index/gridSize;
            auto col = index%gridSize;
            auto latinSqrRowIndex = latinSqrSize*(sqrIndex/latinSqrSize);
            auto latinSqrColIndex = latinSqrSize*(sqrIndex%latinSqrSize);
            return row == std::clamp(row, latinSqrRowIndex, latinSqrRowIndex + latinSqrSize - 1) and
                   col == std::clamp(col, latinSqrColIndex, latinSqrColIndex + latinSqrSize - 1);
        };
        return hasUniqueElements(
                   sudoku.getFilledElements(
                       boost::irange(0u, gridElements) | filtered(nthSqr)));
    }
};


/**
 * @file walkers.hpp
 *
 * @brief Declarations of public methods and definitions of private/static methods for
 *        the Walkers class.
 */
#ifndef WALKERS_HPP
#define WALKERS_HPP

// External includes
#include <iostream>                 // std::cout and std::endl
#include <map>                      // std::map
#include <vector>                   // std::vector
#include <boost/dynamic_bitset.hpp> // boost::dynamic_bitset

typedef boost::dynamic_bitset<>::size_type size_t ;

/**
 * @class Walkers
 *
 * @brief Class for storing walker occupations in determinant space.
 *        Methods for conducting dynamics.
 *
 *        Our choice of mathematical library (boost) has essentially been made for us here.
 *        While there is a std::bitset, it's size has to be set at compile time, which is
 *        unnecessarily restrictive for our purposes. However, a perusal of stackoverflow:
 *
 *        https://stackoverflow.com/questions/3134718/define-bitset-size-at-initialization
 *
 *        reveals that boost contains a bitset class whose size can be set at runtime. We'll
 *        pursue this solution for the moment, but if something like armadillo or trilinos
 *        proves significantly better for the types of operation we conduct in this application,
 *        we'll have to rethink.
 */
class Walkers {

public:
  // Constructors/ Destructors
  Walkers( const size_t _nWalkers, const size_t _nSpinOrbs ) ;

  // Getters/ Setters
  void nWalkers( const size_t _nWalkers ) ;
  std::size_t nWalkers( ) const ;

  // General methods for calculation
  size_t nDiff( const boost::dynamic_bitset<> & det_a, const boost::dynamic_bitset<> & det_b ) const ;

private:
  std::size_t my_nWalkers ;
  // We use std::vector for determinant occupations because I think we'll need random access
  // to the array when we start doing spawning and deaths (?)
  // TODO : We need to be able to keep track of the number of walkers on each determinant,
  //        as well as other bit flags, e.g. whether walker spawned from an initiator.
  std::vector< boost::dynamic_bitset<> > my_determinants ;
  std::vector< std::map< boost::dynamic_bitset<>, std::vector<size_t> > > my_occupation_luts ;

} ;

#endif /* #ifndef WALKERS_HPP */


//
// Created by Alex Beccaro on 18/01/18.
//

#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include "../../src/problems/51-100/60/problem60.hpp"

BOOST_AUTO_TEST_SUITE( Problem60 )

    BOOST_AUTO_TEST_CASE( Example ) {
        auto res = problems::problem60::solve(4);
        BOOST_CHECK_EQUAL(res, 792);
    }

    BOOST_AUTO_TEST_CASE( Solution ) {
        auto res = problems::problem60::solve();
        BOOST_CHECK_EQUAL(res, 26033);
    }

BOOST_AUTO_TEST_SUITE_END()


// Copyright 2011-2017 Ryan Curtin (http://www.ratml.org/)
// Copyright 2017 National ICT Australia (NICTA)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------

#include <armadillo>

#include "catch.hpp"

using namespace arma;

TEST_CASE("fn_mean_spmat_empty_test")
  {
  SpMat<double> m(20, 25);

  SpRow<double> result = mean(m, 0);
  REQUIRE( result.n_nonzero == 0 );
  REQUIRE( result.n_rows == 1 );
  REQUIRE( result.n_cols == 25 );

  SpCol<double> result2 = mean(m, 1);
  REQUIRE( result2.n_nonzero == 0 );
  REQUIRE( result2.n_rows == 20 );
  REQUIRE( result2.n_cols == 1 );

  double r = mean(mean(m));
  REQUIRE( r == Approx(0.0) );

  // Now the same with subviews.
  result = mean(m.submat(2, 2, 11, 16));
  REQUIRE( result.n_nonzero == 0 );
  REQUIRE( result.n_rows == 1 );
  REQUIRE( result.n_cols == 15 );

  result2 = mean(m.submat(2, 2, 11, 16), 1);
  REQUIRE( result2.n_nonzero == 0 );
  REQUIRE( result2.n_rows == 10 );
  REQUIRE( result2.n_cols == 1 );

  r = mean(mean(m.submat(2, 2, 11, 16)));
  REQUIRE( r == Approx(0.0) );

  // And with an operation.
  result = mean(trans(m));
  REQUIRE( result.n_nonzero == 0 );
  REQUIRE( result.n_rows == 1 );
  REQUIRE( result.n_cols == 20 );

  result2 = mean(trans(m), 1);
  REQUIRE( result2.n_nonzero == 0 );
  REQUIRE( result2.n_rows == 25 );
  REQUIRE( result2.n_cols == 1 );

  r = mean(mean(trans(m)));
  REQUIRE( r == Approx(0.0) );
  }

TEST_CASE("fn_mean_spcxmat_empty_test")
  {
  // Now with complex numbers.
  SpMat<std::complex<double> > m(20, 25);
  SpRow<std::complex<double> > result = mean(m, 0);

  REQUIRE( result.n_nonzero == 0 );
  REQUIRE( result.n_rows == 1 );
  REQUIRE( result.n_cols == 25 );

  SpCol<std::complex<double> > result2 = mean(m, 1);

  REQUIRE( result2.n_nonzero == 0 );
  REQUIRE( result2.n_rows == 20 );
  REQUIRE( result2.n_cols == 1 );

  std::complex<double> r = mean(mean(m));

  REQUIRE( real(r) == Approx(0.0) );
  REQUIRE( imag(r) == Approx(0.0) );

  // Now the same with subviews.
  result = mean(m.submat(2, 2, 11, 16));
  REQUIRE( result.n_nonzero == 0 );
  REQUIRE( result.n_rows == 1 );
  REQUIRE( result.n_cols == 15 );

  result2 = mean(m.submat(2, 2, 11, 16), 1);
  REQUIRE( result2.n_nonzero == 0 );
  REQUIRE( result2.n_rows == 10 );
  REQUIRE( result2.n_cols == 1 );

  r = mean(mean(m.submat(2, 2, 11, 16)));
  REQUIRE( real(r) == Approx(0.0) );
  REQUIRE( imag(r) == Approx(0.0) );

  // And with an operation.
  result = mean(trans(m));
  REQUIRE( result.n_nonzero == 0 );
  REQUIRE( result.n_rows == 1 );
  REQUIRE( result.n_cols == 20 );

  result2 = mean(trans(m), 1);
  REQUIRE( result2.n_nonzero == 0 );
  REQUIRE( result2.n_rows == 25 );
  REQUIRE( result2.n_cols == 1 );

  r = mean(mean(trans(m)));
  REQUIRE( real(r) == Approx(0.0) );
  REQUIRE( imag(r) == Approx(0.0) );
  }

TEST_CASE("fn_mean_spmat_test")
  {
  // Create a random matrix and do mean testing on it, with varying levels of
  // nonzero (eventually this becomes a fully dense matrix).
  for (int i = 0; i < 10; ++i)
    {
    SpMat<double> x;
    x.sprandu(50, 75, ((double) (i + 1)) / 10);
    mat d(x);

    SpRow<double> rr = mean(x);
    rowvec drr = mean(d);

    REQUIRE( rr.n_rows == 1 );
    REQUIRE( rr.n_cols == 75 );
    for (uword j = 0; j < 75; ++j)
      REQUIRE( drr[j] == Approx((double) rr[j]) );

    SpCol<double> cr = mean(x, 1);
    vec dcr = mean(d, 1);

    REQUIRE( cr.n_rows == 50 );
    REQUIRE( cr.n_cols == 1 );
    for (uword j = 0; j < 50; ++j)
      REQUIRE( dcr[j] == Approx((double) cr[j]) );

    double dr = mean(mean(x));
    double ddr = mean(mean(d));

    REQUIRE( dr == Approx(ddr) );

    // Now on a subview.
    rr = mean(x.submat(11, 11, 30, 45), 0);
    drr = mean(d.submat(11, 11, 30, 45), 0);

    REQUIRE( rr.n_rows == 1 );
    REQUIRE( rr.n_cols == 35 );
    for (uword j = 0; j < 35; ++j)
      REQUIRE( drr[j] == Approx((double) rr[j]) );

    cr = mean(x.submat(11, 11, 30, 45), 1);
    dcr = mean(d.submat(11, 11, 30, 45), 1);

    REQUIRE( cr.n_rows == 20 );
    REQUIRE( cr.n_cols == 1 );
    for (uword j = 0; j < 20; ++j)
      REQUIRE( dcr[j] == Approx((double) cr[j]) );

    dr = mean(mean(x.submat(11, 11, 30, 45)));
    ddr = mean(mean(d.submat(11, 11, 30, 45)));

    REQUIRE( dr == Approx(ddr) );

    // Now on an SpOp (spop_scalar_times)
    rr = mean(3.0 * x);
    drr = mean(3.0 * d);

    REQUIRE( rr.n_rows == 1 );
    REQUIRE( rr.n_cols == 75 );
    for (uword j = 0; j < 75; ++j)
      REQUIRE( drr[j] == Approx((double) rr[j]) );

    cr = mean(4.5 * x, 1);
    dcr = mean(4.5 * d, 1);

    REQUIRE( cr.n_rows == 50 );
    REQUIRE( cr.n_cols == 1 );
    for (uword j = 0; j < 50; ++j)
      REQUIRE( dcr[j] == Approx((double) cr[j]) );

    dr = mean(mean(1.2 * x));
    ddr = mean(mean(1.2 * d));

    REQUIRE( dr == Approx(ddr) );

    // Now on an SpGlue!
    SpMat<double> y;
    y.sprandu(50, 75, 0.3);
    mat e(y);

    rr = mean(x + y);
    drr = mean(d + e);

    REQUIRE( rr.n_rows == 1 );
    REQUIRE( rr.n_cols == 75 );
    for (uword j = 0; j < 75; ++j)
      REQUIRE( drr[j] == Approx((double) rr[j]) );

    cr = mean(x + y, 1);
    dcr = mean(d + e, 1);

    REQUIRE( cr.n_rows == 50 );
    REQUIRE( cr.n_cols == 1 );
    for (uword j = 0; j < 50; ++j)
      REQUIRE( dcr[j] == Approx((double) cr[j]) );

    dr = mean(mean(x + y));
    ddr = mean(mean(d + e));

    REQUIRE( dr == Approx(ddr) );
    }
  }

TEST_CASE("fn_mean_spcxmat_test")
  {
  // Create a random matrix and do mean testing on it, with varying levels of
  // nonzero (eventually this becomes a fully dense matrix).
  for (int i = 0; i < 10; ++i)
  {
    SpMat<std::complex<double> > x;
    x.sprandu(50, 75, ((double) (i + 1)) / 10);
    cx_mat d(x);

    SpRow<std::complex<double> > rr = mean(x);
    cx_rowvec drr = mean(d);

    REQUIRE( rr.n_rows == 1 );
    REQUIRE( rr.n_cols == 75 );
    for (uword j = 0; j < 75; ++j)
      {
      REQUIRE( real(drr[j]) == Approx(real((std::complex<double>) rr[j])) );
      REQUIRE( imag(drr[j]) == Approx(imag((std::complex<double>) rr[j])) );
      }

    SpCol<std::complex<double> > cr = mean(x, 1);
    cx_vec dcr = mean(d, 1);

    REQUIRE( cr.n_rows == 50 );
    REQUIRE( cr.n_cols == 1 );
    for (uword j = 0; j < 50; ++j)
      {
      REQUIRE( real(dcr[j]) == Approx(real((std::complex<double>) cr[j])) );
      REQUIRE( imag(dcr[j]) == Approx(imag((std::complex<double>) cr[j])) );
      }

    std::complex<double> dr = mean(mean(x));
    std::complex<double> ddr = mean(mean(d));

    REQUIRE( real(dr) == Approx(real(ddr)) );
    REQUIRE( imag(dr) == Approx(imag(ddr)) );

    // Now on a subview.
    rr = mean(x.submat(11, 11, 30, 45), 0);
    drr = mean(d.submat(11, 11, 30, 45), 0);

    REQUIRE( rr.n_rows == 1 );
    REQUIRE( rr.n_cols == 35 );
    for (uword j = 0; j < 35; ++j)
      {
      REQUIRE( real(drr[j]) == Approx(real((std::complex<double>) rr[j])) );
      REQUIRE( imag(drr[j]) == Approx(imag((std::complex<double>) rr[j])) );
      }

    cr = mean(x.submat(11, 11, 30, 45), 1);
    dcr = mean(d.submat(11, 11, 30, 45), 1);

    REQUIRE( cr.n_rows == 20 );
    REQUIRE( cr.n_cols == 1 );
    for (uword j = 0; j < 20; ++j)
      {
      REQUIRE( real(dcr[j]) == Approx(real((std::complex<double>) cr[j])) );
      REQUIRE( imag(dcr[j]) == Approx(imag((std::complex<double>) cr[j])) );
      }

    dr = mean(mean(x.submat(11, 11, 30, 45)));
    ddr = mean(mean(d.submat(11, 11, 30, 45)));

    REQUIRE( real(dr) == Approx(real(ddr)) );
    REQUIRE( imag(dr) == Approx(imag(ddr)) );

    // Now on an SpOp (spop_scalar_times)
    rr = mean(3.0 * x);
    drr = mean(3.0 * d);

    REQUIRE( rr.n_rows == 1 );
    REQUIRE( rr.n_cols == 75 );
    for (uword j = 0; j < 75; ++j)
      {
      REQUIRE( real(drr[j]) == Approx(real((std::complex<double>) rr[j])) );
      REQUIRE( imag(drr[j]) == Approx(imag((std::complex<double>) rr[j])) );
      }

    cr = mean(4.5 * x, 1);
    dcr = mean(4.5 * d, 1);

    REQUIRE( cr.n_rows == 50 );
    REQUIRE( cr.n_cols == 1 );
    for (uword j = 0; j < 50; ++j)
      {
      REQUIRE( real(dcr[j]) == Approx(real((std::complex<double>) cr[j])) );
      REQUIRE( imag(dcr[j]) == Approx(imag((std::complex<double>) cr[j])) );
      }

    dr = mean(mean(1.2 * x));
    ddr = mean(mean(1.2 * d));

    REQUIRE( real(dr) == Approx(real(ddr)) );
    REQUIRE( imag(dr) == Approx(imag(ddr)) );

    // Now on an SpGlue!
    SpMat<std::complex<double> > y;
    y.sprandu(50, 75, 0.3);
    cx_mat e(y);

    rr = mean(x + y);
    drr = mean(d + e);

    REQUIRE( rr.n_rows == 1 );
    REQUIRE( rr.n_cols == 75 );
    for (uword j = 0; j < 75; ++j)
      {
      REQUIRE( real(drr[j]) == Approx(real((std::complex<double>) rr[j])) );
      REQUIRE( imag(drr[j]) == Approx(imag((std::complex<double>) rr[j])) );
      }

    cr = mean(x + y, 1);
    dcr = mean(d + e, 1);

    REQUIRE( cr.n_rows == 50 );
    REQUIRE( cr.n_cols == 1 );
    for (uword j = 0; j < 50; ++j)
      {
      REQUIRE( real(dcr[j]) == Approx(real((std::complex<double>) cr[j])) );
      REQUIRE( imag(dcr[j]) == Approx(imag((std::complex<double>) cr[j])) );
      }

    dr = mean(mean(x + y));
    ddr = mean(mean(d + e));

    REQUIRE( real(dr) == Approx(real(ddr)) );
    REQUIRE( imag(dr) == Approx(imag(ddr)) );
    }
  }

TEST_CASE("fn_mean_sp_vector_test")
  {
  // Test mean() on vectors.
  SpCol<double> c(1000);

  SpCol<double> cr = mean(c, 0);
  REQUIRE( cr.n_rows == 1 );
  REQUIRE( cr.n_cols == 1 );
  REQUIRE( (double) cr[0] == Approx(0.0) );

  cr = mean(c, 1);
  REQUIRE( cr.n_rows == 1000 );
  REQUIRE( cr.n_cols == 1 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( (double) cr[i] == Approx(0.0) );
    }

  double ddcr = mean(c);
  REQUIRE( ddcr == Approx(0.0) );

  c.sprandu(1000, 1, 0.3);
  vec dc(c);

  cr = mean(c, 0);
  vec dcr = mean(dc, 0);

  REQUIRE( cr.n_rows == 1 );
  REQUIRE( cr.n_cols == 1 );
  REQUIRE( (double) cr[0] == Approx(dcr[0]) );

  cr = mean(c, 1);
  dcr = mean(dc, 1);

  REQUIRE( cr.n_rows == 1000 );
  REQUIRE( cr.n_cols == 1 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( (double) cr[i] == Approx(dcr[i]) );
    }

  ddcr = mean(c);
  double dddr = mean(dc);

  REQUIRE( ddcr == Approx(dddr) );

  SpRow<double> r;
  r.sprandu(1, 1000, 0.3);
  rowvec dr(r);

  SpRow<double> rr = mean(r, 0);
  rowvec drr = mean(dr, 0);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 1000 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( (double) rr[i] == Approx(drr[i]) );
    }

  rr = mean(r, 1);
  drr = mean(dr, 1);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 1 );
  REQUIRE( (double) rr[0] == Approx(drr[0]) );

  ddcr = mean(r);
  dddr = mean(dr);

  REQUIRE( ddcr == Approx(dddr) );
  }

TEST_CASE("fn_mean_sp_cx_vector_test")
  {
  // Test mean() on vectors.
  SpCol<std::complex<double> > c(1000);

  SpCol<std::complex<double> > cr = mean(c, 0);
  REQUIRE( cr.n_rows == 1 );
  REQUIRE( cr.n_cols == 1 );
  REQUIRE( real((std::complex<double>) cr[0]) == Approx(0.0) );
  REQUIRE( imag((std::complex<double>) cr[0]) == Approx(0.0) );

  cr = mean(c, 1);
  REQUIRE( cr.n_rows == 1000 );
  REQUIRE( cr.n_cols == 1 );
  for (uword i = 0; i < 1000; ++i)
  {
    REQUIRE( real((std::complex<double>) cr[i]) == Approx(0.0) );
    REQUIRE( imag((std::complex<double>) cr[i]) == Approx(0.0) );
  }

  std::complex<double> ddcr = mean(c);
  REQUIRE( real(ddcr) == Approx(0.0) );
  REQUIRE( imag(ddcr) == Approx(0.0) );

  c.sprandu(1000, 1, 0.3);
  cx_vec dc(c);

  cr = mean(c, 0);
  cx_vec dcr = mean(dc, 0);

  REQUIRE( cr.n_rows == 1 );
  REQUIRE( cr.n_cols == 1 );
  REQUIRE( real((std::complex<double>) cr[0]) == Approx(real(dcr[0])) );
  REQUIRE( imag((std::complex<double>) cr[0]) == Approx(imag(dcr[0])) );

  cr = mean(c, 1);
  dcr = mean(dc, 1);

  REQUIRE( cr.n_rows == 1000 );
  REQUIRE( cr.n_cols == 1 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( real((std::complex<double>) cr[i]) == Approx(real(dcr[i])) );
    REQUIRE( imag((std::complex<double>) cr[i]) == Approx(imag(dcr[i])) );
    }

  ddcr = mean(c);
  std::complex<double> dddr = mean(dc);

  REQUIRE( real(ddcr) == Approx(real(dddr)) );
  REQUIRE( imag(ddcr) == Approx(imag(dddr)) );

  SpRow<std::complex<double> > r;
  r.sprandu(1, 1000, 0.3);
  cx_rowvec dr(r);

  SpRow<std::complex<double> > rr = mean(r, 0);
  cx_rowvec drr = mean(dr, 0);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 1000 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( real((std::complex<double>) rr[i]) == Approx(real(drr[i])) );
    REQUIRE( imag((std::complex<double>) rr[i]) == Approx(imag(drr[i])) );
    }

  rr = mean(r, 1);
  drr = mean(dr, 1);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 1 );
  REQUIRE( real((std::complex<double>) rr[0]) == Approx(real(drr[0])) );
  REQUIRE( imag((std::complex<double>) rr[0]) == Approx(imag(drr[0])) );

  ddcr = mean(r);
  dddr = mean(dr);

  REQUIRE( real(ddcr) == Approx(real(dddr)) );
  REQUIRE( imag(ddcr) == Approx(imag(dddr)) );
  }

TEST_CASE("fn_mean_robust_sparse_test")
  {
  // Create a sparse matrix with values that will overflow.
  SpMat<double> x;
  x.sprandu(50, 75, 0.1);
  for (SpMat<double>::iterator i = x.begin(); i != x.end(); ++i)
    {
    (*i) *= std::numeric_limits<double>::max();
    }
  mat d(x);

  SpRow<double> rr = mean(x);
  rowvec drr = mean(d);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 75 );
  for (uword j = 0; j < 75; ++j)
    {
    REQUIRE( drr[j] == Approx((double) rr[j]) );
    }

  SpCol<double> cr = mean(x, 1);
  vec dcr = mean(d, 1);

  REQUIRE( cr.n_rows == 50 );
  REQUIRE( cr.n_cols == 1 );
  for (uword j = 0; j < 50; ++j)
    {
    REQUIRE( dcr[j] == Approx((double) cr[j]) );
    }

  double dr = mean(mean(x));
  double ddr = mean(mean(d));

  REQUIRE( dr == Approx(ddr) );

  // Now on a subview.
  rr = mean(x.submat(11, 11, 30, 45), 0);
  drr = mean(d.submat(11, 11, 30, 45), 0);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 35 );
  for (uword j = 0; j < 35; ++j)
    {
    REQUIRE( drr[j] == Approx((double) rr[j]) );
    }

  cr = mean(x.submat(11, 11, 30, 45), 1);
  dcr = mean(d.submat(11, 11, 30, 45), 1);

  REQUIRE( cr.n_rows == 20 );
  REQUIRE( cr.n_cols == 1 );
  for (uword j = 0; j < 20; ++j)
    {
    REQUIRE( dcr[j] == Approx((double) cr[j]) );
    }

  dr = mean(mean(x.submat(11, 11, 30, 45)));
  ddr = mean(mean(d.submat(11, 11, 30, 45)));

  REQUIRE( dr == Approx(ddr) );

  // Now on an SpOp (spop_scalar_times)
  rr = mean(0.4 * x);
  drr = mean(0.4 * d);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 75 );
  for (uword j = 0; j < 75; ++j)
    {
    REQUIRE( drr[j] == Approx((double) rr[j]) );
    }

  cr = mean(0.1 * x, 1);
  dcr = mean(0.1 * d, 1);

  REQUIRE( cr.n_rows == 50 );
  REQUIRE( cr.n_cols == 1 );
  for (uword j = 0; j < 50; ++j)
    {
    REQUIRE( dcr[j] == Approx((double) cr[j]) );
    }

  dr = mean(mean(0.7 * x));
  ddr = mean(mean(0.7 * d));

  REQUIRE( dr == Approx(ddr) );

  // Now on an SpGlue!
  SpMat<double> y;
  y.sprandu(50, 75, 0.3);
  for (SpMat<double>::iterator i = y.begin(); i != y.end(); ++i)
    {
    (*i) *= std::numeric_limits<double>::max();
    }
  mat e(y);

  rr = mean(0.5 * x + 0.5 * y);
  drr = mean(0.5 * d + 0.5 * e);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 75 );
  for (uword j = 0; j < 75; ++j)
    {
    REQUIRE( drr[j] == Approx((double) rr[j]) );
    }

  cr = mean(0.5 * x + 0.5 * y, 1);
  dcr = mean(0.5 * d + 0.5 * e, 1);

  REQUIRE( cr.n_rows == 50 );
  REQUIRE( cr.n_cols == 1 );
  for (uword j = 0; j < 50; ++j)
    {
    REQUIRE( dcr[j] == Approx((double) cr[j]) );
    }

  dr = mean(mean(0.5 * x + 0.5 * y));
  ddr = mean(mean(0.5 * d + 0.5 * e));

  REQUIRE( dr == Approx(ddr) );
  }

TEST_CASE("fn_mean_robust_cx_sparse_test")
  {
  SpMat<std::complex<double> > x;
  x.sprandu(50, 75, 0.3);
  for (SpMat<std::complex<double> >::iterator i = x.begin(); i != x.end(); ++i)
    {
    (*i) *= std::numeric_limits<double>::max();
    }
  cx_mat d(x);

  SpRow<std::complex<double> > rr = mean(x);
  cx_rowvec drr = mean(d);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 75 );
  for (uword j = 0; j < 75; ++j)
    {
    REQUIRE( real(drr[j]) == Approx(real((std::complex<double>) rr[j])) );
    REQUIRE( imag(drr[j]) == Approx(imag((std::complex<double>) rr[j])) );
    }

  SpCol<std::complex<double> > cr = mean(x, 1);
  cx_vec dcr = mean(d, 1);

  REQUIRE( cr.n_rows == 50 );
  REQUIRE( cr.n_cols == 1 );
  for (uword j = 0; j < 50; ++j)
    {
    REQUIRE( real(dcr[j]) == Approx(real((std::complex<double>) cr[j])) );
    REQUIRE( imag(dcr[j]) == Approx(imag((std::complex<double>) cr[j])) );
    }

  std::complex<double> dr = mean(mean(x));
  std::complex<double> ddr = mean(mean(d));

  REQUIRE( real(dr) == Approx(real(ddr)) );
  REQUIRE( imag(dr) == Approx(imag(ddr)) );

  // Now on a subview.
  rr = mean(x.submat(11, 11, 30, 45), 0);
  drr = mean(d.submat(11, 11, 30, 45), 0);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 35 );
  for (uword j = 0; j < 35; ++j)
    {
    REQUIRE( real(drr[j]) == Approx(real((std::complex<double>) rr[j])) );
    REQUIRE( imag(drr[j]) == Approx(imag((std::complex<double>) rr[j])) );
    }

  cr = mean(x.submat(11, 11, 30, 45), 1);
  dcr = mean(d.submat(11, 11, 30, 45), 1);

  REQUIRE( cr.n_rows == 20 );
  REQUIRE( cr.n_cols == 1 );
  for (uword j = 0; j < 20; ++j)
    {
    REQUIRE( real(dcr[j]) == Approx(real((std::complex<double>) cr[j])) );
    REQUIRE( imag(dcr[j]) == Approx(imag((std::complex<double>) cr[j])) );
    }

  dr = mean(mean(x.submat(11, 11, 30, 45)));
  ddr = mean(mean(d.submat(11, 11, 30, 45)));

  REQUIRE( real(dr) == Approx(real(ddr)) );
  REQUIRE( imag(dr) == Approx(imag(ddr)) );

  // Now on an SpOp (spop_scalar_times)
  rr = mean(0.5 * x);
  drr = mean(0.5 * d);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 75 );
  for (uword j = 0; j < 75; ++j)
    {
    REQUIRE( real(drr[j]) == Approx(real((std::complex<double>) rr[j])) );
    REQUIRE( imag(drr[j]) == Approx(imag((std::complex<double>) rr[j])) );
    }

  cr = mean(0.7 * x, 1);
  dcr = mean(0.7 * d, 1);

  REQUIRE( cr.n_rows == 50 );
  REQUIRE( cr.n_cols == 1 );
  for (uword j = 0; j < 50; ++j)
    {
    REQUIRE( real(dcr[j]) == Approx(real((std::complex<double>) cr[j])) );
    REQUIRE( imag(dcr[j]) == Approx(imag((std::complex<double>) cr[j])) );
    }

  dr = mean(mean(0.6 * x));
  ddr = mean(mean(0.6 * d));

  REQUIRE( real(dr) == Approx(real(ddr)) );
  REQUIRE( imag(dr) == Approx(imag(ddr)) );

  // Now on an SpGlue!
  SpMat<std::complex<double> > y;
  y.sprandu(50, 75, 0.3);
  for (SpMat<std::complex<double> >::iterator i = y.begin(); i != y.end(); ++i)
    {
    (*i) *= std::numeric_limits<double>::max();
    }
  cx_mat e(y);

  rr = mean(0.5 * x + 0.5 * y);
  drr = mean(0.5 * d + 0.5 * e);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 75 );
  for (uword j = 0; j < 75; ++j)
    {
    REQUIRE( real(drr[j]) == Approx(real((std::complex<double>) rr[j])) );
    REQUIRE( imag(drr[j]) == Approx(imag((std::complex<double>) rr[j])) );
    }

  cr = mean(0.5 * x + 0.5 * y, 1);
  dcr = mean(0.5 * d + 0.5 * e, 1);

  REQUIRE( cr.n_rows == 50 );
  REQUIRE( cr.n_cols == 1 );
  for (uword j = 0; j < 50; ++j)
    {
    REQUIRE( real(dcr[j]) == Approx(real((std::complex<double>) cr[j])) );
    REQUIRE( imag(dcr[j]) == Approx(imag((std::complex<double>) cr[j])) );
    }

  dr = mean(mean(0.5 * x + 0.5 * y));
  ddr = mean(mean(0.5 * d + 0.5 * e));

  REQUIRE( real(dr) == Approx(real(ddr)) );
  REQUIRE( imag(dr) == Approx(imag(ddr)) );
  }

TEST_CASE("fn_mean_robust_sparse_vector_test")
  {
  // Test mean() on vectors.
  SpCol<double> c(1000);

  SpCol<double> cr;
  double ddcr;

  c.sprandu(1000, 1, 0.3);
  for (SpCol<double>::iterator i = c.begin(); i != c.end(); ++i)
    {
    (*i) *= (std::numeric_limits<double>::max());
    }
  vec dc(c);

  cr = mean(c, 0);
  vec dcr = mean(dc, 0);

  REQUIRE( cr.n_rows == 1 );
  REQUIRE( cr.n_cols == 1 );
  REQUIRE( (double) cr[0] == Approx(dcr[0]) );

  cr = mean(c, 1);
  dcr = mean(dc, 1);

  REQUIRE( cr.n_rows == 1000 );
  REQUIRE( cr.n_cols == 1 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( (double) cr[i] == Approx(dcr[i]) );
    }

  ddcr = mean(c);
  double dddr = mean(dc);

  REQUIRE( ddcr == Approx(dddr) );

  SpRow<double> r;
  r.sprandu(1, 1000, 0.3);
  for (SpRow<double>::iterator i = r.begin(); i != r.end(); ++i)
    {
    (*i) *= (std::numeric_limits<double>::max());
    }
  rowvec dr(r);

  SpRow<double> rr = mean(r, 0);
  rowvec drr = mean(dr, 0);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 1000 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( (double) rr[i] == Approx(drr[i]) );
    }

  rr = mean(r, 1);
  drr = mean(dr, 1);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 1 );
  REQUIRE( (double) rr[0] == Approx(drr[0]) );

  ddcr = mean(r);
  dddr = mean(dr);

  REQUIRE( ddcr == Approx(dddr) );
  }

TEST_CASE("fn_mean_robust_cx_sparse_vector_test")
  {
  // Test mean() on vectors.
  SpCol<std::complex<double> > c(1000);

  SpCol<std::complex<double> > cr;
  std::complex<double> ddcr;

  c.sprandu(1000, 1, 0.3);
  for (SpCol<std::complex<double> >::iterator i = c.begin(); i != c.end(); ++i)
    {
    (*i) *= (std::numeric_limits<double>::max());
    }
  cx_vec dc(c);

  cr = mean(c, 0);
  cx_vec dcr = mean(dc, 0);

  REQUIRE( cr.n_rows == 1 );
  REQUIRE( cr.n_cols == 1 );
  REQUIRE( real((std::complex<double>) cr[0]) == Approx(real(dcr[0])) );
  REQUIRE( imag((std::complex<double>) cr[0]) == Approx(imag(dcr[0])) );

  cr = mean(c, 1);
  dcr = mean(dc, 1);

  REQUIRE( cr.n_rows == 1000 );
  REQUIRE( cr.n_cols == 1 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( real((std::complex<double>) cr[i]) == Approx(real(dcr[i])) );
    REQUIRE( imag((std::complex<double>) cr[i]) == Approx(imag(dcr[i])) );
    }

  ddcr = mean(c);
  std::complex<double> dddr = mean(dc);

  REQUIRE( real(ddcr) == Approx(real(dddr)) );
  REQUIRE( imag(ddcr) == Approx(imag(dddr)) );

  SpRow<std::complex<double> > r;
  r.sprandu(1, 1000, 0.3);
  cx_rowvec dr(r);

  SpRow<std::complex<double> > rr = mean(r, 0);
  cx_rowvec drr = mean(dr, 0);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 1000 );
  for (uword i = 0; i < 1000; ++i)
    {
    REQUIRE( real((std::complex<double>) rr[i]) == Approx(real(drr[i])) );
    REQUIRE( imag((std::complex<double>) rr[i]) == Approx(imag(drr[i])) );
    }

  rr = mean(r, 1);
  drr = mean(dr, 1);

  REQUIRE( rr.n_rows == 1 );
  REQUIRE( rr.n_cols == 1 );
  REQUIRE( real((std::complex<double>) rr[0]) == Approx(real(drr[0])) );
  REQUIRE( imag((std::complex<double>) rr[0]) == Approx(imag(drr[0])) );

  ddcr = mean(r);
  dddr = mean(dr);

  REQUIRE( real(ddcr) == Approx(real(dddr)) );
  REQUIRE( imag(ddcr) == Approx(imag(dddr)) );
  }

TEST_CASE("fn_mean_sparse_alias_test")
  {
  sp_mat s;
  s.sprandu(70, 70, 0.3);
  mat d(s);

  s = mean(s);
  d = mean(d);

  REQUIRE( d.n_rows == s.n_rows );
  REQUIRE( d.n_cols == s.n_cols );
  for (uword i = 0; i < d.n_elem; ++i)
    {
    REQUIRE( d[i] == Approx((double) s[i]) );
    }

  s.sprandu(70, 70, 0.3);
  d = s;

  s = mean(s, 1);
  d = mean(d, 1);
  for (uword i = 0; i < d.n_elem; ++i)
    {
    REQUIRE( d[i] == Approx((double) s[i]) );
    }
  }


///////////////////////////////////////////////////////////////////////////////
//  Copyright 2018 John Maddock. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/multiprecision/cpp_int.hpp>

#include "eigen.hpp"

int main()
{
   using namespace boost::multiprecision;
   test_integer_type<int>();
   test_integer_type<boost::multiprecision::int256_t>();
   test_integer_type<boost::multiprecision::cpp_int>();
   return 0;
}


#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <boost/thread/thread.hpp>
#include <boost/range/combine.hpp>
#include <boost/foreach.hpp>
#include <chrono>
#include <cstdlib>
#include <ctime>
#include<omp.h>

#include "libscapi/include/comm/Comm.hpp"
#include "libscapi/include/primitives/DlogOpenSSL.hpp"
#include "libscapi/include/interactive_mid_protocols/CommitmentSchemePedersenTrapdoor.hpp"
#include "libscapi/include/mid_layer/ElGamalEnc.hpp"
#include "libscapi/include/infra/Common.hpp"

#include "bvsma/include/functions.hpp"
#include "bvsma/include/ZKProofs.hpp"
#include "bvsma/include/SchnorrSignature.hpp"
#include "bvsma/include/fileFunctions.hpp"

class Component;
class Signature;
class SchnorrSignature;

vector<biginteger> generateVectBigintFixed_parallel(biginteger mod, biginteger start, size_t len);
vector<biginteger> generateVectBigintRand_parallel(biginteger q, size_t len);
vector<shared_ptr<AsymmetricCiphertext>> generateVectElGamalCiphersFromVects_parallel(string configFile, string curve , shared_ptr<PublicKey> pubKey, vector<biginteger> vectM, vector<biginteger> vectR);
map<int, vector<shared_ptr<AsymmetricCiphertext>>> encryptColIndices_parallel(string configFile, string curve , shared_ptr<PublicKey> pubKey, vector<int> maxNFQ);
map<int, vector<shared_ptr<AsymmetricCiphertext>>> encryptRowsFromLLR_parallel(string dir, string configFile, string curve , shared_ptr<PublicKey> pubKey, vector<int> vectQuantizedSample);
map<int, vector<Component>> generatePartialTemplate_parallel(biginteger userId, map<int, vector<int>> permutation, map<int, vector<shared_ptr<AsymmetricCiphertext>>> colEncMap, map<int, vector<shared_ptr<AsymmetricCiphertext>>> scoreEncMap);
vector<shared_ptr<AsymmetricCiphertext>> extractColEncFromTemp_parallel(vector<Component> vectComp);
vector<shared_ptr<AsymmetricCiphertext>> extractScoreEncFromTemp_parallel(vector<Component> vectComp);
map<int, vector<Component>> generateTemplate_parallel(string configFile, string curve, shared_ptr<GroupElement> verKey, biginteger signKey, map<int, vector<Component>> partialTemplate);
bool verifyVectCompSignatures_parallel(string configFile, string curve, shared_ptr<GroupElement> verKey, vector<Component> vectComp);
vector<shared_ptr<AsymmetricCiphertext>> subtractTwoCipherVect_parallel(string configFile, string curve, shared_ptr<PublicKey> pubKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher1, vector<shared_ptr<AsymmetricCiphertext>> vectCipher2);
vector<shared_ptr<AsymmetricCiphertext>> multEvenCipherVect_parallel(string configFile, string curve, shared_ptr<PublicKey> pubKey, const vector<shared_ptr<AsymmetricCiphertext>>& vectCipher);
vector<shared_ptr<AsymmetricCiphertext>> multOddCipherVect_parallel(string configFile, string curve, shared_ptr<PublicKey> pubKey, const vector<shared_ptr<AsymmetricCiphertext>>& vectCipher);
shared_ptr<AsymmetricCiphertext> multiplyCiphersOfVect_parallel(string configFile, string curve, shared_ptr<PublicKey> pubKey, const vector<shared_ptr<AsymmetricCiphertext>>& vectCipher);
vector<shared_ptr<AsymmetricCiphertext>> subtractOneCipherFromCipherVect_parallel(string configFile, string curve, shared_ptr<PublicKey> pubKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher, shared_ptr<AsymmetricCiphertext> cipher);
bool finalDecryptionANDMatch_parallel(string configFile, string curve, shared_ptr<PublicKey> pubKey, shared_ptr<PrivateKey> privKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipherBlinded, vector<shared_ptr<GroupElement>> vectPartialDec);
vector<shared_ptr<GroupElement>> getVectC1_parallel(vector<shared_ptr<AsymmetricCiphertext>> vectCipher);
vector<shared_ptr<GroupElement>> getVectC2_parallel(vector<shared_ptr<AsymmetricCiphertext>> vectCipher);
vector<shared_ptr<AsymmetricCiphertext>> blindVectCipherElGamal_parallel(string configFile, string curve, vector<shared_ptr<AsymmetricCiphertext>> vectCipher, vector<biginteger> rBlindVect);
vector<shared_ptr<GroupElement>> partiallyDecryptVectCiphers_parallel(string configFile, string curve, shared_ptr<PublicKey> pubKey, shared_ptr<PrivateKey> privKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher);
vector<shared_ptr<AsymmetricCiphertext>> elgamalPartialDecryption_parallel(string configFile, string curve, shared_ptr<PublicKey> pubKey, shared_ptr<PrivateKey> privKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher);
vector<shared_ptr<AsymmetricCiphertext>> generateThresholdEncSet_parallel(int seed, string configFile, string curve, shared_ptr<PublicKey> pubKey, biginteger T, size_t len);

/*
* ZKs parallel [Prover]
*/

int zkPoKMultiANDPlainProver_parallel(shared_ptr<CommParty> prover, string configFile, string curve, shared_ptr<PublicKey> pubKey, vector<biginteger> vectM, vector<biginteger> vectR);

int niZKMultiANDDecZeroProver_parallel(shared_ptr<CommParty> prover, string configFile, string curve, shared_ptr<PublicKey> pubKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher, biginteger x);
int niZKMultiANDBlindedProver_parallel(shared_ptr<CommParty> prover, string configFile, string curve, shared_ptr<PublicKey> pubKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher, vector<biginteger> rBlindVect);
int niZKMultiANDPartialDecProver_parallel(shared_ptr<CommParty> prover, string configFile, string curve, shared_ptr<PublicKey> provThreshPubKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher, biginteger provPrivKey);

/*
* ZKs parallel [Verifier]
*/
bool zkPoKMultiANDPlainVerifier_parallel(shared_ptr<CommParty> verifier, string configFile, string curve, shared_ptr<PublicKey> pubKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher);

bool niZKMultiANDBlindedVerifier_parallel(shared_ptr<CommParty> verifier, string configFile, string curve, shared_ptr<PublicKey> pubKey,vector<shared_ptr<AsymmetricCiphertext>> vectCipher, vector<shared_ptr<AsymmetricCiphertext>> vectBlindedCipher);
bool niZKMultiANDPartialDecVerifier_parallel(shared_ptr<CommParty> verifier, string configFile, string curve, shared_ptr<PublicKey> provThreshPubKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher, vector<shared_ptr<GroupElement>> partialCipherVect);
bool niZKMultiANDDecZeroVerifier_parallel(shared_ptr<CommParty> verifier, string configFile, string curve, shared_ptr<PublicKey> pubKey, vector<shared_ptr<AsymmetricCiphertext>> vectCipher);