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

// Copyright (c) 2007-2012 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)

#ifndef BOOST_GEOMETRY_EXTENSIONS_GIS_GEOGRAPHIC_STRATEGIES_ANDOYER_HPP
#define BOOST_GEOMETRY_EXTENSIONS_GIS_GEOGRAPHIC_STRATEGIES_ANDOYER_HPP

#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/promote_floating_point.hpp>
#include <boost/geometry/util/math.hpp>

#include <boost/geometry/extensions/gis/geographic/detail/ellipsoid.hpp>

namespace boost { namespace geometry
{

namespace strategy { namespace distance
{

/*!
\brief Point-point distance approximation taking flattening into account
\ingroup distance
\tparam RadiusType Type of specified radius of the Earth
\tparam CalculationType \tparam_calculation
\author After Andoyer, 19xx, republished 1950, republished by Meeus, 1999
\note Although not so well-known, the approximation is very good: in all cases the results
are about the same as Vincenty. In my (Barend's) testcases the results didn't differ more than 6 m
\see http://nacc.upc.es/tierra/node16.html
\see http://sci.tech-archive.net/Archive/sci.geo.satellite-nav/2004-12/2724.html
\see http://home.att.net/~srschmitt/great_circle_route.html (implementation)
\see http://www.codeguru.com/Cpp/Cpp/algorithms/article.php/c5115 (implementation)
\see http://futureboy.homeip.net/frinksamp/navigation.frink (implementation)
\see http://www.voidware.com/earthdist.htm (implementation)
*/
template
<
    typename RadiusType,
    typename CalculationType = void
>
class andoyer
{
public :
    template <typename Point1, typename Point2>
    struct calculation_type
        : promote_floating_point
          <
              typename select_calculation_type
                  <
                      Point1,
                      Point2,
                      CalculationType
                  >::type
          >
    {};

    typedef RadiusType radius_type;

    inline andoyer()
        : m_ellipsoid()
    {}

    explicit inline andoyer(RadiusType f)
        : m_ellipsoid(f)
    {}

    explicit inline andoyer(geometry::detail::ellipsoid<RadiusType> const& e)
        : m_ellipsoid(e)
    {}

    template <typename Point1, typename Point2>
    inline typename calculation_type<Point1, Point2>::type
    apply(Point1 const& point1, Point2 const& point2) const
    {
        return calc<typename calculation_type<Point1, Point2>::type>
            (
                get_as_radian<0>(point1), get_as_radian<1>(point1),
                get_as_radian<0>(point2), get_as_radian<1>(point2)
            );
    }

    inline geometry::detail::ellipsoid<RadiusType> ellipsoid() const
    {
        return m_ellipsoid;
    }

    inline RadiusType radius() const
    {
        return m_ellipsoid.a();
    }

private :
    geometry::detail::ellipsoid<RadiusType> m_ellipsoid;

    template <typename CT, typename T>
    inline CT calc(T const& lon1,
                T const& lat1,
                T const& lon2,
                T const& lat2) const
    {
        CT const G = (lat1 - lat2) / 2.0;
        CT const lambda = (lon1 - lon2) / 2.0;

        if (geometry::math::equals(lambda, 0.0)
            && geometry::math::equals(G, 0.0))
        {
            return 0.0;
        }

        CT const F = (lat1 + lat2) / 2.0;

        CT const sinG2 = math::sqr(sin(G));
        CT const cosG2 = math::sqr(cos(G));
        CT const sinF2 = math::sqr(sin(F));
        CT const cosF2 = math::sqr(cos(F));
        CT const sinL2 = math::sqr(sin(lambda));
        CT const cosL2 = math::sqr(cos(lambda));

        CT const S = sinG2 * cosL2 + cosF2 * sinL2;
        CT const C = cosG2 * cosL2 + sinF2 * sinL2;

        CT const c0 = 0;
        CT const c1 = 1;
        CT const c2 = 2;
        CT const c3 = 3;

        if (geometry::math::equals(S, c0) || geometry::math::equals(C, c0))
        {
            return c0;
        }

        CT const omega = atan(sqrt(S / C));
        CT const r3 = c3 * sqrt(S * C) / omega; // not sure if this is r or greek nu
        CT const D = c2 * omega * m_ellipsoid.a();
        CT const H1 = (r3 - c1) / (c2 * C);
        CT const H2 = (r3 + c1) / (c2 * S);
        CT const f = m_ellipsoid.f();

        return D * (c1 + f * H1 * sinF2 * cosG2 - f * H2 * cosF2 * sinG2);
    }
};

#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{

template <typename RadiusType, typename CalculationType>
struct tag<andoyer<RadiusType, CalculationType> >
{
    typedef strategy_tag_distance_point_point type;
};

template <typename RadiusType, typename CalculationType, typename P1, typename P2>
struct return_type<andoyer<RadiusType, CalculationType>, P1, P2>
    : andoyer<RadiusType, CalculationType>::template calculation_type<P1, P2>
{};

template <typename RadiusType, typename CalculationType>
struct comparable_type<andoyer<RadiusType, CalculationType> >
{
    typedef andoyer<RadiusType, CalculationType> type;
};

template <typename RadiusType, typename CalculationType>
struct get_comparable<andoyer<RadiusType, CalculationType> >
{
    static inline andoyer<RadiusType, CalculationType> apply(andoyer<RadiusType, CalculationType> const& input)
    {
        return input;
    }
};

template <typename RadiusType, typename CalculationType, typename P1, typename P2>
struct result_from_distance<andoyer<RadiusType, CalculationType>, P1, P2>
{
    template <typename T>
    static inline typename return_type<andoyer<RadiusType, CalculationType>, P1, P2>::type
        apply(andoyer<RadiusType, CalculationType> const& , T const& value)
    {
        return value;
    }
};

template <typename Point1, typename Point2>
struct default_strategy<point_tag, Point1, Point2, geographic_tag, geographic_tag>
{
    typedef strategy::distance::andoyer<typename select_coordinate_type<Point1, Point2>::type> type;
};

} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS

}} // namespace strategy::distance

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_EXTENSIONS_GIS_GEOGRAPHIC_STRATEGIES_ANDOYER_HPP


#include <votca/ctp/ewald3d.h>
#include <votca/tools/globals.h>
#include <boost/format.hpp>
#include <algorithm>

using boost::format;

namespace votca { namespace ctp {

Ewald3D3D::~Ewald3D3D() { ; }

Ewald3D3D::Ewald3D3D(Topology *top, PolarTop *ptop, Property *opt, Logger *log)
  : Ewald3DnD(top, ptop, opt, log) {}

EWD::triple<> Ewald3D3D::ConvergeReciprocalSpaceSum(vector<PolarSeg*> &target) {

    const double int2eV = votca::tools::globals::conversion::int2eV;

    vector<PolarSeg*>::iterator sit;
    vector<APolarSite*> ::iterator pit;

    // CELLS OF THE RECIPROCAL LATTICE: SUM OVER ELLIPSOIDAL SHELLS
    // ... Shell-size increment is magnitude of largest reciprocal cell vector
    // ... Tschebyschow/Euclidean norm is used to group k-vectors into k-shells

    vector< vector<vec> > shell_ks;
    vector< vector<vec> >::iterator shellit;
    double shell_dk = (maxnorm(_A) > maxnorm(_B)) ?
        ((maxnorm(_A) > maxnorm(_C)) ? maxnorm(_A) : maxnorm(_C))
      : ((maxnorm(_B) > maxnorm(_C)) ? maxnorm(_B) : maxnorm(_C));
    // Determine all k-vectors within k-space cut-off
    vector< vec >::iterator kit;
    vector< vec > ks;
    for (int kx = -_NA_max; kx < _NA_max+1; ++kx) {
        for (int ky = -_NB_max; ky < _NB_max+1; ++ky) {
            for (int kz = -_NC_max; kz < _NC_max+1; ++kz) {
                if (kx == 0 && ky == 0 && kz == 0) continue;
                vec k = kx*_A + ky*_B + kz*_C;
                if (maxnorm(k) > _K_co) continue;
                ks.push_back(k);
            }
        }
    }
    // Sort according to magnitude
    std::sort(ks.begin(), ks.end(), _eucsort);
    // Group into shells
    int shell_idx = 0;
    kit = ks.begin();
    shell_ks.resize(int(_K_co/shell_dk+0.5)+1);
    double shell_k = shell_dk;
    while (shell_k <= _K_co) {
        for ( ; kit < ks.end(); ++kit) {
            vec k = *kit;
            if (maxnorm(k) <= shell_k) {
                // Add to current shell
                shell_ks[shell_idx].push_back(k);
            }
            else {
                // Open new shell
                shell_k += shell_dk;
                shell_idx += 1;
                shell_ks[shell_idx].push_back(k);
                break;
            }
        }
        // All k-vectors consumed?
        if (kit == ks.end()) break;
    }
//    for (int i = 0; i < shell_ks.size(); ++i) {
//        std::ofstream ofs;
//        string outfile = (format("shell_%1$d.out") % (i+1)).str();
//        ofs.open(outfile.c_str(), ofstream::out);
//        for (kit = shell_ks[i].begin(); kit < shell_ks[i].end(); ++kit) {
//            ofs << (*kit).getX() << " " << (*kit).getY() << " " << (*kit).getZ() << endl;
//        }
//        ofs.close();
//    }

    // K=K TERM
    CTP_LOG(logDEBUG,*_log) << flush;
    double EKK_fgC_bgP = 0.0;
    unsigned int N_EKK_memory = (unsigned int)(0.5*(_NA_max+_NB_max)+0.5);
    int N_K_proc = 0;
    int N_shells_proc = 0;
    vector< double > dEKKs;
    _converged_K = false;

    double re_E = 0.0;
    double im_E = 0.0;

    for (shellit = shell_ks.begin(); shellit < shell_ks.end(); ++shellit, ++N_shells_proc) {

        for (kit = (*shellit).begin(); kit < (*shellit).end(); ++kit, ++N_K_proc) {
            vec k = *kit;

            // K-DEPENDENT FACTOR
            double K = abs(k);
            double expkk_k = 4*M_PI*exp(-K*K/(4*_alpha*_alpha)) / (K*K);

            CTP_LOG(logDEBUG,*_log)
                << (format("k[%5$d] = %1$+1.3f %2$+1.3f %3$+1.3f   |K| = %4$+1.3f 1/nm")
                % (k.getX()) % (k.getY()) % (k.getZ()) % K % (N_shells_proc+1));

            // STRUCTURE FACTORS
            // Calculate structure factor S(k) for FGC
            double qcos_fgC = 0.0;
            double qsin_fgC = 0.0;
            for (sit = target.begin(); sit < target.end(); ++sit) {
                for (pit = (*sit)->begin(); pit < (*sit)->end(); ++pit) {
                    qcos_fgC += (*pit)->Q00 * cos(k * (*pit)->getPos());
                    qsin_fgC += (*pit)->Q00 * sin(k * (*pit)->getPos());
                }
            }
            // Calculate structure factor S(-k) for BGP
            double qcos_bgP = 0.0;
            double qsin_bgP = 0.0;
            for (sit = _bg_P.begin(); sit < _bg_P.end(); ++sit) {
                for (pit = (*sit)->begin(); pit < (*sit)->end(); ++pit) {
                    qcos_bgP += (*pit)->Q00 * cos(-k * (*pit)->getPos());
                    qsin_bgP += (*pit)->Q00 * sin(-k * (*pit)->getPos());
                }
            }
            // Structure-factor product
            double re_s1s2 = qcos_fgC*qcos_bgP - qsin_fgC*qsin_bgP;
            double im_s1s2 = qsin_fgC*qcos_bgP + qcos_fgC*qsin_bgP;

            // REAL & IMAGINARY ENERGY
            double re_dE = expkk_k * re_s1s2;
            double im_dE = expkk_k * im_s1s2;
            re_E += re_dE;
            im_E += im_dE;

            CTP_LOG(logDEBUG,*_log)
                << (format("    Re(dE) = %1$+1.7f")
                % (re_dE/_LxLyLz*int2eV));

            CTP_LOG(logDEBUG,*_log)
                << (format("    Re(E) = %1$+1.7f Im(E) = %2$+1.7f")
                % (re_E/_LxLyLz*int2eV) % (im_E/_LxLyLz*int2eV));

            // CONVERGED?
            double dEKK = sqrt(re_dE*re_dE + im_dE*im_dE);
            double dEKK_rms = 0.0;
            if (dEKKs.size() < N_EKK_memory) {
                dEKKs.resize(N_EKK_memory,dEKK);
            }
            else {
                dEKKs[N_K_proc % N_EKK_memory] = dEKK;
            }
            for (unsigned int i = 0; i < dEKKs.size(); ++i) {
                dEKK_rms += dEKKs[i]*dEKKs[i];
            }
            dEKK_rms /= dEKKs.size();
            dEKK_rms = sqrt(dEKK_rms);

            CTP_LOG(logDEBUG,*_log)
                << (format("   RMS(%2$d) = %1$+1.7f")
                % (dEKK_rms/_LxLyLz*int2eV) % N_EKK_memory) << flush;

            if (dEKK_rms/_LxLyLz*int2eV <= _crit_dE && N_K_proc > 2 && N_shells_proc > 0) {
                _converged_K = true;
                CTP_LOG(logDEBUG,*_log)
                    << (format(":::: Converged to precision as of |K| = %1$+1.3f 1/nm")
                    % K ) << flush;
                break;
            }
        } // Sum over k's in k-shell
        if (_converged_K) break;
    } // Sum over k-shells

    EKK_fgC_bgP = re_E/_LxLyLz;
    return EWD::triple<>(EKK_fgC_bgP,0,0);
}

EWD::triple<> Ewald3D3D::CalculateShapeCorrection(vector<PolarSeg*> &target) {

    vector<PolarSeg*>::iterator sit1;
    vector<APolarSite*> ::iterator pit1;
    vector<PolarSeg*>::iterator sit2;
    vector<APolarSite*> ::iterator pit2;

    double EJ = 0.0;

    if (_shape == "xyslab") {
        // DIRECT CALCULATION VIA DOUBLE LOOP
        // TODO The double-loop can be avoided, but direct summation as below
        //      appears to be more stable from a numerical point of view
        for (sit1 = target.begin(); sit1 < target.end(); ++sit1) {
           for (sit2 = _bg_P.begin(); sit2 < _bg_P.end(); ++sit2) {
              for (pit1 = (*sit1)->begin(); pit1 < (*sit1)->end(); ++pit1) {
                 for (pit2 = (*sit2)->begin(); pit2 < (*sit2)->end(); ++pit2) {
                    double za = (*pit1)->getPos().getZ();
                    double zb = (*pit2)->getPos().getZ();
                    EJ += (za-zb)*(za-zb) * (*pit1)->getQ00()*(*pit2)->getQ00();
                 }
              }
           }
        }

        //    // DECOMPOSITION INTO CHARGE-DENSITY MULTIPOLE MOMENTS
        //    vec DA = vec(0,0,0);
        //    vec DA = vec(0,0,0);
        //    double QA = 0.0;
        //    double DZZBG = 0.0;
        //    for (sit1 = target.begin(); sit1 < target.end(); ++sit1) {
        //        for (pit1 = (*sit1)->begin(); pit1 < (*sit1)->end(); ++pit1) {
        //            DA += (*pit1)->getQ00() * (*pit1)->getPos();
        //            QA += (*pit1)->getQ00();
        //        }
        //    }
        //    for (sit1 = _bg_P.begin(); sit1 < _bg_P.end(); ++sit1) {
        //        for (pit1 = (*sit1)->begin(); pit1 < (*sit1)->end(); ++pit1) {
        //            double zb = (*pit1)->getPos().getZ();
        //            DB += (*pit1)->getQ00() * (*pit1)->getPos();
        //            DZZB += (*pit1)->getQ00() * zb*zb;
        //        }
        //    }
        //    EJ = QA*DZZB - 2*(DA.getZ())*(DB.getZ());

        EJ *= - 2*M_PI/_LxLyLz;
    }
    else {
        CTP_LOG(logERROR,*_log)
            << (format("Shape %1$s not implemented. Setting EJ = 0.0 ...")
            % _shape) << flush;
        EJ = 0.0;
    }

    return EWD::triple<>(EJ,0,0);
}

double Ewald3D3D::CalculateSq2(vec &k) {
    vector<PolarSeg*>::iterator sit;
    vector<APolarSite*> ::iterator pit;
    double cs = 0.0;
    double ss = 0.0;
    for (sit = _bg_P.begin(); sit < _bg_P.end(); ++sit) {
        for (pit = (*sit)->begin(); pit < (*sit)->end(); ++pit) {
            cs += (*pit)->Q00 * cos(k * (*pit)->getPos());
            ss += (*pit)->Q00 * sin(k * (*pit)->getPos());
        }
    }
    return cs*cs + ss*ss;
}

}}


#define DEBUG 1
/**
 * File    : D.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/1/18 21:28:34
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll lcm(ll x, ll y) { return x / gcd(x, y) * y; }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
constexpr int infty{100000};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- SegTree -----

template <typename T>
class SegTree
{ // 0-indexed, [0, N).
private:
  int N;
  vector<T> dat;
  T unit;  // モノイドの単位元
  T(*func) // モノイドの演算
  (T, T);
  T(*_update) // update で値をどうするか書く
  (T, T);

public:
  SegTree() {}

  SegTree(int n, T unit, T (*func)(T, T), T (*_update)(T, T)) : N{1}, unit{unit}, func{func}, _update{_update}
  {
    while (N < n)
    {
      N *= 2;
    }
    dat = vector<T>(2 * N - 1, unit);
  }

  void update(int k, T a)
  {
    k += N - 1;
    dat[k] = _update(dat[k], a);
    while (k > 0)
    {
      k = (k - 1) / 2;
      dat[k] = func(dat[k * 2 + 1], dat[k * 2 + 2]);
    }
  }

private:
  T find(int a, int b, int k, int l, int r)
  {
    if (r <= a || b <= l)
    {
      return unit;
    }
    if (a <= l && r <= b)
    {
      return dat[k];
    }
    T vl = find(a, b, k * 2 + 1, l, (l + r) / 2);
    T vr = find(a, b, k * 2 + 2, (l + r) / 2, r);
    return func(vl, vr);
  }

public:
  T find(int a, int b)
  { // [a, b) の find をする。
    return find(a, b, 0, 0, N);
  }
};

// ----- frequently used examples -----

// for +
auto func2 = [](auto x, auto y) {
  return x + y;
};
auto _update2 = [](auto x, auto y) {
  return y;
};
constexpr ll unit2{0LL};

// ----- main() -----

struct Card
{
  int A, B;
};

using Info = tuple<int, int>;

int main()
{
  int N;
  cin >> N;
  vector<Card> V(N);
  for (auto i = 0; i < N; ++i)
  {
    cin >> V[i].A;
  }
  for (auto i = 0; i < N; ++i)
  {
    cin >> V[i].B;
  }
  for (auto i = 1; i < N; i += 2)
  {
    swap(V[i].A, V[i].B);
  }
  if (N == 1)
  {
    cout << 0 << endl;
    return 0;
  }
  int ans{infty};
  for (auto k = 0; k < (1 << N); ++k)
  {
    int cnt{0};
    for (auto i = 0; i < N; ++i)
    {
      cnt += (k >> i) & 1;
    }
    if (cnt == N - N / 2)
    {
      vector<Info> X, Y;
      for (auto i = 0; i < N; ++i)
      {
        if ((k >> i) & 1)
        {
          X.push_back(Info(V[i].A, i));
        }
        else
        {
          Y.push_back(Info(V[i].B, i));
        }
      }
      sort(X.begin(), X.end());
      sort(Y.begin(), Y.end());
      vector<Info> Z;
      int x = 0, y = 0;
      while (x < static_cast<int>(X.size()))
      {
        Z.push_back(X[x]);
        ++x;
        if (y < static_cast<int>(Y.size()))
        {
          Z.push_back(Y[y]);
          ++y;
        }
      }
      assert(static_cast<int>(Z.size()) == N);
      bool ok{true};
      for (auto i = 0; i < N - 1; ++i)
      {
        if (get<0>(Z[i]) > get<0>(Z[i + 1]))
        {
          ok = false;
          break;
        }
      }
      if (!ok)
      {
        continue;
      }
#if DEBUG == 1
      for (auto i = 0; i < N; ++i)
      {
        cerr << "Z[" << i << "] = (" << get<0>(Z[i]) << ", " << get<1>(Z[i]) << ")" << endl;
      }
#endif
      SegTree<ll> tree{N, unit2, func2, _update2};
      int tmp{0};
      for (auto i = 0; i < N; ++i)
      {
        int v{get<1>(Z[i])};
        tmp += tree.find(v, N);
        tree.update(v, 1);
      }
      ch_min(ans, tmp);
    }
  }
  if (ans == infty)
  {
    cout << -1 << endl;
  }
  else
  {
    cout << ans << endl;
  }
}


/* boost random/faure.hpp header file
 *
 * Copyright Justinas Vygintas Daugmaudis 2010-2018
 * 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)
 */

#ifndef BOOST_RANDOM_FAURE_HPP
#define BOOST_RANDOM_FAURE_HPP

#include <boost/random/detail/qrng_base.hpp>

#include <cmath>
#include <vector>
#include <algorithm>

#include <boost/assert.hpp>

namespace boost {
namespace random {

/** @cond */
namespace detail {

namespace qrng_tables {

// There is no particular reason why 187 first primes were chosen
// to be put into this table. The only reason was, perhaps, that
// the number of dimensions for Faure generator would be around
// the same order of magnitude as the number of dimensions supported
// by the Sobol qrng.
struct primes
{
  typedef unsigned short value_type;

  BOOST_STATIC_CONSTANT(int, number_of_primes = 187);

  // A function that returns lower bound prime for a given n
  static value_type lower_bound(std::size_t n)
  {
    static const value_type prim_a[number_of_primes] = {
      2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
      59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
      127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181,
      191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251,
      257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
      331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
      401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
      467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557,
      563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619,
      631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
      709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787,
      797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
      877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953,
      967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031,
      1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093,
      1097, 1103, 1109, 1117 };

    qrng_detail::dimension_assert("Faure", n, prim_a[number_of_primes - 1]);

    return *std::lower_bound(prim_a, prim_a + number_of_primes, n);
  }
};

} // namespace qrng_tables
} // namespace detail

namespace qrng_detail {
namespace fr {

// Returns the integer part of the logarithm base Base of arg.
// In erroneous situations, e.g., integer_log(base, 0) the function
// returns 0 and does not report the error. This is the intended
// behavior.
template <typename T>
inline T integer_log(T base, T arg)
{
  T ilog = T();
  while (base <= arg)
  {
    arg /= base; ++ilog;
  }
  return ilog;
}

// Perform exponentiation by squaring (potential for code reuse in multiprecision::powm)
template <typename T>
inline T integer_pow(T base, T e)
{
  T result = static_cast<T>(1);
  while (e)
  {
    if (e & static_cast<T>(1))
      result *= base;
    e >>= 1;
    base *= base;
  }
  return result;
}

} // namespace fr

// Computes a table of binomial coefficients modulo qs.
template<typename RealType, typename SeqSizeT, typename PrimeTable>
struct binomial_coefficients
{
  typedef RealType value_type;
  typedef SeqSizeT size_type;

  // Binomial values modulo qs_base will never be bigger than qs_base.
  // We can choose an appropriate integer type to hold modulo values and
  // shave off memory footprint.
  typedef typename PrimeTable::value_type packed_uint_t;

  // default copy c-tor is fine

  explicit binomial_coefficients(std::size_t dimension)
  {
    resize(dimension);
  }

  void resize(std::size_t dimension)
  {
    qs_base = PrimeTable::lower_bound(dimension);

    // Throw away previously computed coefficients.
    // This will trigger recomputation on next update
    coeff.clear();
  }

  template <typename Iterator>
  void update(size_type seq, Iterator first, Iterator last)
  {
    if (first != last)
    {
      const size_type ilog = fr::integer_log(static_cast<size_type>(qs_base), seq);
      const size_type hisum = ilog + 1;
      if (coeff.size() != size_hint(hisum)) {
        ytemp.resize(static_cast<std::size_t>(hisum)); // cast safe because log is small
        compute_coefficients(hisum);
        qs_pow = fr::integer_pow(static_cast<size_type>(qs_base), ilog);
      }

      *first = compute_recip(seq, ytemp.rbegin());

      // Find other components using the Faure method.
      ++first;
      for ( ; first != last; ++first)
      {
        *first = RealType();
        RealType r = static_cast<RealType>(1);

        for (size_type i = 0; i != hisum; ++i)
        {
          RealType ztemp = ytemp[static_cast<std::size_t>(i)] * upper_element(i, i, hisum);
          for (size_type j = i + 1; j != hisum; ++j)
            ztemp += ytemp[static_cast<std::size_t>(j)] * upper_element(i, j, hisum);

          // Sum ( J <= I <= HISUM ) ( old ytemp(i) * binom(i,j) ) mod QS.
          ytemp[static_cast<std::size_t>(i)] = std::fmod(ztemp, static_cast<RealType>(qs_base));
          r *= static_cast<RealType>(qs_base);
          *first += ytemp[static_cast<std::size_t>(i)] / r;
        }
      }
    }
  }

private:
  inline static size_type size_hint(size_type n)
  {
    return n * (n + 1) / 2;
  }

  packed_uint_t& upper_element(size_type i, size_type j, size_type dim)
  {
    BOOST_ASSERT( i < dim );
    BOOST_ASSERT( j < dim );
    BOOST_ASSERT( i <= j );
    return coeff[static_cast<std::size_t>((i * (2 * dim - i + 1)) / 2 + j - i)];
  }

  template<typename Iterator>
  RealType compute_recip(size_type seq, Iterator out) const
  {
    // Here we do
    //   Sum ( 0 <= J <= HISUM ) YTEMP(J) * QS**J
    //   Sum ( 0 <= J <= HISUM ) YTEMP(J) / QS**(J+1)
    // in one go
    RealType r = RealType();
    size_type m, k = qs_pow;
    for( ; k != 0; ++out, seq = m, k /= qs_base )
    {
      m  = seq % k;
      RealType v  = static_cast<RealType>((seq - m) / k); // RealType <- size type
      r += v;
      r /= static_cast<RealType>(qs_base);
      *out = v; // saves double dereference
    }
    return r;
  }

  void compute_coefficients(const size_type n)
  {
    // Resize and initialize to zero
    coeff.resize(static_cast<std::size_t>(size_hint(n)));
    std::fill(coeff.begin(), coeff.end(), packed_uint_t());

    // The first row and the diagonal is assigned to 1
    upper_element(0, 0, n) = 1;
    for (size_type i = 1; i < n; ++i)
    {
      upper_element(0, i, n) = 1;
      upper_element(i, i, n) = 1;
    }

    // Computes binomial coefficients MOD qs_base
    for (size_type i = 1; i < n; ++i)
    {
      for (size_type j = i + 1; j < n; ++j)
      {
        upper_element(i, j, n) = ( upper_element(i, j-1, n) +
                                   upper_element(i-1, j-1, n) ) % qs_base;
      }
    }
  }

private:
  packed_uint_t qs_base;

  // here we cache precomputed data; note that binomial coefficients have
  // to be recomputed iff the integer part of the logarithm of seq changes,
  // which happens relatively rarely.
  std::vector<packed_uint_t> coeff; // packed upper (!) triangular matrix
  std::vector<RealType> ytemp;
  size_type qs_pow;
};

} // namespace qrng_detail

typedef detail::qrng_tables::primes default_faure_prime_table;

/** @endcond */

//!Instantiations of class template faure_engine model a \quasi_random_number_generator.
//!The faure_engine uses the algorithm described in
//! \blockquote
//!Henri Faure,
//!Discrepance de suites associees a un systeme de numeration (en dimension s),
//!Acta Arithmetica,
//!Volume 41, 1982, pages 337-351.
//! \endblockquote
//
//! \blockquote
//!Bennett Fox,
//!Algorithm 647:
//!Implementation and Relative Efficiency of Quasirandom
//!Sequence Generators,
//!ACM Transactions on Mathematical Software,
//!Volume 12, Number 4, December 1986, pages 362-376.
//! \endblockquote
//!
//!In the following documentation @c X denotes the concrete class of the template
//!faure_engine returning objects of type @c RealType, u and v are the values of @c X.
//!
//!Some member functions may throw exceptions of type @c std::bad_alloc.
template<typename RealType, typename SeqSizeT, typename PrimeTable = default_faure_prime_table>
class faure_engine
  : public qrng_detail::qrng_base<
      faure_engine<RealType, SeqSizeT, PrimeTable>
    , qrng_detail::binomial_coefficients<RealType, SeqSizeT, PrimeTable>
    , SeqSizeT
    >
{
  typedef faure_engine<RealType, SeqSizeT, PrimeTable> self_t;

  typedef qrng_detail::binomial_coefficients<RealType, SeqSizeT, PrimeTable> lattice_t;
  typedef qrng_detail::qrng_base<self_t, lattice_t, SeqSizeT> base_t;

  friend class qrng_detail::qrng_base<self_t, lattice_t, SeqSizeT>;

public:
  typedef RealType result_type;

  /** @copydoc boost::random::niederreiter_base2_engine::min() */
  static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
  { return static_cast<result_type>(0); }

  /** @copydoc boost::random::niederreiter_base2_engine::max() */
  static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
  { return static_cast<result_type>(1); }

  //!Effects: Constructs the `s`-dimensional default Faure quasi-random number generator.
  //!
  //!Throws: bad_alloc, invalid_argument.
  explicit faure_engine(std::size_t s)
    : base_t(s) // initialize the binomial table here
  {}

  /** @copydetails boost::random::niederreiter_base2_engine::seed(UIntType)
   * Throws: bad_alloc.
   */
  void seed(SeqSizeT init = 0)
  {
    compute_seq(init);
    base_t::reset_seq(init);
  }

#ifdef BOOST_RANDOM_DOXYGEN
  //=========================Doxygen needs this!==============================

  /** @copydoc boost::random::niederreiter_base2_engine::dimension() */
  std::size_t dimension() const { return base_t::dimension(); }

  /** @copydoc boost::random::niederreiter_base2_engine::operator()() */
  result_type operator()()
  {
    return base_t::operator()();
  }

  /** @copydoc boost::random::niederreiter_base2_engine::discard(boost::uintmax_t)
   * Throws: bad_alloc.
   */
  void discard(boost::uintmax_t z)
  {
    base_t::discard(z);
  }

  /** Returns true if the two generators will produce identical sequences of outputs. */
  BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(faure_engine, x, y)
  { return static_cast<const base_t&>(x) == y; }

  /** Returns true if the two generators will produce different sequences of outputs. */
  BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(faure_engine)

  /** Writes the textual representation of the generator to a @c std::ostream. */
  BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, faure_engine, s)
  { return os << static_cast<const base_t&>(s); }

  /** Reads the textual representation of the generator from a @c std::istream. */
  BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, faure_engine, s)
  { return is >> static_cast<base_t&>(s); }

#endif // BOOST_RANDOM_DOXYGEN

private:
/** @cond hide_private_members */
  void compute_seq(SeqSizeT seq)
  {
    qrng_detail::check_seed_sign(seq);
    this->lattice.update(seq, this->state_begin(), this->state_end());
  }
/** @endcond */
};

/**
 * @attention This specialization of \faure_engine supports up to 1117 dimensions.
 *
 * However, it is possible to provide your own prime table to \faure_engine should the default one be insufficient.
 */
typedef faure_engine<double, boost::uint_least64_t, default_faure_prime_table> faure;

} // namespace random

} // namespace boost

#endif // BOOST_RANDOM_FAURE_HPP


#include "generalizedassignmentsolver/algorithms/lagrelax_lbfgs.hpp"

#include "knapsacksolver/algorithms/minknap.hpp"
#include "knapsacksolver/algorithms/bellman.hpp"

#include <dlib/optimization.h>

#include <algorithm>
#include <iomanip>
#include <limits>

using namespace generalizedassignmentsolver;
using namespace dlib;

typedef matrix<double,0,1> column_vector;

////////////////////////////////////////////////////////////////////////////////
/////////////////////////// lagrelax_assignment_lbfgs //////////////////////////
////////////////////////////////////////////////////////////////////////////////

LagRelaxAssignmentLbfgsOutput& LagRelaxAssignmentLbfgsOutput::algorithm_end(Info& info)
{
    //FFOT_PUT(info, "Algorithm", "Iterations", it);
    Output::algorithm_end(info);
    //FFOT_VER(info, "Iterations: " << it << std::endl);
    return *this;
}

class LagRelaxAssignmentLbfgsFunction
{

public:

    LagRelaxAssignmentLbfgsFunction(
            const Instance& instance,
            LagRelaxAssignmentLbfgsOptionalParameters& p,
            ItemIdx number_of_unfixed_items,
            const std::vector<ItemIdx>& item_indices):
        instance_(instance), p_(p), item_indices_(item_indices), grad_(number_of_unfixed_items)
    {
        ItemIdx n = instance_.number_of_items();
        AgentIdx m = instance_.number_of_agents();

        // Compute knapsack capacities
        kp_capacities_.resize(m);
        for (AgentIdx i = 0; i < m; ++i) {
            kp_capacities_[i] = instance.capacity(i);
            for (ItemIdx j = 0; j < n; ++j) {
                if (p.fixed_alt != NULL && (*p.fixed_alt)[j][i] == 1)
                    kp_capacities_[i] -= instance.weight(j, i);
            }
            if (kp_capacities_[i] < 0)
                std::cout << "ERROR i " << i << " c " << kp_capacities_[i] << std::endl;
        }

        // Initialize kp_indices_
        kp_indices_.resize(n);
    }

    virtual ~LagRelaxAssignmentLbfgsFunction() { }

    double f(const column_vector& x);

    const column_vector der(const column_vector& x) const { (void)x; return grad_; }

private:

    const Instance& instance_;
    LagRelaxAssignmentLbfgsOptionalParameters& p_;
    /** item_indices_[j] is the index of item j in mu and grad_. */
    const std::vector<ItemIdx>& item_indices_;

    column_vector grad_;

    std::vector<knapsacksolver::Weight> kp_capacities_;
    /** kp_indices_[j] is the index of item j in the current KP. */
    std::vector<knapsacksolver::ItemIdx> kp_indices_;

};

double LagRelaxAssignmentLbfgsFunction::f(const column_vector& mu)
{
    ItemIdx n = instance_.number_of_items();
    AgentIdx m = instance_.number_of_agents();

    // Initialize bound and gradient;
    double l = 0;
    for (ItemIdx j = 0; j < n; ++j)
        if (item_indices_[j] >= 0)
            l += mu(item_indices_[j]);
    std::fill(grad_.begin(), grad_.end(), 1);

    Weight mult = 10000;
    for (AgentIdx i = 0; i < m; ++i) {
        // Create knapsack instance
        knapsacksolver::Instance kp_instance;
        kp_instance.set_capacity(kp_capacities_[i]);
        knapsacksolver::ItemIdx j_kp = 0;
        for (ItemIdx j = 0; j < n; ++j) {
            if ((p_.fixed_alt != NULL && (*p_.fixed_alt)[j][i] >= 0)
                    || instance_.weight(j, i) > kp_capacities_[i]) {
                kp_indices_[j] = -1;
                continue;
            }
            knapsacksolver::Profit profit = std::ceil(mult * mu(j) - mult * instance_.cost(j, i));
            if (profit <= 0) {
                kp_indices_[j] = -1;
                continue;
            }
            kp_instance.add_item(instance_.weight(j, i), profit);
            kp_indices_[j] = j_kp;
            j_kp++;
        }

        // Solve knapsack instance
        //auto kp_output = knapsacksolver::bellman_array_all(kp_instance, Info().set_verbose(false));
        auto kp_output = knapsacksolver::minknap(kp_instance);
        //std::cout << "i " << i << " opt " << kp_output.solution.profit() << std::endl;

        // Update bound and gradient
        for (ItemIdx j = 0; j < n; ++j) {
            if (kp_indices_[j] >= 0 && kp_output.solution.contains_idx(kp_indices_[j])) {
                grad_(item_indices_[j])--;
                l += instance_.cost(j, i) - mu(item_indices_[j]);
            }
        }
    }

    return l;
}

LagRelaxAssignmentLbfgsOutput generalizedassignmentsolver::lagrelax_assignment_lbfgs(
        const Instance& instance,
        LagRelaxAssignmentLbfgsOptionalParameters parameters)
{
    init_display(instance, parameters.info);
    FFOT_VER(parameters.info,
               "Algorithm" << std::endl
            << "---------" << std::endl
            << "Lagrangian Relaxation - Assignment Constraints (LBFGS)" << std::endl
            << std::endl);

    LagRelaxAssignmentLbfgsOutput output(instance, parameters.info);

    ItemIdx n = instance.number_of_items();
    AgentIdx m = instance.number_of_agents();

    // Compute c0, item_indices and number_of_unfixed_items
    ItemIdx item_idx = 0;
    Cost c0 = 0;
    std::vector<ItemIdx> item_indices(n, -2);
    for (ItemIdx j = 0; j < n; ++j) {
        for (AgentIdx i = 0; i < m; ++i) {
            if (parameters.fixed_alt != NULL && (*parameters.fixed_alt)[j][i] == 1) {
                c0 += instance.cost(j, i);
                item_indices[j] = -1;
                break;
            }
        }
        if (item_indices[j] == -2) {
            item_indices[j] = item_idx;
            item_idx++;
        }
    }
    ItemIdx number_of_unfixed_items = item_idx;

    // Initialize multipliers
    column_vector mu(number_of_unfixed_items);
    if (parameters.initial_multipliers != NULL) {
        for (ItemIdx j = 0; j < n; ++j)
            if (item_indices[j] >= 0)
                mu(item_indices[j]) = (*parameters.initial_multipliers)[j];
    } else {
        for (ItemIdx j = 0; j < n; ++j)
            mu(j) = 0;
    }

    // Solve
    LagRelaxAssignmentLbfgsFunction func(instance, parameters, number_of_unfixed_items, item_indices);
    auto f   = [&func](const column_vector& x) { return func.f(x); };
    auto def = [&func](const column_vector& x) { return func.der(x); };
    auto stop_strategy = objective_delta_stop_strategy(0.0001);
    //auto stop_strategy = gradient_norm_stop_strategy().be_verbose(),
    double res = find_max(
            lbfgs_search_strategy(256),
            stop_strategy,
            f,
            def,
            mu,
            std::numeric_limits<double>::max());

    // Compute output parameters
    Cost lb = c0 + std::ceil(res - FFOT_TOL);
    output.update_lower_bound(lb, std::stringstream(""), parameters.info);
    output.multipliers.resize(n);
    for (ItemIdx j = 0; j < n; ++j)
        if (item_indices[j] >= 0)
            output.multipliers[j] = mu(item_indices[j]);

    return output.algorithm_end(parameters.info);
}

////////////////////////////////////////////////////////////////////////////////
//////////////////////////// lagrelax_knapsack_lbfgs ///////////////////////////
////////////////////////////////////////////////////////////////////////////////

LagRelaxKnapsackLbfgsOutput& LagRelaxKnapsackLbfgsOutput::algorithm_end(Info& info)
{
    //FFOT_PUT(info, "Algorithm", "Iterations", it);
    Output::algorithm_end(info);
    //FFOT_VER(info, "Iterations: " << it << std::endl);
    return *this;
}

class LagRelaxKnapsackLbfgsFunction
{

public:

    LagRelaxKnapsackLbfgsFunction(const Instance& instance):
        instance_(instance),
        x_(instance.number_of_items()),
        grad_(instance.number_of_agents())
    {  }
    virtual ~LagRelaxKnapsackLbfgsFunction() { };

    double f(const column_vector& x);

    const column_vector der(const column_vector& x) const { (void)x; return grad_; }

    AgentIdx agent(ItemIdx j) const { return x_(j); }

private:

    const Instance& instance_;
    column_vector x_;
    column_vector grad_;

};

double LagRelaxKnapsackLbfgsFunction::f(const column_vector& mu)
{
    ItemIdx n = instance_.number_of_items();
    AgentIdx m = instance_.number_of_agents();

    // Initialize bound and gradient
    double l = 0;
    for (AgentIdx i = 0; i < m; ++i) {
        l += mu(i) * instance_.capacity(i);
        grad_(i) = instance_.capacity(i);
    }

    for (ItemIdx j = 0; j < n; ++j) {
        // Solve the trivial Generalized Upper Bound Problem
        AgentIdx i_best = -1;
        double rc_best = -1;
        for (AgentIdx i = 0; i < m; ++i) {
            double rc = instance_.cost(j, i) - mu(i) * instance_.weight(j, i);
            if (i_best == -1
                    || rc_best > rc
                    // If the minimum reduced cost of a job is reached for
                    // several agents, schedule the job on the agent with the
                    // most available remaining capacity.
                    // Without this condition, the relaxation fails to get the
                    // optimal bound (the one from the linear relaxation) for
                    // some instances.
                    || (rc_best == rc && grad_(i) > grad_(i_best))) {
                i_best = i;
                rc_best = rc;
            }
        }

        // Update bound and gradient
        grad_(i_best) -= instance_.weight(j, i_best);
        x_(j) = i_best;
        l += rc_best;
    }

    return l;
}

LagRelaxKnapsackLbfgsOutput generalizedassignmentsolver::lagrelax_knapsack_lbfgs(
        const Instance& instance,
        Info info)
{
    init_display(instance, info);
    FFOT_VER(info,
               "Algorithm" << std::endl
            << "---------" << std::endl
            << "Lagrangian Relaxation - Knapsack Constraints (LBFGS)" << std::endl
            << std::endl);

    LagRelaxKnapsackLbfgsOutput output(instance, info);

    AgentIdx m = instance.number_of_agents();
    ItemIdx n = instance.number_of_items();

    // Initialize multipliers
    column_vector mu(m);
    column_vector mu_lower(m);
    column_vector mu_upper(m);
    for (AgentIdx i = 0; i < m; ++i) {
        //mu_lower(i) = 0;
        //mu_upper(i) = std::numeric_limits<double>::max();
        mu(i) = 0;
        mu_lower(i) = -std::numeric_limits<double>::max();
        mu_upper(i) = 0;
    }

    // Solve
    LagRelaxKnapsackLbfgsFunction func(instance);
    auto f   = [&func](const column_vector& x) { return func.f(x); };
    auto def = [&func](const column_vector& x) { return func.der(x); };
    auto stop_strategy = objective_delta_stop_strategy();
    //auto stop_strategy = gradient_norm_stop_strategy();
    double res = find_max_box_constrained(
            lbfgs_search_strategy(256),
            stop_strategy,
            f,
            def,
            mu,
            mu_lower,
            mu_upper);

    // Compute output parameters
    Cost lb = std::ceil(res - FFOT_TOL);
    output.update_lower_bound(lb, std::stringstream(""), info);
    output.multipliers.resize(m);
    for (AgentIdx i = 0; i < m; ++i)
        output.multipliers[i] = mu(i);
    func.f(mu);
    for (ItemIdx j = 0; j < n; ++j) {
        output.x.push_back(std::vector<double>(instance.number_of_agents(), 0));
        output.x[j][func.agent(j)] = 1;
    }

    return output.algorithm_end(info);
}


#ifndef UKF_H
#define UKF_H

#include <functional>
#include <string>
#include <vector>

#include <Eigen/Dense>

class UKF {

    public:

        // Available sigma point types
        enum sig_type {JU, CUT4, CUT6, CUT8};

        // Dynamical model type
        typedef std::function <Eigen::VectorXd (double, double,
            const Eigen::VectorXd&, const Eigen::VectorXd&)> dyn_model;

        // Measurement model type
        typedef std::function <Eigen::VectorXd (double,
            const Eigen::VectorXd&)> meas_model;

        // Dimensions of state, measurement, & process noise
        const int nx, nz, nw;

        // Indicates whether process noise is additive
        const bool addw;

        // Dynamical model: x(tf) = f(ti, tf, x(ti), w)
        const dyn_model f;

        // Measurement model: z = h(t, x) + v
        const meas_model h;

        // Process & measurement noise covariance
        const Eigen::MatrixXd Pww, Pnn;

        // Cholesky decomposition of process noise covariance
        const Eigen::MatrixXd Cww;

        // Standardized sigma points & weights
        const Eigen::MatrixXd Sp, Su;
        const Eigen::VectorXd wp, wu;

        // Number of sigma points in prediction & update step
        const int nsp, nsu;

        // Constructor
        UKF (
            const dyn_model& f_,
            const meas_model& h_,
            bool addw_,
            double t0,
            const Eigen::VectorXd& xm0,
            const Eigen::MatrixXd& Pxx0,
            const Eigen::MatrixXd& Pww_,
            const Eigen::MatrixXd& Pnn_,
            sig_type stype,
            double k);

        // Prediction step
        void predict(double tp);

        // Update step with one measurement
        void update(const Eigen::VectorXd& z);

        // Run filter for sequence of measurements
        void run(const Eigen::VectorXd& tz, const Eigen::MatrixXd& Z);

        // Generate standardized sigma points
        static Eigen::MatrixXd sigmaSt(sig_type stype, int n, double k);

        // Generate sigma point weights
        static Eigen::VectorXd sigmaWt(sig_type stype, int n, double k);

        // Times
        std::vector<double> t;

        // State estimates
        std::vector<Eigen::VectorXd> xest;

        // State estimate covariances
        std::vector<Eigen::MatrixXd> Pxx;

        // Reset filter
        void reset(
            double t0,
            const Eigen::VectorXd& xm0,
            const Eigen::MatrixXd& Pxx0
        );

        // Save results
        void save(const std::string& filename);

        // Directory for CUT files
        static std::string cut_dir;

};

#endif


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                           */
/*  This file is part of the library KASKADE 7                               */
/*    see http://www.zib.de/projects/kaskade7-finite-element-toolbox         */
/*                                                                           */
/*  Copyright (C) 2002-2016 Zuse Institute Berlin                            */
/*                                                                           */
/*  KASKADE 7 is distributed under the terms of the ZIB Academic License.    */
/*    see $KASKADE/academic.txt                                              */
/*                                                                           */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef PSHAPEFUNCTIONS_HH
#define PSHAPEFUNCTIONS_HH

#include <tuple>
#include <vector>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <memory>

#include <boost/multi_array.hpp>

#include "fem/barycentric.hh"
#include "fem/fixdune.hh"
#include "fem/mllgeometry.hh"
#include "linalg/dynamicMatrix.hh"

namespace Kaskade
{
  /** \ingroup fem
   * \brief Shape functions
   *
   * This class provides a common interface to the access of shape functions
   *
   * \tparam ctype the scalar type used for coordinates (usually double)
   * \tparam dim the spatial dimension
   * \tparam T  Scalar type, the value field type of the shape functions
   * \tparam comp number of components
   *
   * A shape function lives on the reference element and may be scalar valued or vector valued:
   * \f[ \phi: R^d \to T^m \f]
   * with the spatial (grid) dimension \f$ d \f$, the value field type \f$ T \f$ (either a complex
   * or a real type), and the vectorial dimension \f$ m \f$ (comp) of the image space. Shape function
   * values are indeed defined not only on the reference element but on whole \f$ R^d \f$, even though
   * the values outside the reference elements may be of little interest.
   * It is possible to evaluate the shape function and its derivative.
   *
   */
  template <class ctype, int dim, class T=double, int comp=1>
  class ShapeFunction
  {
  public:
    virtual ~ShapeFunction() {}

    /**
     * \brief Creates a copy of the actual derived shape function.
     */
    virtual std::unique_ptr<ShapeFunction> clone() const = 0;

    /**
     * \brief Evaluates the shape function (all components at once).
     */
    virtual Dune::FieldVector<T,comp> evaluateFunction(Dune::FieldVector<ctype,dim> const& xi) const = 0;

    /**
     * \brief Evaluates the derivative of the shape function (all components and all directions at once).
     */
    virtual Dune::FieldMatrix<T,comp,dim> evaluateDerivative(Dune::FieldVector<ctype,dim> const& xi) const = 0;

    /**
     * \brief Evaluates the second derivative of the shape function (all components and all directions at once).
     */
    virtual Tensor3<T,comp,dim,dim> evaluate2ndDerivative(Dune::FieldVector<ctype,dim> const& xi) const {
      std::cerr << "NOT IMPLEMENTED: " << __FILE__ << ":" << __LINE__ << "\n";
      abort();
    }

    /**
     * \brief Returns a tuple (nominalOrder,codim,entity,index) giving detailed information about the location of the shape function.
     *
     * Each shape function is associated to a certain subentity of the element.
     *
     * nominalOrder is a nonnegative ordering parameter that is usually
     * the polynomial order of the shape function, but need not coincide.
     *
     * codim is the codimension of the subentity to which the shape
     * function is associated, entity is the number of the subentity,
     * and index is the number of the shape function among those that
     * are associated to the same subentity.
     */
    virtual std::tuple<int,int,int,int> location() const = 0;
  };

  //---------------------------------------------------------------------
  /** \ingroup fem
   *  \brief A set of shape functions
   *
   *
   * \tparam ctype scalar type for coordinates
   * \tparam dimension spatial dimension
   * \tparam T  scalar type
   * \tparam comp number of components
   */
  template <class ctype, int dimension, class T, int comp=1>
  class ShapeFunctionSet
  {
  public:
    /// Scalar field type
    typedef T Scalar;
    /// type of one shape function
    typedef ShapeFunction<ctype,dimension,T,comp> value_type;

    /**
     * \brief A matrix type mapping one-component coefficient vectors.
     */
    typedef DynamicMatrix<Dune::FieldMatrix<T,1,1> > Matrix;

    /// Constructor
    ShapeFunctionSet(Dune::GeometryType gt):
      order_(-1), size_(-1),
      gt_(gt),
      refElem(&Dune::ReferenceElements<ctype,dimension>::general(gt))
    {}

    ShapeFunctionSet(ShapeFunctionSet const& other)
    : iNodes(other.iNodes), projection(other.projection), order_(other.order_), size_(other.size_),
      gt_(other.gt_), refElem(&Dune::ReferenceElements<ctype,dimension>::general(gt_))
    {}

    /**
     * \brief Number of components of the shape function values.
     */
    static int const comps = comp;

    virtual ~ShapeFunctionSet() {}

    /// Random access to a shape function
    virtual value_type const& operator[](int i) const = 0;

    /**
     * \brief Number of shape functions in the set.
     */
    virtual int size() const { return size_; }

    /**
     * \brief Maximal polynomial order of shape functions.
     */
    int order() const { return order_; }

    /// Type of geometry on which the shape functions are defined.
    Dune::GeometryType type() const { return gt_; }

    /**
     * Returns a reference to the reference element on which this shape
     * function set is defined.
     */
    Dune::ReferenceElement<ctype,dimension> const& referenceElement() const { return *refElem; }

    /// A container type for holding interpolation points in the reference elements.
    typedef std::vector<Dune::FieldVector<ctype,dimension> > InterpolationNodes;

    /// A twodimensional array type for holding shape function values
    /// evaluated at a set of nodes.
    typedef DynamicMatrix<Dune::FieldMatrix<T,comp,1> > SfValueArray;

    /**
     * \brief Initialize the hierarchical projection matrix based on the given
     * lower order shape function set.
     */
    void initHierarchicalProjection(ShapeFunctionSet<ctype,dimension,T,comp> const* sfl)
    {
      // If no lower order shape function set is given, we assume an
      // empty set, i.e. the projection is just zero.
      if (!sfl || size()==0) {
        projection.setSize(size(),size());
//       projection = 0 // causes compilation error with dune-2.4.0 and clang++ on OS X (Darwin)
        projection.fill(0);
        return;
      }

      // Compute the hierarchic projection P = I_h E_l(x_h) I_l E_h(x_l),
      // where E_h(x_l) the evaluation of high order shape functions at
      // low order nodes, I_l the low order interpolation, E_l(x_h) the
      // evaluation of low order shape functions at high order nodes,
      // and I_h the high order shape function evaluation.

      // Compute the local restriction matrix A
      SfValueArray Ehxl;
      evaluate(sfl->interpolationNodes(),Ehxl);  // E_h(x_l)
      Matrix A;
      sfl->interpolate(Ehxl,A);                  // I_l  E_h(x_l)

      // Compute the local prolongation matrix B
      SfValueArray Elxh;
      sfl->evaluate(interpolationNodes(),Elxh);  // E_l(x_h)
      Matrix B;
      interpolate(Elxh,B);                       // I_h E_l(x_h)

      // Compute projection P=B*A
      MatMult(projection,B,A);
    }

    /**
     * @brief Interpolation points.
     *
     * Provides interpolation points such
     * that the shape function coefficients can be computed from
     * function values at interpolation nodes by multiplication by this
     * matrix.  The interpolation points are guaranteed to be inside the
     * reference element associated to this shape function set.
     */
    InterpolationNodes const& interpolationNodes() const { return iNodes; }

    /**
     * @brief Left-multiplies the provided matrix with the interpolation
     * matrix of the shape function set.
     *
     * Each column of A is interpreted as values of some function
     * evaluated at this shape function set's interpolation points (see
     * below). The columns of the output array IA then contain the shape
     * function coefficients such that the corresponding
     * linearcombination of shape functions "interpolates" that function
     * in the interpolation points. What "interpolation" means is up to
     * the actual implementation.
     *
     * IA is automatically resized if needed.
     *
     * Storage order: A[i][j] contains the value of function j at
     * interpolation node i.
     */
    virtual void interpolate(SfValueArray const& A, Matrix& IA) const = 0;

    /**
     * @brief Evaluate shape function set at a set of points. In
     * notation of the LocalToGlobalMapperConcept, this gives the matrix
     * \f$ \Phi \f$: the entry Phi[i][j] is the value of shape function
     * j evaluated at iNodes[i].
     *
     * @param iNodes the points at which the shape functions are to be evaluated.
     * \param phi    the array that is filled with shape function values. The array
     *               will be resized if needed.
     */
    void evaluate(InterpolationNodes const& iNodes, SfValueArray& phi) const
    {
      int s = size();
      phi.setSize(iNodes.size(),s);

      for (int j=0; j<s; ++j) {
        value_type const& sf = (*this)[j];
        for (int i=0; i<iNodes.size(); ++i) {
          Dune::FieldVector<T,comp> v = sf.evaluateFunction(iNodes[i]);
          for (int k=0; k<comp; ++k)
            phi[i][j][k] = v[k];  // todo: improve efficiency! cache directly!
        }
      }
    }

    /**
     * \brief Returns a square matrix that projects shape function
     * coefficients to a subspace spanned by shape functions of lower
     * order.  This is intended to be used to implement embedded error
     * estimators. The actual definition of this subspace depends on the
     * shape function set specified in the call to
     * initHierarchicalProjection().
     */
    Matrix const& hierarchicProjection() const
    {
      // check that the projection has been properly initialized.
      assert(projection.N()==size() && projection.M()==size());

      return projection;
    }

    virtual void removeShapeFunction(size_t index) {}

  protected:
    InterpolationNodes iNodes;
    Matrix             projection;
    int                order_;
    int                size_;

  private:
    Dune::GeometryType gt_;
    Dune::ReferenceElement<ctype,dimension> const* refElem;
   };

  //---------------------------------------------------------------------
  /**
   * \brief Restricted shape function set.
   * Introduces a new local ordering for the shape functions. To retrieve the original shape function id use getId(int newLocalId)
   * \todo docme: what is is good for? Which ordering? Why "restricted"?
   */
  template <class ShapeFunctionSet_>
  class RestrictedShapeFunctionSet: public ShapeFunctionSet_
  {
  public:
    /// Grid type
    //typedef typename ShapeFunctionSet_::Grid Grid; causes compiler error
    /// Scalar field type
    typedef typename ShapeFunctionSet_::Scalar Scalar;
    /// type of one shape function
    typedef typename ShapeFunctionSet_::value_type value_type;

    explicit RestrictedShapeFunctionSet(int order) : ShapeFunctionSet_(order) {}

    RestrictedShapeFunctionSet(ShapeFunctionSet_ const& other) : ShapeFunctionSet_(other) {}
    RestrictedShapeFunctionSet(RestrictedShapeFunctionSet const& other) : ShapeFunctionSet_(other) {}
    /// Copy constructor. Resets restriction ids
    RestrictedShapeFunctionSet(RestrictedShapeFunctionSet const& other, std::vector<int>* ids_) : ShapeFunctionSet_(other) {}

    virtual ~RestrictedShapeFunctionSet(){}

    /**
     * \param ids_ vector of used ids of the shape function set
     */
    void setRestriction(std::vector<int> const& ids_)
    {
      if(ids_.size()==0)
      {
        this->sf.clear();
        this->iNodes.clear();
        this->size_ = 0;
        return;
      }

      for(int i=this->sf.size()-1; i>-1; --i)
        if(std::find(ids_.begin(),ids_.end(),i)==ids_.end()) this->removeShapeFunction(i);

      this->size_ = ids_.size();
    }
  };

  //---------------------------------------------------------------------

  /**
   * \brief Base class for sets of shape function containers.
   *
   * \tparam ctype scalar type for coordinates
   * \tparam dimension spatial dimension
   * \tparam T the scalar shape function return value
   * \tparam comp the number of components of the shape functions' values
   */
  template <class ctype, int dimension, class T, int comp=1>
  class ShapeFunctionSetContainer
  {
  public:
    typedef ShapeFunctionSet<ctype,dimension,T,comp> value_type;

    virtual ~ShapeFunctionSetContainer() {}

    /// access a shape function via type and order
    virtual value_type const& operator() (Dune::GeometryType type, int order) const = 0;
  };

  //---------------------------------------------------------------------
  //---------------------------------------------------------------------

  /**
   * For a given shape function set \arg sfs which is defined on a
   * simplex and permits a simple coupling, and a given permutation \arg
   * vPermutation of the vertices of the simplex defining an affine
   * spatial transformation \f$ f \f$, this function returns a
   * permutation \arg sfPermutation of the shape functions and a sign
   * vector \arg sign, such that
   *
   * \f[ \mathrm{sign[k]}\phi_{\mathrm{sfPermutation[k]}}(f(x)) =
   * \phi_k(x). \f]
   */
  template <class ShapeFunctionSet>
  void computeSimplexSfPermutation(ShapeFunctionSet const& sfs,
      int const* vPermutation,
      int*       sfPermutation,
      int*       sign)
  {
    assert(vPermutation);
    assert(sfPermutation);
    assert(sign);

    // Ok, we rely on the evaluation & interpolation of the shape
    // function set. First we evaluate the shape functions on the
    // interpolation nodes transformed by f, then we interpolate these
    // values. This gives us a matrix which, if the shape function set
    // indeed allows simple coupling, is a signed permutation
    // matrix. Finally we extract the signs and the permutation from
    // this matrix.

    // Get the interpolation nodes. Make a copy because we need to
    // modify them.
    typedef typename ShapeFunctionSet::InterpolationNodes InterpolationNodes;
    InterpolationNodes in = sfs.interpolationNodes();

    // Transform the nodes. This is done by permuting their barycentric
    // coordinates. Remember that the interpolation nodes are given in
    // Cartesian, not in barycentric coordinates. This determines the
    // loop termination for j.
    for (int i=0; i<in.size(); ++i) {
      Dune::FieldVector<typename ShapeFunctionSet::Grid::ctype,ShapeFunctionSet::Grid::dimension+1> b = barycentric(in[i]);
      for (int j=0; j<ShapeFunctionSet::Grid::dimension; ++j)
        in[i][j] = b[vPermutation[j]];
    }

    // Evaluate the shape functions at the transformed nodes.
    typename ShapeFunctionSet::SfValueArray phi(in.size(),sfs.size());
    sfs.evaluate(in,phi);

    // Interpolate the shape function values.
    typename ShapeFunctionSet::Matrix P(sfs.size(),sfs.size());
    sfs.interpolate(phi,P);

#ifndef NDEBUG
    // Check that the permutation matrix is indeed a signed permutation
    bool ok = true;
    for (int i=0; i<sfs.size(); ++i) {
      double rowSum = 0;
      double colSum = 0;
      for (int j=0; j<sfs.size(); ++j) {
        if (std::abs(P[i][j])>1e-8 && std::abs(1-std::abs(P[i][j]))>1e-8) ok = false;
        rowSum += std::abs(P[i][j]);
        colSum += std::abs(P[j][i]);
      }
      if (std::abs(rowSum-1)>1e-8 || std::abs(colSum-1)>1e-8) ok = false;
    }
    if (!ok) {
      std::cout << "\nPermutation matrix:\n";
      for (int i=0; i<P.N(); ++i) {
        for (int j=0; j<P.M(); ++j)
          std::cout << std::setw(2) << P[i][j] << " ";
        std::cout << "\n";
      }
    }
#endif

    // Extract the permutation and the sign.
    for (int i=0; i<sfs.size(); ++i)
      for (int j=0; j<sfs.size(); ++j)
        if (std::abs(P[j][i])>0.5) {
          sfPermutation[i] = j; // XXX or the other way round?
          sign[i] = P[j][i]>0? 1: -1;
          break;
        }

  }
} // end of namespace Kaskade

#endif


/* =========================================================================
   Copyright (c) 2010-2016, Institute for Microelectronics,
                            Institute for Analysis and Scientific Computing,
                            TU Wien.
   Portions of this software are copyright by UChicago Argonne, LLC.

                            -----------------
                  ViennaCL - The Vienna Computing Library
                            -----------------

   Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at

   (A list of authors and contributors can be found in the PDF manual)

   License:         MIT (X11), see file LICENSE in the base directory
============================================================================= */

/** \example eigen-with-viennacl.cpp
*
*   This tutorial shows how data can be directly transferred from the Eigen Library to ViennaCL objects using the built-in convenience wrappers.
*
*   The first step is to include the necessary headers and activate the Eigen convenience functions in ViennaCL:
**/

// System headers
#include <iostream>

// Eigen headers
#include <Eigen/Core>
#include <Eigen/Sparse>

// IMPORTANT: Must be set prior to any ViennaCL includes if you want to use ViennaCL algorithms on Eigen objects
#define VIENNACL_WITH_EIGEN 1

// ViennaCL includes
#include "viennacl/vector.hpp"
#include "viennacl/matrix.hpp"
#include "viennacl/compressed_matrix.hpp"
#include "viennacl/linalg/prod.hpp"

// Helper functions for this tutorial:
#include "vector-io.hpp"

/**
*   The following is a set of auxiliary dispatchers for obtaining the right Eigen types for a given floating point type.
*   This is merely an implementation detail, so feel free to skip over it.
**/

//dense matrix:
template<typename T>
struct Eigen_dense_matrix
{
  typedef typename T::ERROR_NO_EIGEN_TYPE_AVAILABLE   error_type;
};

template<>
struct Eigen_dense_matrix<float>
{
  typedef Eigen::MatrixXf  type;
};

template<>
struct Eigen_dense_matrix<double>
{
  typedef Eigen::MatrixXd  type;
};

//sparse matrix
template<typename T>
struct Eigen_vector
{
  typedef typename T::ERROR_NO_EIGEN_TYPE_AVAILABLE   error_type;
};

template<>
struct Eigen_vector<float>
{
  typedef Eigen::VectorXf  type;
};

template<>
struct Eigen_vector<double>
{
  typedef Eigen::VectorXd  type;
};

/**
*    The following function contains the main code for this tutorial.
*    It consists of the following steps:
*      - Creates Eigen matrices and vectors
*      - Initializes them with data
*      - Create ViennaCL objects
*      - Copy them over to the respective ViennaCL objects
*      - Compute matrix-vector products in both Eigen and ViennaCL and compare results.
*
**/
template<typename ScalarType>
void run_tutorial()
{
  /**
  * Get Eigen matrix and vector types for the provided ScalarType.
  * Involves a little bit of template-metaprogramming.
  **/
  typedef typename Eigen_dense_matrix<ScalarType>::type  EigenMatrix;
  typedef typename Eigen_vector<ScalarType>::type        EigenVector;

  /**
  * Create and fill dense matrices from the Eigen library:
  **/
  EigenMatrix eigen_densemat(6, 5);
  EigenMatrix eigen_densemat2(6, 5);
  eigen_densemat(0,0) = 2.0;   eigen_densemat(0,1) = -1.0;
  eigen_densemat(1,0) = -1.0;  eigen_densemat(1,1) =  2.0;  eigen_densemat(1,2) = -1.0;
  eigen_densemat(2,1) = -1.0;  eigen_densemat(2,2) = -1.0;  eigen_densemat(2,3) = -1.0;
  eigen_densemat(3,2) = -1.0;  eigen_densemat(3,3) =  2.0;  eigen_densemat(3,4) = -1.0;
                               eigen_densemat(5,4) = -1.0;  eigen_densemat(4,4) = -1.0;
  Eigen::Map<EigenMatrix> eigen_densemat_map(eigen_densemat.data(), 6, 5); // same as eigen_densemat, but emulating user-provided buffer

  /**
  * Create and fill sparse matrices from the Eigen library:
  **/
  Eigen::SparseMatrix<ScalarType, Eigen::RowMajor> eigen_sparsemat(6, 5);
  Eigen::SparseMatrix<ScalarType, Eigen::RowMajor> eigen_sparsemat2(6, 5);
  eigen_sparsemat.reserve(5*2);
  eigen_sparsemat.insert(0,0) = 2.0;   eigen_sparsemat.insert(0,1) = -1.0;
  eigen_sparsemat.insert(1,1) = 2.0;   eigen_sparsemat.insert(1,2) = -1.0;
  eigen_sparsemat.insert(2,2) = -1.0;  eigen_sparsemat.insert(2,3) = -1.0;
  eigen_sparsemat.insert(3,3) = 2.0;   eigen_sparsemat.insert(3,4) = -1.0;
  eigen_sparsemat.insert(5,4) = -1.0;
  //eigen_sparsemat.endFill();

  /**
  * Create and fill a few vectors from the Eigen library:
  **/
  EigenVector eigen_rhs(5);
  Eigen::Map<EigenVector> eigen_rhs_map(eigen_rhs.data(), 5);
  EigenVector eigen_result(6);
  EigenVector eigen_temp(6);

  eigen_rhs(0) = 10.0;
  eigen_rhs(1) = 11.0;
  eigen_rhs(2) = 12.0;
  eigen_rhs(3) = 13.0;
  eigen_rhs(4) = 14.0;

  /**
  * Create the corresponding ViennaCL objects:
  **/
  viennacl::vector<ScalarType> vcl_rhs(5);
  viennacl::vector<ScalarType> vcl_result(6);
  viennacl::matrix<ScalarType> vcl_densemat(6, 5);
  viennacl::compressed_matrix<ScalarType> vcl_sparsemat(6, 5);

  /**
  * Directly copy the Eigen objects to ViennaCL objects
  **/
  viennacl::copy(&(eigen_rhs[0]), &(eigen_rhs[0]) + 5, vcl_rhs.begin());  // Method 1: via iterator interface (cf. std::copy())
  viennacl::copy(eigen_rhs, vcl_rhs);                                     // Method 2: via built-in wrappers (convenience layer)
  viennacl::copy(eigen_rhs_map, vcl_rhs);                                 // Same as method 2, but for a mapped vector

  viennacl::copy(eigen_densemat, vcl_densemat);
  viennacl::copy(eigen_densemat_map, vcl_densemat); //same as above, using mapped matrix
  viennacl::copy(eigen_sparsemat, vcl_sparsemat);
  std::cout << "VCL sparsematrix dimensions: " << vcl_sparsemat.size1() << ", " << vcl_sparsemat.size2() << std::endl;

  // For completeness: Copy matrices from ViennaCL back to Eigen:
  viennacl::copy(vcl_densemat, eigen_densemat2);
  viennacl::copy(vcl_sparsemat, eigen_sparsemat2);

  /**
  * Run dense matrix-vector products and compare results:
  **/
  eigen_result = eigen_densemat * eigen_rhs;
  vcl_result = viennacl::linalg::prod(vcl_densemat, vcl_rhs);
  viennacl::copy(vcl_result, eigen_temp);
  std::cout << "Difference for dense matrix-vector product: " << (eigen_result - eigen_temp).norm() << std::endl;
  std::cout << "Difference for dense matrix-vector product (Eigen->ViennaCL->Eigen): "
            << (eigen_densemat2 * eigen_rhs - eigen_temp).norm() << std::endl;

  /**
  * Run sparse matrix-vector products and compare results:
  **/
  eigen_result = eigen_sparsemat * eigen_rhs;
  vcl_result = viennacl::linalg::prod(vcl_sparsemat, vcl_rhs);
  viennacl::copy(vcl_result, eigen_temp);
  std::cout << "Difference for sparse matrix-vector product: " << (eigen_result - eigen_temp).norm() << std::endl;
  std::cout << "Difference for sparse matrix-vector product (Eigen->ViennaCL->Eigen): "
            << (eigen_sparsemat2 * eigen_rhs - eigen_temp).norm() << std::endl;
}

/**
*   In the main() routine we only call the worker function defined above with both single and double precision arithmetic.
**/
int main(int, char *[])
{
  std::cout << "----------------------------------------------" << std::endl;
  std::cout << "## Single precision" << std::endl;
  std::cout << "----------------------------------------------" << std::endl;
  run_tutorial<float>();

#ifdef VIENNACL_HAVE_OPENCL
  if ( viennacl::ocl::current_device().double_support() )
#endif
  {
    std::cout << "----------------------------------------------" << std::endl;
    std::cout << "## Double precision" << std::endl;
    std::cout << "----------------------------------------------" << std::endl;
    run_tutorial<double>();
  }

  /**
  *   That's it. Print a success message and exit.
  **/
  std::cout << std::endl;
  std::cout << "!!!! TUTORIAL COMPLETED SUCCESSFULLY !!!!" << std::endl;
  std::cout << std::endl;

}


// Copyright 2015-2018 Hans Dembinski
//
// 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)

#ifndef BOOST_HISTOGRAM_ACCUMULATORS_MEAN_HPP
#define BOOST_HISTOGRAM_ACCUMULATORS_MEAN_HPP

#include <boost/core/nvp.hpp>
#include <boost/histogram/fwd.hpp> // for mean<>
#include <boost/throw_exception.hpp>
#include <cassert>
#include <stdexcept>
#include <type_traits>

namespace boost {
namespace histogram {
namespace accumulators {

/** Calculates mean and variance of sample.

  Uses Welfords's incremental algorithm to improve the numerical
  stability of mean and variance computation.
*/
template <class ValueType>
class mean {
public:
  using value_type = ValueType;
  using const_reference = const value_type&;

  mean() = default;

  /// Allow implicit conversion from mean<T>
  template <class T>
  mean(const mean<T>& o) noexcept
      : sum_{o.sum_}, mean_{o.mean_}, sum_of_deltas_squared_{o.sum_of_deltas_squared_} {}

  /// Initialize to external count, mean, and variance
  mean(const_reference n, const_reference mean, const_reference variance) noexcept
      : sum_(n), mean_(mean), sum_of_deltas_squared_(variance * (n - 1)) {}

  /// Insert sample x
  void operator()(const_reference x) noexcept {
    sum_ += static_cast<value_type>(1);
    const auto delta = x - mean_;
    mean_ += delta / sum_;
    sum_of_deltas_squared_ += delta * (x - mean_);
  }

  /// Insert sample x with weight w
  void operator()(const weight_type<value_type>& w, const_reference x) noexcept {
    sum_ += w.value;
    const auto delta = x - mean_;
    mean_ += w.value * delta / sum_;
    sum_of_deltas_squared_ += w.value * delta * (x - mean_);
  }

  /// Add another mean accumulator
  mean& operator+=(const mean& rhs) noexcept {
    if (sum_ != 0 || rhs.sum_ != 0) {
      const auto tmp = mean_ * sum_ + rhs.mean_ * rhs.sum_;
      sum_ += rhs.sum_;
      mean_ = tmp / sum_;
    }
    sum_of_deltas_squared_ += rhs.sum_of_deltas_squared_;
    return *this;
  }

  /** Scale by value

   This acts as if all samples were scaled by the value.
  */
  mean& operator*=(const_reference s) noexcept {
    mean_ *= s;
    sum_of_deltas_squared_ *= s * s;
    return *this;
  }

  bool operator==(const mean& rhs) const noexcept {
    return sum_ == rhs.sum_ && mean_ == rhs.mean_ &&
           sum_of_deltas_squared_ == rhs.sum_of_deltas_squared_;
  }

  bool operator!=(const mean& rhs) const noexcept { return !operator==(rhs); }

  /// Return how many samples were accumulated
  const_reference count() const noexcept { return sum_; }

  /// Return mean value of accumulated samples
  const_reference value() const noexcept { return mean_; }

  /// Return variance of accumulated samples
  value_type variance() const noexcept { return sum_of_deltas_squared_ / (sum_ - 1); }

  template <class Archive>
  void serialize(Archive& ar, unsigned version) {
    if (version == 0) {
      // read only
      std::size_t sum;
      ar& make_nvp("sum", sum);
      sum_ = static_cast<value_type>(sum);
    } else {
      ar& make_nvp("sum", sum_);
    }
    ar& make_nvp("mean", mean_);
    ar& make_nvp("sum_of_deltas_squared", sum_of_deltas_squared_);
  }

private:
  value_type sum_{};
  value_type mean_{};
  value_type sum_of_deltas_squared_{};
};

} // namespace accumulators
} // namespace histogram
} // namespace boost

#ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED

namespace boost {
namespace serialization {

template <class T>
struct version;

// version 1 for boost::histogram::accumulators::mean<T>
template <class T>
struct version<boost::histogram::accumulators::mean<T>> : std::integral_constant<int, 1> {
};

} // namespace serialization
} // namespace boost

namespace std {
template <class T, class U>
/// Specialization for boost::histogram::accumulators::mean.
struct common_type<boost::histogram::accumulators::mean<T>,
                   boost::histogram::accumulators::mean<U>> {
  using type = boost::histogram::accumulators::mean<common_type_t<T, U>>;
};
} // namespace std

#endif

#endif