#define DEBUG 1
/**
 * File    : L.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/1/31 16:50:07
 * 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;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- 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>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL};
// 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);
}
// ----- main() -----

char to_char(int x)
{
  return x + 'A';
}

bool query(int const &x, int const &y)
{
  cout << "? " << to_char(x) << " " << to_char(y) << endl;
  char a;
  cin >> a;
  return a == '<';
}

template <typename Iter, typename Comp>
void merge_sort(Iter begin, Iter end, Comp cmp);

template <typename Iter, typename Comp>
void merge_sort_impl(Iter begin, Iter end, Comp cmp, random_access_iterator_tag)
{
  int N{static_cast<int>(end - begin)};
  if (N <= 1)
  {
    return;
  }
  auto mid{begin + N / 2};
  merge_sort(begin, mid, cmp);
  merge_sort(mid, end, cmp);
  vector<typename Iter::value_type> temp(N);
  merge(begin, mid, mid, end, temp.begin(), cmp);
  copy(temp.begin(), temp.end(), begin);
}

template <typename Iter, typename Comp>
void merge_sort(Iter begin, Iter end, Comp cmp)
{
  merge_sort_impl(begin, end, cmp, typename std::iterator_traits<Iter>::iterator_category());
}

bool check_vector(vector<int> const &V, int x, int y)
{
  for (auto e : V)
  {
    if (e == x)
    {
      return true;
    }
    else if (e == y)
    {
      return false;
    }
  }
  assert(false);
  return true;
}

int main()
{
  int N, Q;
  cin >> N >> Q;
  vector<int> V(N);
  for (auto i = 0; i < N; ++i)
  {
    V[i] = i;
  }
  if (Q == 1000)
  {
    sort(V.begin(), V.end(), query);
    cout << "! ";
    for (auto i = 0; i < N; ++i)
    {
      cout << to_char(V[i]);
    }
    cout << endl;
  }
  else if (Q == 100)
  {
    merge_sort(V.begin(), V.end(), query);
    cout << "! ";
    for (auto i = 0; i < N; ++i)
    {
      cout << to_char(V[i]);
    }
    cout << endl;
  }
  else
  {
    vector<vector<int>> W;
    do
    {
      W.push_back(V);
    } while (next_permutation(V.begin(), V.end()));
    while (static_cast<int>(W.size()) > 1)
    {
      auto cnt{static_cast<int>(W.size())};
      int ind_x = -1, ind_y = -1;
      for (auto x = 0; x < N; ++x)
      {
        for (auto y = x + 1; y < N; ++y)
        {
          int tmp{0};
          for (auto const &v : W)
          {
            if (check_vector(v, x, y))
            {
              ++tmp;
            }
          }
          auto c_tmp{static_cast<int>(W.size()) - tmp};
          auto t{max(tmp, c_tmp)};
          if (cnt > t)
          {
            cnt = t;
            ind_x = x;
            ind_y = y;
          }
        }
      }
      assert(ind_x != -1 && ind_y != -1);
      if (!query(ind_x, ind_y))
      {
        swap(ind_x, ind_y);
      }
      vector<vector<int>> U;
      for (auto const &v : W)
      {
        if (check_vector(v, ind_x, ind_y))
        {
          U.push_back(v);
        }
      }
      swap(U, W);
    }
    auto const &v{W[0]};
    cout << "! ";
    for (auto i = 0; i < N; ++i)
    {
      cout << to_char(v[i]);
    }
    cout << endl;
  }
}


#include "wanglandau.h"
#include <limits>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <algorithm>

namespace wanglandau{

WangLandau::WangLandau(int hsize, double flatness,
                       double final_factor, int initial_threshold,
                       double normalization, int normalization_origin)
  :hsize_(hsize), hist_(hsize), g_(hsize),
   flatness_(flatness), factor_(1.0), final_(final_factor),
   threshold_(initial_threshold), stage_(1),
   normalization_(normalization), normalization_origin_(normalization_origin)
{
}

bool WangLandau::check_flat(bool verbose = false)
{
  long hmin = std::numeric_limits<long>::max();
  int count = 0;
  long hsum = 0;
  for(int i=0; i<hsize_; ++i){
    if(hist_[i] == 0) continue;
    ++count;
    hsum += hist_[i];
    hmin = std::min(hmin, hist_[i]);
  }
  const double mean = static_cast<double>(hsum)/count;
  const double fn = hmin / mean;
  if(count < threshold_ || fn < flatness_){
    if(verbose){
      std::cout << "Histogram is not flat. "
               << "[ hmin = " << hmin
               << ", mean = " << mean
               << ", flatness = " << fn
               << ", nonzero bin = " << count
               << ", threshold = " << threshold_
               << ", factor = " << factor_
               << "]" << std::endl;
    }
    return false;
  }else{
    if(verbose){
      std::cout << "Histogram is     flat. "
               << "[ hmin = " << hmin
               << ", mean = " << mean
               << ", flatness = " << fn
               << ", nonzero bin = " << count
               << ", threshold = " << threshold_
               << ", factor = " << factor_
               << "]" << std::endl;
    }
    threshold_ = count;
    return true;
  }
}

void WangLandau::update(bool verbose=false)
{
  bool flat = check_flat(verbose);
  if(flat){

    /*
     * save and reset
     */

    std::string filename("hist-");
    filename += boost::lexical_cast<std::string>(stage_);
    filename += ".dat";
    std::ofstream ofs(filename.c_str());
    ofs << "# $1 : index" << std::endl;
    ofs << "# $2 : log of DoS" << std::endl;
    ofs << "# $3 : population" << std::endl;

    const double offset = normalization_ - g_[normalization_origin_];
    for(int i=0; i<hsize_; ++i){
      g_[i] += offset;
      if(hist_[i] != 0)
        ofs << i << " " << g_[i] << " " << hist_[i] << std::endl;
      hist_[i] = 0;
    }

    std::cout << "# " <<  stage_ << " iteration (factor = " << factor_ << " ) finished." << std::endl;
    factor_ *= 0.5;
    ++stage_;
  }
}

} // end of namespace wanglandau


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

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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)

#include <geometry_test_common.hpp>

#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>
#include <boost/geometry/util/rational.hpp>

void test_coordinate_cast(std::string const& s, int expected_nom, int expected_denom)
{
    boost::rational<int> a = bg::detail::coordinate_cast<boost::rational<int> >::apply(s);
    BOOST_CHECK_EQUAL(a.numerator(), expected_nom);
    BOOST_CHECK_EQUAL(a.denominator(), expected_denom);
}

void test_wkt(std::string const& wkt, std::string const expected_wkt)
{
    bg::model::point<boost::rational<int>, 2, bg::cs::cartesian> p;
    bg::read_wkt(wkt, p);
    std::ostringstream out;
    out << bg::wkt(p);

    BOOST_CHECK_EQUAL(out.str(), expected_wkt);
}

int test_main(int, char* [])
{
    test_coordinate_cast("0", 0, 1);
    test_coordinate_cast("1", 1, 1);
    test_coordinate_cast("-1", -1, 1);
    test_coordinate_cast("-0.5", -1, 2);
    test_coordinate_cast("-1.5", -3, 2);
    test_coordinate_cast("0.5", 1, 2);
    test_coordinate_cast("1.5", 3, 2);
    test_coordinate_cast("2.12345", 42469, 20000);
    test_coordinate_cast("1.", 1, 1);

    test_coordinate_cast("3/2", 3, 2);
    test_coordinate_cast("-3/2", -3, 2);

    test_wkt("POINT(1.5 2.75)", "POINT(3/2 11/4)");
    test_wkt("POINT(3/2 11/4)", "POINT(3/2 11/4)");
    test_wkt("POINT(-1.5 2.75)", "POINT(-3/2 11/4)");
    test_wkt("POINT(-3/2 11/4)", "POINT(-3/2 11/4)");

    return 0;
}


#include <boost/test/unit_test.hpp>

#include "logs.h"
#include "route.h"
#include "track.h"
#include <math.h>

using namespace GPS;

/*

  A B C D E
  F G H I J
  K L M N O
  P Q R S T
  U V W X Y

*/

/*
 * Check if the total length calculated from the GPX files
 * is close to the length calculated in the function.
 */
BOOST_AUTO_TEST_SUITE( route_correct_distance_from_files )

const bool isFileName = true;

// check if the length calculated from the file ABCD.gpx
// is close to the length calculated in the function
BOOST_AUTO_TEST_CASE( ABCD_length )
{
   Route route = Route(LogFiles::GPXRoutesDir + "ABCD.gpx", isFileName);
   BOOST_CHECK_EQUAL(30022.523566455005, route.totalLength());
}

// check if the length calculated from the file NorthYorkMoors.gpx
// is close to the length calculated in the function
BOOST_AUTO_TEST_CASE( NYM_length )
{
   Route route = Route(LogFiles::GPXRoutesDir + "NorthYorkMoors.gpx", isFileName);
   BOOST_CHECK_EQUAL(25204.617211916873, route.totalLength());
}

// check if function can calculate length between 2 consecutive points
// Ex: Distance between A and B
// using the log file AB.gpx
BOOST_AUTO_TEST_CASE( AB_length) {
    Route route = Route(LogFiles::GPXRoutesDir + "AB.gpx", isFileName);
    BOOST_CHECK_CLOSE(10010, route.totalLength(), 2);
}

// check if function can calculate an overlapping route
// Ex: ABA => AB & BA
// This test can also be used to check if length calculated
// by moving right 1 point is equal to the length calculated by moving left 1 point
// Ex: AB (moving right 1 point) =? BA(moving left 1 point)
BOOST_AUTO_TEST_CASE( ABA_length) {
    Route route = Route(LogFiles::GPXRoutesDir + "ABA.gpx", isFileName);
    BOOST_CHECK_CLOSE(20020, route.totalLength(), 2);
}

// checks if length calculated by moving downwards 2 points is equal to
// the length calculated by moving upwards 2 points
// Ex: length of CHM (move downwards 2 points) =? length of MHC (move upwards 2 points)
BOOST_AUTO_TEST_CASE( CHM_MHC_length) {
    Route route1 = Route(LogFiles::GPXRoutesDir + "CHM.gpx", isFileName);
    Route route2 = Route(LogFiles::GPXRoutesDir + "MHC.gpx", isFileName);
    BOOST_CHECK_CLOSE(route1.totalLength(), route2.totalLength(), 2);
}

// checks if length calculated by moving right one point is equal to
// the length calculated my moving downwards one point
// Ex: length of AB (move right 1 ponit) =? length of BG (move downwards 1 point)
// Note: AB.gpx is already tested above so if BG.gpx is equal to AB.gpx then BG.gpx is correct
BOOST_AUTO_TEST_CASE( BG_AB_length) {
    Route route1 = Route(LogFiles::GPXRoutesDir + "AB.gpx", isFileName);
    Route route2 = Route(LogFiles::GPXRoutesDir + "BG.gpx", isFileName);
    BOOST_CHECK_CLOSE(route1.totalLength(), route2.totalLength(), 2);
}

// checks if length calculated by moving upwards 2 points is equal to
// the length calculated by moving right 2 points
// Ex: length of ABC (move right 2 points) =? length of CHM (move downwards 2 points)
BOOST_AUTO_TEST_CASE( ABC_CHM_length) {
    Route route1 = Route(LogFiles::GPXRoutesDir + "ABC.gpx", isFileName);
    Route route2 = Route(LogFiles::GPXRoutesDir + "CHM.gpx", isFileName);
    BOOST_CHECK_CLOSE(route1.totalLength(), route2.totalLength(), 2);
}

// check if function can calculate diagonal lengths
// Ex: length of AGMSY => length of EIMQU
BOOST_AUTO_TEST_CASE( AGMSY_EIMQU_length) {
    Route route1 = Route(LogFiles::GPXRoutesDir + "AGMSY.gpx", isFileName);
    Route route2 = Route(LogFiles::GPXRoutesDir + "EIMQU.gpx", isFileName);
    BOOST_CHECK_CLOSE(route1.totalLength(), route2.totalLength(), 2);
}

// check if pythagoras' theorem works
// using the triangle AFG
// AG(2) =? AF(2) + FG(2)
BOOST_AUTO_TEST_CASE( pythagorean ) {
    Route ag_route = Route(LogFiles::GPXRoutesDir + "AG.gpx", isFileName);
    Route af_route = Route(LogFiles::GPXRoutesDir + "AF.gpx", isFileName);
    Route fg_route = Route(LogFiles::GPXRoutesDir + "FG.gpx", isFileName);
    BOOST_CHECK_CLOSE(pow(ag_route.totalLength(), 2),
                      pow(af_route.totalLength(), 2) + pow(fg_route.totalLength(), 2),
                      2);
}

// check if length calculated by adding by adding 2 routes is equal to the
// length calculated by adding 2 different routes
// where all routes have equal length
// Ex: length of AB + length of RS ?= length of XY + length of OJ
BOOST_AUTO_TEST_CASE( routes_addition) {
    Route ab_route = Route(LogFiles::GPXRoutesDir + "AB.gpx", isFileName);
    Route rs_route = Route(LogFiles::GPXRoutesDir + "RS.gpx", isFileName);
    Route xy_route = Route(LogFiles::GPXRoutesDir + "XY.gpx", isFileName);
    Route oj_route = Route(LogFiles::GPXRoutesDir + "OJ.gpx", isFileName);
    BOOST_CHECK_CLOSE(ab_route.totalLength() + rs_route.totalLength(),
                      xy_route.totalLength() + oj_route.totalLength(),
                      2);
}

// check if length calculated by 2 unsuccessive points is equal to the
// length calculated by another 2 unsuccessive points
// Ex: length of AJ =? length of PY
// where AJ & PY are unsuccessive points
BOOST_AUTO_TEST_CASE( AJ_PY_length) {
    Route route1 = Route(LogFiles::GPXRoutesDir + "AJ.gpx", isFileName);
    Route route2 = Route(LogFiles::GPXRoutesDir + "PY.gpx", isFileName);
    BOOST_CHECK_CLOSE(route1.totalLength(), route2.totalLength(), 2);
}

// check if FG 1/4 FJ
// check if length calculated from the route FG is 1/4 the length of route FJ
BOOST_AUTO_TEST_CASE( FG_FJ_length) {
    Route fg_route = Route(LogFiles::GPXRoutesDir + "FG.gpx", isFileName);
    Route fj_route = Route(LogFiles::GPXRoutesDir + "FJ.gpx", isFileName);
    BOOST_CHECK_CLOSE(0.25 * fj_route.totalLength(),
                      fg_route.totalLength(),
                      2);
}

BOOST_AUTO_TEST_SUITE_END()
/////////////////////////////////////////////////////////////////////////////////////////////

/*
 * checks if function throws exceptions when given incorrect files
 * Such files could be empty strings or non existing files
 */
BOOST_AUTO_TEST_SUITE( incorrect_files)

const bool isFileName = true;

// checks if function throws an invalid argument exception when opening
// NNorthYorkMoors.gpx file (which does not exist)
BOOST_AUTO_TEST_CASE( wrong_file_name )
{
   BOOST_CHECK_THROW(Route route = Route(LogFiles::GPXRoutesDir + "NNorthYorkMoors.gpx", isFileName),
                     std::invalid_argument);
}

// checks if function throws a domain error exception when
// an empty string is given instead of a file name
BOOST_AUTO_TEST_CASE( empty_file_name_param )
{
   BOOST_CHECK_THROW(Route route = Route(LogFiles::GPXRoutesDir + "", isFileName),
                     std::domain_error);
}

BOOST_AUTO_TEST_SUITE_END()
/////////////////////////////////////////////////////////////////////////////////////////////

// checks if function throws exception if the xml contents of the file are incorrect
// such contents could be 'rtept' 'lat' 'lon' 'rte' 'gpx'
BOOST_AUTO_TEST_SUITE( wrong_file_contents )

const bool isFileName = true;

// check if function throws exception if 'rte' is missing from the log file 'ABCD_rte.gpx'
BOOST_AUTO_TEST_CASE( rte_not_found ) {
    BOOST_CHECK_THROW(Route route = Route(LogFiles::GPXRoutesDir + "ABCD_rte.gpx", isFileName),
                      std::domain_error);
}

// check if function throws exception when 'rtept' is missing from the log file 'ABCD_rtept.gpx'
BOOST_AUTO_TEST_CASE( rtept_not_found ) {
    BOOST_CHECK_THROW(Route route = Route(LogFiles::GPXRoutesDir + "ABCD_rtept.gpx", isFileName),
                      std::domain_error);
}

// check if function throws exception when 'lat' is missing from the log file 'ABCD_lat.gpx'
BOOST_AUTO_TEST_CASE( lat_not_found ) {
    BOOST_CHECK_THROW(Route route = Route(LogFiles::GPXRoutesDir + "ABCD_lat.gpx", isFileName),
                      std::domain_error);
}

// check if function throws exception when 'lon' is missing from the log file 'ABCD_lon.gpx'
BOOST_AUTO_TEST_CASE( lon_not_found) {
    BOOST_CHECK_THROW(Route route = Route(LogFiles::GPXRoutesDir + "ABCD_lon.gpx", isFileName),
                      std::domain_error);
}

// check if program throws exception when 'gpx' is missing from the log file 'ABCD_lon.gpx'
BOOST_AUTO_TEST_CASE( gpx_not_found ) {
    BOOST_CHECK_THROW(Route route = Route(LogFiles::GPXRoutesDir + "ABCD_lon.gpx", isFileName),
                      std::domain_error);
}

BOOST_AUTO_TEST_SUITE_END()
/////////////////////////////////////////////////////////////////////////////////////////////

// checks if function can catch incorrect_positions
// Ex: repeated positions or positions that have over range latitude and longitude
BOOST_AUTO_TEST_SUITE( incorrect_positions )

const bool isFileName = true;

// checks if program ignores repeated position (positions that are repeated consecutively).
BOOST_AUTO_TEST_CASE( duplicate_positions ) {
    Route route = Route(LogFiles::GPXRoutesDir + "ABCD_duplicate_positions.gpx", isFileName);
    BOOST_CHECK_EQUAL(30022.523566455005, route.totalLength());
}

BOOST_AUTO_TEST_SUITE_END()


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

 * 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   testVector.cpp
 * @brief  Unit tests for Vector class
 * @author Frank Dellaert
 **/

#include <iostream>
#include <CppUnitLite/TestHarness.h>
#include <boost/tuple/tuple.hpp>
#include <gtsam/base/Vector.h>

using namespace std;
using namespace gtsam;

namespace {
  /* ************************************************************************* */
  template<typename Derived>
  Vector testFcn1(const Eigen::DenseBase<Derived>& in)
  {
    return in;
  }

  /* ************************************************************************* */
  template<typename Derived>
  Vector testFcn2(const Eigen::MatrixBase<Derived>& in)
  {
    return in;
  }
}

/* ************************************************************************* */
TEST( TestVector, special_comma_initializer)
{
  Vector expected(3);
  expected(0) = 1;
  expected(1) = 2;
  expected(2) = 3;

  Vector actual1 = (Vector(3) << 1, 2, 3);
  Vector actual2((Vector(3) << 1, 2, 3));

  Vector subvec1 = (Vector(2) << 2, 3);
  Vector actual4 = (Vector(3) << 1, subvec1);

  Vector subvec2 = (Vector(2) << 1, 2);
  Vector actual5 = (Vector(3) << subvec2, 3);

  Vector actual6 = testFcn1((Vector(3) << 1, 2, 3));
  Vector actual7 = testFcn2((Vector(3) << 1, 2, 3));

  EXPECT(assert_equal(expected, actual1));
  EXPECT(assert_equal(expected, actual2));
  EXPECT(assert_equal(expected, actual4));
  EXPECT(assert_equal(expected, actual5));
  EXPECT(assert_equal(expected, actual6));
  EXPECT(assert_equal(expected, actual7));
}

/* ************************************************************************* */
TEST( TestVector, copy )
{
  Vector a(2); a(0) = 10; a(1) = 20;
  double data[] = {10,20};
  Vector b(2);
  copy(data,data+2,b.data());
  EXPECT(assert_equal(a, b));
}

/* ************************************************************************* */
TEST( TestVector, zero1 )
{
  Vector v = Vector::Zero(2);
  EXPECT(zero(v));
}

/* ************************************************************************* */
TEST( TestVector, zero2 )
{
  Vector a = zero(2);
  Vector b = Vector::Zero(2);
  EXPECT(a==b);
  EXPECT(assert_equal(a, b));
}

/* ************************************************************************* */
TEST( TestVector, scalar_multiply )
{
  Vector a(2); a(0) = 10; a(1) = 20;
  Vector b(2); b(0) = 1; b(1) = 2;
  EXPECT(assert_equal(a,b*10.0));
}

/* ************************************************************************* */
TEST( TestVector, scalar_divide )
{
  Vector a(2); a(0) = 10; a(1) = 20;
  Vector b(2); b(0) = 1; b(1) = 2;
  EXPECT(assert_equal(b,a/10.0));
}

/* ************************************************************************* */
TEST( TestVector, negate )
{
  Vector a(2); a(0) = 10; a(1) = 20;
  Vector b(2); b(0) = -10; b(1) = -20;
  EXPECT(assert_equal(b, -a));
}

/* ************************************************************************* */
TEST( TestVector, sub )
{
  Vector a(6);
  a(0) = 10; a(1) = 20; a(2) = 3;
  a(3) = 34; a(4) = 11; a(5) = 2;

  Vector result(sub(a,2,5));

  Vector b(3);
  b(0) = 3; b(1) = 34; b(2) =11;

  EXPECT(b==result);
  EXPECT(assert_equal(b, result));
}

/* ************************************************************************* */
TEST( TestVector, subInsert )
{
  Vector big = zero(6),
       small = ones(3);

  size_t i = 2;
  subInsert(big, small, i);

  Vector expected = (Vector(6) << 0.0, 0.0, 1.0, 1.0, 1.0, 0.0);

  EXPECT(assert_equal(expected, big));
}

/* ************************************************************************* */
TEST( TestVector, householder )
{
  Vector x(4);
  x(0) = 3; x(1) = 1; x(2) = 5; x(3) = 1;

  Vector expected(4);
  expected(0) = 1.0; expected(1) = -0.333333; expected(2) = -1.66667; expected(3) = -0.333333;

  pair<double, Vector> result = house(x);

  EXPECT(result.first==0.5);
  EXPECT(equal_with_abs_tol(expected,result.second,1e-5));
}

/* ************************************************************************* */
TEST( TestVector, concatVectors)
{
  Vector A(2);
  for(int i = 0; i < 2; i++)
    A(i) = i;
  Vector B(5);
  for(int i = 0; i < 5; i++)
    B(i) = i;

  Vector C(7);
  for(int i = 0; i < 2; i++) C(i) = A(i);
  for(int i = 0; i < 5; i++) C(i+2) = B(i);

  list<Vector> vs;
  vs.push_back(A);
  vs.push_back(B);
  Vector AB1 = concatVectors(vs);
  EXPECT(AB1 == C);

  Vector AB2 = concatVectors(2, &A, &B);
  EXPECT(AB2 == C);
}

/* ************************************************************************* */
TEST( TestVector, weightedPseudoinverse )
{
  // column from a matrix
  Vector x(2);
  x(0) = 1.0; x(1) = 2.0;

  // create sigmas
  Vector sigmas(2);
  sigmas(0) = 0.1; sigmas(1) = 0.2;
  Vector weights = reciprocal(emul(sigmas,sigmas));

  // perform solve
  Vector actual; double precision;
  boost::tie(actual, precision) = weightedPseudoinverse(x, weights);

  // construct expected
  Vector expected(2);
  expected(0) = 0.5; expected(1) = 0.25;
  double expPrecision = 200.0;

  // verify
  EXPECT(assert_equal(expected,actual));
  EXPECT(fabs(expPrecision-precision) < 1e-5);
}

/* ************************************************************************* */
TEST( TestVector, weightedPseudoinverse_constraint )
{
  // column from a matrix
  Vector x(2);
  x(0) = 1.0; x(1) = 2.0;

  // create sigmas
  Vector sigmas(2);
  sigmas(0) = 0.0; sigmas(1) = 0.2;
  Vector weights = reciprocal(emul(sigmas,sigmas));

  // perform solve
  Vector actual; double precision;
  boost::tie(actual, precision) = weightedPseudoinverse(x, weights);

  // construct expected
  Vector expected(2);
  expected(0) = 1.0; expected(1) = 0.0;

  // verify
  EXPECT(assert_equal(expected,actual));
  EXPECT(std::isinf(precision));
}

/* ************************************************************************* */
TEST( TestVector, weightedPseudoinverse_nan )
{
  Vector a = (Vector(4) << 1., 0., 0., 0.);
  Vector sigmas = (Vector(4) << 0.1, 0.1, 0., 0.);
  Vector weights = reciprocal(emul(sigmas,sigmas));
  Vector pseudo; double precision;
  boost::tie(pseudo, precision) = weightedPseudoinverse(a, weights);

  Vector expected = (Vector(4) << 1., 0., 0.,0.);
  EXPECT(assert_equal(expected, pseudo));
  DOUBLES_EQUAL(100, precision, 1e-5);
}

/* ************************************************************************* */
TEST( TestVector, ediv )
{
  Vector a = (Vector(3) << 10., 20., 30.);
  Vector b = (Vector(3) << 2.0, 5.0, 6.0);
  Vector actual(ediv(a,b));

  Vector c = (Vector(3) << 5.0, 4.0, 5.0);
  EXPECT(assert_equal(c,actual));
}

/* ************************************************************************* */
TEST( TestVector, dot )
{
  Vector a = (Vector(3) << 10., 20., 30.);
  Vector b = (Vector(3) << 2.0, 5.0, 6.0);
  DOUBLES_EQUAL(20+100+180,dot(a,b),1e-9);
}

/* ************************************************************************* */
TEST( TestVector, axpy )
{
  Vector x = (Vector(3) << 10., 20., 30.);
  Vector y0 = (Vector(3) << 2.0, 5.0, 6.0);
  Vector y1 = y0, y2 = y0;
  axpy(0.1,x,y1);
  axpy(0.1,x,y2.head(3));
  Vector expected = (Vector(3) << 3.0, 7.0, 9.0);
  EXPECT(assert_equal(expected,y1));
  EXPECT(assert_equal(expected,Vector(y2)));
}

/* ************************************************************************* */
TEST( TestVector, equals )
{
  Vector v1 = (Vector(1) << 0.0/std::numeric_limits<double>::quiet_NaN()); //testing nan
  Vector v2 = (Vector(1) << 1.0);
  double tol = 1.;
  EXPECT(!equal_with_abs_tol(v1, v2, tol));
}

/* ************************************************************************* */
TEST( TestVector, greater_than )
{
  Vector v1 = (Vector(3) << 1.0, 2.0, 3.0),
       v2 = zero(3);
  EXPECT(greaterThanOrEqual(v1, v1)); // test basic greater than
  EXPECT(greaterThanOrEqual(v1, v2)); // test equals
}

/* ************************************************************************* */
TEST( TestVector, reciprocal )
{
  Vector v = (Vector(3) << 1.0, 2.0, 4.0);
  EXPECT(assert_equal((Vector(3) << 1.0, 0.5, 0.25),reciprocal(v)));
}

/* ************************************************************************* */
TEST( TestVector, linear_dependent )
{
  Vector v1 = (Vector(3) << 1.0, 2.0, 3.0);
  Vector v2 = (Vector(3) << -2.0, -4.0, -6.0);
  EXPECT(linear_dependent(v1, v2));
}

/* ************************************************************************* */
TEST( TestVector, linear_dependent2 )
{
  Vector v1 = (Vector(3) << 0.0, 2.0, 0.0);
  Vector v2 = (Vector(3) << 0.0, -4.0, 0.0);
  EXPECT(linear_dependent(v1, v2));
}

/* ************************************************************************* */
TEST( TestVector, linear_dependent3 )
{
  Vector v1 = (Vector(3) << 0.0, 2.0, 0.0);
  Vector v2 = (Vector(3) << 0.1, -4.1, 0.0);
  EXPECT(!linear_dependent(v1, v2));
}

/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
/* ************************************************************************* */


///
/// Boost コルーチン サンプル(フィボナッチ数)
///
///

#include <iostream>
#include <boost/coroutine2/coroutine.hpp>

/// フィボナッチ数
///
///     F(0) = 0
///     F(1) = 1
///     F(n) = F(n-1) + F(n-2)
///
void fibonacci(boost::coroutines2::coroutine<int>::push_type& yield)
{
    yield(0);
    yield(1);

    int prepre = 0;
    int pre = 1;
    for (int cnt = 0 ; cnt < 8 ; cnt++) {
        auto cur = prepre + pre;
        yield(cur);
        prepre = pre;
        pre = cur;
    }
}

void fibonacci_limit(boost::coroutines2::coroutine<int>::push_type& yield, int limit)
{
    yield(0);
    yield(1);

    int prepre = 0;
    int pre = 1;
    for (int cnt = 0 ; cnt < limit ; cnt++) {
        auto cur = prepre + pre;
        yield(cur);
        prepre = pre;
        pre = cur;
    }
}

int main()
{
    boost::coroutines2::coroutine<int>::pull_type source(fibonacci);

    for (; source ; source()) {
        std::cout << source.get() <<  " ";
    }
    std::cout << std::endl;

    source = boost::coroutines2::coroutine<int>::pull_type(fibonacci);
    for (auto num : source) {
        std::cout << num <<  " ";
    }
    std::cout << std::endl;

    boost::coroutines2::coroutine<int>::pull_type source2(
        [](auto & yield){fibonacci_limit(yield, 10);});

    for (auto num : source2) {
        std::cout << num <<  " ";
    }
    std::cout << std::endl;

    return 0;
}


/***
* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
* Distributed under the MIT Software License.
* See accompanying file LICENSE.txt or copy at
* https://opensource.org/licenses/MIT
***/

#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <stdexcept>
#include <algorithm>
#include <iomanip>

#include <boost/cstdint.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

#include "disturbancevector.hpp"
#include "saveload.hpp"

namespace po = boost::program_options;
namespace fs = boost::filesystem;

using namespace std;

typedef boost::uint32_t uint32;

class bitrel;
map<string,bitrel> gl_map_DV_bitrels;

vector<string> break_string(string in, const string& delim)
{
	vector<string> ret;
	size_t pos = in.find_first_of(delim);
	while (pos < in.size())
	{
		ret.push_back(in.substr(0, pos));
		in.erase(0, pos+1);
		pos = in.find_first_of(delim);
	}
	ret.push_back(in);
	return ret;
}

vector<uint32> operator^(const vector<uint32>& l, const vector<uint32>& r)
{
	if (l.size() != r.size())
		throw runtime_error("vector xor undefined for unequal length vectors");

	vector<uint32> ret(l);
	for (unsigned i = 0; i < ret.size(); ++i)
		ret[i] ^= r[i];

	return ret;
}

vector<uint32>& operator^=(vector<uint32>& l, const vector<uint32>& r)
{
	if (l.size() != r.size())
		throw runtime_error("vector xor undefined for unequal length vectors");

	for (unsigned i = 0; i < l.size(); ++i)
		l[i] ^= r[i];

	return l;
}

class bitrel
{
public:
	vector< vector<uint32> > basis; // 80 wordmasks + LSB 81-th word as parity

	size_t size() const
	{
		return basis.size();
	}

	void clear()
	{
		basis.clear();
	}

	vector< vector<uint32> > space(unsigned len = 81) const
	{
		vector< vector<uint32> > tmp;
		if (basis.size() == 0)
			return tmp;

		// skip the zero vector: start with i=1
		for (uint32 i = 1; i < uint32(1<<basis.size()); ++i)
		{
			vector<uint32> elem(basis.front().size(), 0);

			for (uint32 j = 0; j < basis.size(); ++j)
				if (i & (1<<j))
					elem ^= basis[j];

			elem.resize(len);
			tmp.push_back(elem);
		}

		std::sort(tmp.begin(), tmp.end());
		tmp.erase( std::unique(tmp.begin(),tmp.end()), tmp.end());
		return tmp;
	}

	template<typename Archive>
	void serialize(Archive& ar, const unsigned int file_version)
	{
		ar & boost::serialization::make_nvp("basis", basis);
	}
};

string bitrel_to_string(const vector<uint32>& br)
{
	string ret;

	for (unsigned t = 0; t < 80; ++t)
		if (br[t])
			for (unsigned b = 0; b < 32; ++b)
				if ((br[t]>>b)&1)
					ret += string(ret.empty() ? "W" : " ^ W") + to_string(t) + "[" + to_string(b) + "]";

	if (br.size() > 80)
		ret += " = " + to_string(br[80]&1);
	return ret;
}

vector<uint32> parse_bitrel_line(string in)
{
	//exampleline: - W37[4] ^ W39[4] = 1
	vector<uint32> br(81,0); // 80 wordmasks plus parity

	size_t pos = in.find("=");
	if ((pos = in.find_first_of("01", pos)) == string::npos)
		throw;
	if (in[pos] == '1')
		br[80] = 1;

	in.erase(pos);
	while (true)
	{
		if ((pos = in.find_first_of("0123456789")) == string::npos)
			break;

		size_t pos2 = in.find_first_not_of("0123456789", pos);
		unsigned t = stoul(in.substr(pos, pos2-pos));

		if ((pos = in.find_first_of("0123456789", pos2)) == string::npos)
			break;

		pos2 = in.find_first_not_of("0123456789", pos);
		unsigned b = stoul(in.substr(pos, pos2-pos));

		if (t >= 80 || b >= 32)
			throw runtime_error("t or b out of bounds");
		br[t] ^= uint32(1)<<b;

		in.erase(0, pos2);
	}
	return br;
}

void load_bitrel(bitrel& br, const fs::path& filename)
{
	br.clear();
	ifstream ifs(filename.native());
	while (!!ifs)
	{
		string line;
		getline(ifs, line);
		if (line.find("=") != string::npos)
			br.basis.push_back( parse_bitrel_line(line) );
	}
}

string filename_to_DV(const fs::path& filename)
{
	vector<string> DV = break_string( filename.stem().string() , "_-");
	if ( DV.size() >= 3
		&& (DV[0] == "I" || DV[0] == "II")
		&& DV[1].find_first_not_of("0123456789") == string::npos
		&& DV[2].find_first_not_of("0123456789") == string::npos
		)
	{
		return DV[0] + "(" + DV[1] + "," + DV[2] + ")";
	}
	throw runtime_error("Filename does not contain DV description");
}

void load_bitrels(std::map<string,bitrel>& map_DV_bitrels, const string& workdir, const set<string>& DVselection)
{
	cout << "Loading bit relation data for DVs from directory " << workdir << endl;
	fs::path basedir = workdir;
	if (!fs::is_directory(basedir))
		throw runtime_error("Specified workdir is not a directory");

	for (auto dit = fs::directory_iterator(basedir); dit != fs::directory_iterator(); ++dit)
	{
		if (fs::is_regular_file(dit->path()))
		{
			string DV = filename_to_DV(dit->path());
			if (!DVselection.empty())
			{
				bool ok = false;
				for (auto it = DVselection.begin(); it != DVselection.end(); ++it)
				{
					if ((dit->path().stem().string().find(*it) != string::npos || DV.find(*it) != string::npos)
						&& dit->path().stem().string().find("I" + *it) == string::npos
						&& DV.find("I" + *it) == string::npos
						)
						ok = true;
				}
				if (!ok) continue;
			}

			cout << DV << ": " << flush;
			load_bitrel(map_DV_bitrels[DV], dit->path());
			cout << map_DV_bitrels[DV].size() << endl;
		}
	}
}

unsigned hammingweight(uint32 in)
{
	unsigned c = 0;
	for (; in; ++c)
		in &= in - 1;
	return c;
}

unsigned hammingweight(const vector<uint32>& in)
{
	unsigned c = 0;
	for (auto i = in.begin(); i != in.end(); ++i)
		c += hammingweight(*i);
	return c;
}

bool basis_less(const std::vector<uint32>& l, const std::vector<uint32>& r)
{
	// first: rate on total # active bits
	unsigned hwl = hammingweight(l), hwr = hammingweight(r);
	if (hwl != hwr)
		return hwl < hwr;

	// second: rate on # active bit positions
	uint32 bitsl = 0, bitsr = 0;
	for (auto it = l.begin(); it != l.end(); ++it)
		bitsl |= *it;
	for (auto it = r.begin(); it != r.end(); ++it)
		bitsr |= *it;
	hwl = hammingweight(bitsl);
	hwr = hammingweight(bitsr);
	if (hwl != hwr)
		return hwl < hwr;

	// third: rate on maximum worddistance between active bits
	int fl = 0, fr = 0;
	while (fl < (int)l.size() && l[fl] == 0)
		++fl;
	while (fr < (int)r.size() && r[fr] == 0)
		++fr;
	int el = l.size()-1, er = r.size()-1;
	while (el > 0 && l[el] == 0)
		--el;
	while (er > 0 && r[er] == 0)
		--er;
	if ((el-fl) != (er-fr))
		return (el-fl) < (er-fr);

	// fourth: lex
	return l < r;
}

void greedy_selection(const map<string,bitrel>& map_DV_bitrels, map<vector<uint32>, vector<string> >& bitrel_to_DV)
{
	map<string,bitrel> map_DV_newbitrels;

	while (true)
	{
		map<vector<uint32>, vector<string> > bitrelcnt;
		map<vector<uint32>, vector<string> > bitrelcnt2;
		for (auto DVit = map_DV_bitrels.begin(); DVit != map_DV_bitrels.end(); ++DVit)
		{
			vector< vector<uint32> > fullspace = DVit->second.space(81); // 81 and 80 give the same results => all bitrel do not have negated version for other DV (so far)
			vector< vector<uint32> > selspace = map_DV_newbitrels[DVit->first].space(81);
			for (auto it = fullspace.begin(); it != fullspace.end(); ++it)
			{
				if (!binary_search(selspace.begin(), selspace.end(), *it))
					bitrelcnt[*it].push_back(DVit->first);
				bitrelcnt2[*it].push_back(DVit->first);
			}
		}

		uint32 maxcnt = 0;
		for (auto it = bitrelcnt.begin(); it != bitrelcnt.end(); ++it)
			if (it->second.size() > maxcnt)
				maxcnt = it->second.size();
		if (maxcnt == 0) break;

		vector< vector<uint32> > maxbitrel;
		for (auto it = bitrelcnt.begin(); it != bitrelcnt.end(); ++it)
			if (it->second.size() == maxcnt)
				maxbitrel.push_back(it->first);
		std::sort(maxbitrel.begin(), maxbitrel.end(), basis_less);

		vector<uint32> newbitrel = maxbitrel.front();
		vector<string>& newbitrelDVs = bitrel_to_DV[newbitrel];
		cout << "- " << bitrel_to_string(newbitrel) << ": ";
		for (auto it = bitrelcnt[newbitrel].begin(); it != bitrelcnt[newbitrel].end(); ++it)
		{
			cout << " " << *it;
			newbitrelDVs.push_back(*it);
			map_DV_newbitrels[*it].basis.push_back(newbitrel);
		}
		cout << " (+" << (bitrelcnt2[newbitrel].size()-bitrelcnt[newbitrel].size()) << "DVs)" << endl;
		std::sort(newbitrelDVs.begin(), newbitrelDVs.end());
	}

	for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
	{
		bool first = true;
		for (auto it2 = bitrel_to_DV.begin(); it2 != bitrel_to_DV.end(); ++it2)
		{
			if (it2 != it && it2->second.size() > 1)
			{
				bool ok = true;
				for (auto it3 = it2->second.begin(); it3 != it2->second.end(); ++it3)
				{
					if (!binary_search(it->second.begin(), it->second.end(), *it3))
					{
						ok = false;
						break;
					}
				}
				if (!ok)
					continue;

				// it2 is subset of it1
				if (first)
				{
					first = false;
					cout << bitrel_to_string(it->first) << " (" << it->second.size() << ") => ";
				}
				else
					cout << " , ";
				cout << bitrel_to_string(it2->first) << " (" << it2->second.size() << ")";
			}
		}
		if (!first)
			cout << endl;
	}
}

string DVvariablename(const string& DV, const string& suffix = "", const string& prefix = "DV_")
{
	string ret = prefix + DV + suffix;
	size_t pos;
	while ( (pos = ret.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")) < ret.size())
		ret[pos] = '_';
	return ret;
}

// returns c expression that should be evaluated as bool (i.e., zero / non-zero integer)
string bitrel_bool_expression(const vector<uint32>& bitrel, const string& Wname = "W")
{
	string ret;
	if ((hammingweight(bitrel) - hammingweight(bitrel[80])) != 2)
		throw std::runtime_error("bitrel_bool_expression(,): expected bitrelation with only 2 active W bits");
	unsigned t1 = 0,t2 = 79;
	while (bitrel[t1] == 0)
		++t1;
	while (bitrel[t2] == 0)
		--t2;
	int b1 = 0, b2 = 31;
	while (0 == ((bitrel[t1]>>b1)&1))
		++b1;
	while (0 == ((bitrel[t2]>>b2)&1))
		--b2;

	// shift W[t2] bit position b2 to bit position b1, then xor W2 and W1 and keep only bit position b1
	string W1 = Wname + "[" + boost::lexical_cast<string>(t1) + "]";
	string W2 = Wname + "[" + boost::lexical_cast<string>(t2) + "]";

	if (b1 > b2)
		W2 = "(" + W2 + "<<" + boost::lexical_cast<string>(b1-b2) + ")";
	else if (b2 > b1)
		W2 = "(" + W2 + ">>" + boost::lexical_cast<string>(b2-b1) + ")";

	ret = "((" + W1 + "^" + W2 + ") & (1<<" + boost::lexical_cast<string>(b1) + "))";

	if (bitrel[80] != 0)
		return ret;
	else
		return "(!" + ret + ")"; // use ! instead of ~ (e.g. ~W2) since ! can be absorbed into jz or jnz
}

// return c expression that if true returns 0xFFFFFFFF and else 0
string bitrel_c_expression(const vector<uint32>& bitrel, const string& Wname = "W")
{
	if ((hammingweight(bitrel) - hammingweight(bitrel[80])) != 2)
		throw std::runtime_error("bitrel_c_expression(,): expected bitrelation with only 2 active W bits");
	unsigned t1 = 0,t2 = 79;
	while (bitrel[t1] == 0)
		++t1;
	while (bitrel[t2] == 0)
		--t2;
	int b1 = 0, b2 = 31;
	while (0 == ((bitrel[t1]>>b1)&1))
		++b1;
	while (0 == ((bitrel[t2]>>b2)&1))
		--b2;

	// shift W[t2] bit position b2 to bit position b1, then xor W2 and W1 and keep only bit position b1
	string W1 = Wname + "[" + boost::lexical_cast<string>(t1) + "]";
	string W2 = Wname + "[" + boost::lexical_cast<string>(t2) + "]";

	if (b1 == b2)
		return "(0-(((" + W1 + "^" + (bitrel[80]==0?"~":"") + W2 + ")>>" + boost::lexical_cast<string>(b1) + ")&1))";
	else
		return "(0-(((" + W1 + ">>" + boost::lexical_cast<string>(b1) + ")^(" + (bitrel[80]==0?"~":"") + W2 + ">>" + boost::lexical_cast<string>(b2) + "))&1))";
}

// returns c expression that sets bits in the closed-range [lowbit,highbit] to 1 if true and 0 else
// bits lower than lowbit and bits higher than highbit are undetermined (may be 0 or 1 independent of each other)
string bitrel_c_expression(const vector<uint32>& bitrel, unsigned lowbit, unsigned highbit, const string& Wname = "W")
{
	if ((hammingweight(bitrel) - hammingweight(bitrel[80])) != 2)
		throw std::runtime_error("bitrel_c_expression(,,,): expected bitrelation with only 2 active W bits");
	unsigned t1 = 0,t2 = 79;
	while (bitrel[t1] == 0)
		++t1;
	while (bitrel[t2] == 0)
		--t2;
	unsigned b1 = 0, b2 = 31;
	while (0 == ((bitrel[t1]>>b1)&1))
		++b1;
	while (0 == ((bitrel[t2]>>b2)&1))
		--b2;

	// shift W[t2] bit position b2 to bit position b1, then xor W2 and W1 and keep only bit position b1
	string W1 = Wname + "[" + boost::lexical_cast<string>(t1) + "]";
	string W2 = Wname + "[" + boost::lexical_cast<string>(t2) + "]";
	// make b1 the lowest bitposition
	if (b1 > b2) {
		std::swap(t1,t2);
		std::swap(b1,b2);
		std::swap(W1,W2);
	}

	string ret;

	if (lowbit == highbit)
	{
		// we can avoid expanding a bit to a full mask, i.e., avoiding an AND and a NEG
		if (b1 == b2)
		{
			ret = "(" + W1 + "^"  + W2 + ")";
			if (b1 < lowbit)
				ret = "(" + ret + "<<" + boost::lexical_cast<string>(lowbit - b1) + ")";
			if (b1 > lowbit)
				ret = "(" + ret + ">>" + boost::lexical_cast<string>(b1 - lowbit) + ")";
			return "(" + string(bitrel[80]==0?"~":"") + ret + ")";
		}
		if (b1 < lowbit)
			W1 = "(" + W1 + "<<" + boost::lexical_cast<string>(lowbit - b1) + ")";
		if (b1 > lowbit)
			W1 = "(" + W1 + ">>" + boost::lexical_cast<string>(b1 - lowbit) + ")";
		if (b2 < lowbit)
			W2 = "(" + W2 + "<<" + boost::lexical_cast<string>(lowbit - b2) + ")";
		if (b2 > lowbit)
			W2 = "(" + W2 + ">>" + boost::lexical_cast<string>(b2 - lowbit) + ")";
		return "(" + string(bitrel[80]==0?"~":"") + "(" + W1 + "^"  + W2 + "))";
	}

	if (b1 <= lowbit)
	{
		if (b2 != b1) W2 = "(" + W2 + ">>" + boost::lexical_cast<string>(b2-b1) + ")";
			ret = "((" + W1 + "^" + W2 + ")&(1<<" + boost::lexical_cast<string>(b1) + "))";
		if (bitrel[80]==0)
			return "(" + ret + "-(1<<" + boost::lexical_cast<string>(b1) + "))";
		else
			return "(0-" + ret + ")";
	}

	if (b1 == b2)
		ret = "(((" + W1 + "^" + W2 + ")>>" + boost::lexical_cast<string>(b1) + ")&1)";
	else
		ret = "(((" + W1 + ">>" + boost::lexical_cast<string>(b1) + ")^(" + W2 + ">>" + boost::lexical_cast<string>(b2) + "))&1)";
	if (bitrel[80]==0)
		return "(" + ret + "-1)";
	else
		return "(0-" + ret + ")";
}

// returns c expression that sets bits in the closed-range [lowbit,highbit] to 1 if true and 0 else
// bits lower than lowbit and bits higher than highbit are undetermined (may be 0 or 1 independent of each other)
string bitrel_simd_expression(const vector<uint32>& bitrel, unsigned lowbit, unsigned highbit, const string& Wname = "W")
{
	if ((hammingweight(bitrel) - hammingweight(bitrel[80])) != 2)
		throw std::runtime_error("bitrel_c_expression(,,,): expected bitrelation with only 2 active W bits");
	unsigned t1 = 0, t2 = 79;
	while (bitrel[t1] == 0)
		++t1;
	while (bitrel[t2] == 0)
		--t2;
	unsigned b1 = 0, b2 = 31;
	while (0 == ((bitrel[t1] >> b1) & 1))
		++b1;
	while (0 == ((bitrel[t2] >> b2) & 1))
		--b2;

	// shift W[t2] bit position b2 to bit position b1, then xor W2 and W1 and keep only bit position b1
	string W1 = Wname + "[" + boost::lexical_cast<string>(t1)+"]";
	string W2 = Wname + "[" + boost::lexical_cast<string>(t2)+"]";
	// make b1 the lowest bitposition
	if (b1 > b2) {
		std::swap(t1, t2);
		std::swap(b1, b2);
		std::swap(W1, W2);
	}

	string ret;

	if (lowbit == highbit)
	{
		// we can avoid expanding a bit to a full mask, i.e., avoiding an AND and a NEG
		if (b1 == b2)
		{
			ret = "SIMD_XOR_VV(" + W1 + "," + W2 + ")";
			if (b1 < lowbit)
				ret = "SIMD_SHL_V(" + ret + "," + boost::lexical_cast<string>(lowbit - b1) + ")";
			if (b1 > lowbit)
				ret = "SIMD_SHR_V(" + ret + "," + boost::lexical_cast<string>(b1 - lowbit) + ")";
			if (bitrel[80] == 0)
				return "SIMD_NOT_V(" + ret + ")";
			return ret;
		}
		if (b1 < lowbit)
			W1 = "SIMD_SHL_V(" + W1 + "," + boost::lexical_cast<string>(lowbit - b1) + ")";
		if (b1 > lowbit)
			W1 = "SIMD_SHR_V(" + W1 + "," + boost::lexical_cast<string>(b1 - lowbit) + ")";
		if (b2 < lowbit)
			W2 = "SIMD_SHL_V(" + W2 + "," + boost::lexical_cast<string>(lowbit - b2) + ")";
		if (b2 > lowbit)
			W2 = "SIMD_SHR_V(" + W2 + "," + boost::lexical_cast<string>(b2 - lowbit) + ")";
		return string(bitrel[80]==0 ? "SIMD_NOT_V(" : "(") + "SIMD_XOR_VV(" + W1 + "," + W2 + "))";
	}

	if (b1 <= lowbit)
	{
		if (b2 != b1)
			W2 = "SIMD_SHR_V(" + W2 + "," + boost::lexical_cast<string>(b2 - b1) + ")";
		ret = "SIMD_AND_VW(SIMD_XOR_VV(" + W1 + "," + W2 + "),(1<<" + boost::lexical_cast<string>(b1)+"))";
		if (bitrel[80] == 0)
			return "SIMD_SUB_VW(" + ret + ",(1<<" + boost::lexical_cast<string>(b1)+"))";
		else
			return "SIMD_NEG_V(" + ret + ")";
	}

	if (b1 == b2)
		ret = "SIMD_AND_VW(SIMD_SHR_V(SIMD_XOR_VV(" + W1 + "," + W2 + ")," + boost::lexical_cast<string>(b1)+"),1)";
	else
		ret = "SIMD_AND_VW(SIMD_XOR_VV(SIMD_SHR_V(" + W1 + "," + boost::lexical_cast<string>(b1)+"),SIMD_SHR_V(" + W2 + "," + boost::lexical_cast<string>(b2)+")),1)";
	if (bitrel[80] == 0)
		return "SIMD_SUB_VW(" + ret + ",1)";
	else
		return "SIMD_NEG_V(" + ret + ")";
}

// as a safety precaution, valid testt have zero-diff-state before and after
// depending on implementation, one could add one additional testt either at the beginning or at the end

// in libdetectcoll using step t to test means copying the state between steps t-1 and t of the original run
// and recomputing steps t-1,...,0 backwards and steps t,...,79 forwards
map<string,int> find_testt(const map<string,disturbancevector>& DVs, const map<vector<uint32>, vector<string> >& bitrel_to_DV)
{
	set<string> allDVs;
	map<string,unsigned> DV_nrbitrel;
	for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
	{
		for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
		{
			++DV_nrbitrel[*it2];
			allDVs.insert(*it2);
		}
	}

	map<int,set<string> > t_count;
	for (auto it = DVs.begin(); it != DVs.end(); ++it)
	{
		allDVs.insert(it->first);
		if (it->second.dvtype == 1)
		{
			for (int t = it->second.dvk+5; t <= it->second.dvk+15; ++t)
				t_count[t].insert(it->first);
		}
		else if (it->second.dvtype == 2)
		{
			for (int t = it->second.dvk+9; t <= it->second.dvk+15; ++t)
				t_count[t].insert(it->first);
		}
		else
			throw std::runtime_error("find_testt(): unknown dv type");
	}

	// find smallest set solutions
	map< set<int>, double > solutionst;
	for (unsigned cnt = 1 ; solutionst.size()==0 ; ++cnt)
	{
		vector<bool> sett(t_count.size(), false);
		for (unsigned i = 0; i < cnt; ++i)
			sett[i] = true;
		while (true)
		{
			set<int> ts_covered;
			set<string> DVs_covered;
			for (unsigned i = 0; i < t_count.size(); ++i)
			{
				if (sett[i])
				{
					auto it = t_count.begin(); std::advance(it, i);
					ts_covered.insert(it->first);
					DVs_covered.insert(it->second.begin(), it->second.end());
				}
			}
			if (DVs_covered == allDVs)
				solutionst[ts_covered]=0.0;
			// next permutation in sett
			unsigned j = 0;
			while (j < t_count.size() && sett[j] != true)
				++j;
			while (j < t_count.size() && sett[j] != false)
				++j;
			// j points to the first 0 after a 1 has occured
			if (j >= t_count.size())
				break; // no next permutation
			// move last 1 prior to j to j-th position
			sett[j] = true;
			sett[j-1] = false;
			// all other previous 1's move to the beginning
			unsigned k = 0;
			for (unsigned l = 0; l < j - 1; ++l)
			{
				if (sett[l])
				{
					std::swap(sett[k], sett[l]);
					++k;
				}
			}
		}
	}
	cout << "Found " << solutionst.size() << " solutions of size " << solutionst.begin()->first.size() << endl;

	// rate solutions
	// TODO

	// return best solution
	set<int> solt = solutionst.begin()->first;
	map<string,int> sol;
	for (auto it = solt.begin(); it != solt.end(); ++it)
		for (auto it2 = t_count[*it].begin(); it2 != t_count[*it].end(); ++it2)
			sol[*it2] = *it;
	return sol;
}

void output_code_header(map<string, unsigned>& DV_to_bitpos, const map<vector<uint32>, vector<string> >& bitrel_to_DV, ostream& out_h, ostream& out_c, ostream& out_c_test)
{
	unsigned dvmasksize = ((DV_to_bitpos.size() + 31) / 32);

	map<string, disturbancevector> DVs;
	for (auto it = DV_to_bitpos.begin(); it != DV_to_bitpos.end(); ++it)
		DVs.emplace(it->first, disturbancevector(it->first));
	// figure out distribution of testts: minimum #, balanced distribution of DVs
	map<string, int> DV_testt = find_testt(DVs, bitrel_to_DV);
	set<int> testt;
	for (auto it = DV_testt.begin(); it != DV_testt.end(); ++it)
		testt.insert(it->second);

	out_h << "#ifndef UBC_CHECK_H" << endl;
	out_h << "#define UBC_CHECK_H" << endl << endl;
	out_h << "#include <stdint.h>" << endl << endl;
	out_h << "#define DVMASKSIZE " << dvmasksize << endl;
	out_h << "typedef struct { int dvType; int dvK; int dvB; int testt; int maski; int maskb; uint32_t dm[80]; } dv_info_t;" << endl;
	out_h << "extern dv_info_t sha1_dvs[];" << endl;
	out_h << "void ubc_check(const uint32_t W[80], uint32_t dvmask[DVMASKSIZE]);" << endl;

	out_h << endl;
	for (auto it = testt.begin(); it != testt.end(); ++it)
		out_h << "#define DOSTORESTATE" << std::setw(2) << std::setfill('0') << *it << endl;
	out_h << endl;

	out_h << endl << "#endif // UBC_CHECK_H" << endl;

	string inttype = (DV_to_bitpos.size() <= 32) ? "uint32_t" : "uint64_t";
	out_c
		<< "#include <stdint.h>" << endl
		<< "#include \"ubc_check.h\"" << endl
		<< endl;
	for (auto it = DV_to_bitpos.begin(); it != DV_to_bitpos.end(); ++it)
		out_c << "static const " << inttype << " " << DVvariablename(it->first, "bit") << " \t= (" << inttype << ")(1) << " << it->second << ";" << endl;
	out_c << endl;

	out_c << "dv_info_t sha1_dvs[] = \n{" << endl;
	for (auto it = DVs.begin(); it != DVs.end(); ++it)
	{
		out_c << ((it == DVs.begin())?"  ":", ");
		out_c << "{" << it->second.dvtype << "," << it->second.dvk << "," << it->second.dvb << "," << DV_testt[it->first] << "," << (DV_to_bitpos[it->first]/32) << "," << (DV_to_bitpos[it->first]%32) << ", { ";
		for (int t = 0; t < 80; ++t)
			out_c << ((t!=0)?",":"") << "0x" << std::hex << std::setfill('0') << std::setw(8) << it->second.DW[t] << std::dec;
		out_c << " } }" << endl;
	}
	out_c << ", {0,0,0,0,0,0, {0";
	for (int i = 1; i < 80; ++i)
		out_c << ",0";
	out_c << "}}\n};" << endl;

	out_c_test
		<< "#include <stdint.h>" << endl
		<< "#include \"ubc_check.h\"" << endl
		<< endl;

	out_c_test
		<< "void ubc_check_verify(const uint32_t W[80], uint32_t dvmask[DVMASKSIZE])\n{" << endl
		<< "\tfor (unsigned i=0; i < DVMASKSIZE; ++i)\n\t\tdvmask[i]=0xFFFFFFFF;\n\n";
	for (auto DVit = gl_map_DV_bitrels.begin(); DVit != gl_map_DV_bitrels.end(); ++DVit)
	{
		out_c_test << "\tif (\t   ";
		for (auto it = DVit->second.basis.begin(); it != DVit->second.basis.end(); ++it)
		{
			if (it != DVit->second.basis.begin())
				out_c_test << "\t\t|| ";
			out_c_test << "(0";
			for (unsigned i = 0; i < 80; ++i)
			{
				for (unsigned b = 0; b < 32; ++b)
				{
					if ((*it)[i] & (1 << b))
					{
						out_c_test << "^((W[" << i << "]>>" << b << ")&1)";
					}
				}
			}
			out_c_test << ")!=" << (((*it)[80]) ? "1" : "0") << endl;
		}
		out_c_test << "\t\t)\n\t\t\tdvmask[" << (DV_to_bitpos[DVit->first] / 32) << "] &= ~((uint32_t)(1<<" << (DV_to_bitpos[DVit->first] % 32) << "));\n" << endl;
	}
	out_c_test << "}" << endl;
}

void output_code_simd(const map<vector<uint32>, vector<string> >& bitrel_to_DV, ostream& out_c)
{
	cout << "Generating code..." << endl;

	map<string, unsigned> DV_to_bitpos;
	for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
		for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			DV_to_bitpos[*it2];
	unsigned DVcnt = 0;
	for (auto it = DV_to_bitpos.begin(); it != DV_to_bitpos.end(); ++it, ++DVcnt)
		it->second = DVcnt;
	if (DVcnt > 64)
	{
		cerr << "Error: Integer type with more than 64 bits required..." << endl;
		return;
	}
	string inttype = (DV_to_bitpos.size() <= 32) ? "uint32_t" : "uint64_t";

	out_c << "#include \"ubc_check.h\"" << endl;
	out_c << endl;
	for (auto it = DV_to_bitpos.begin(); it != DV_to_bitpos.end(); ++it)
		out_c << "static const " << inttype << " " << DVvariablename(it->first, "bit") << " \t= (" << inttype << ")(1) << " << it->second << ";" << endl;
	out_c << endl;
	out_c << "void UBC_CHECK_SIMD(const SIMD_WORD* W, SIMD_WORD* dvmask)" << endl;
	out_c << "{" << endl;
	out_c << "\tSIMD_WORD mask = SIMD_WTOV(0xFFFFFFFF);" << endl;

	for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
	{
		unsigned lowbit = 31, highbit = 0;
		string DVsmask = "(";
		for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
		{
			DVsmask += (it2 == it->second.begin() ? "" : "|") + DVvariablename(*it2, "bit");
			if (DV_to_bitpos[*it2] < lowbit)
				lowbit = DV_to_bitpos[*it2];
			if (DV_to_bitpos[*it2] > highbit)
				highbit = DV_to_bitpos[*it2];
		}
		DVsmask += ")";
		out_c << "\tmask = SIMD_AND_VV(mask, SIMD_OR_VW(" << bitrel_simd_expression(it->first, lowbit, highbit) << ", ~" << DVsmask << "));" << endl;
	}

	out_c << "\tdvmask[0]=mask;" << endl;
	out_c << "}" << endl;;
}

void output_code_v1(const map<vector<uint32>, vector<string> >& bitrel_to_DV, ostream& out_h, ostream& out_c, ostream& out_c_test, unsigned minDVs = 1)
{
	cout << "Generating code..." << endl;

	map<string, unsigned> DV_to_bitpos;
	for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
		for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			DV_to_bitpos[*it2];
	unsigned DVcnt = 0;
	for (auto it = DV_to_bitpos.begin(); it != DV_to_bitpos.end(); ++it,++DVcnt)
		it->second = DVcnt;
	if (DVcnt > 64)
	{
		cerr << "Error: Integer type with more than 64 bits required..." << endl;
		return;
	}
	string inttype = (DV_to_bitpos.size() <= 32) ? "uint32_t" : "uint64_t";

	output_code_header(DV_to_bitpos, bitrel_to_DV, out_h, out_c, out_c_test);

	out_c << "void ubc_check(const uint32_t W[80], uint32_t dvmask[" << ((DV_to_bitpos.size()+31)/32)<< "])\n{\n\t" << inttype << " mask = ~((" << inttype << ")(0));\n";

	// first process all multi-DV bitrels
	out_c << "\tmask = mask\n";
	//  for (unsigned nrdvs = DVcnt; nrdvs >= minDVs; --nrdvs)
	for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
		if (it->second.size() >= minDVs)
		{
			unsigned lowbit = 31, highbit = 0;
			string DVsmask = "(";
			for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			{
				DVsmask += (it2==it->second.begin()?"":"|") + DVvariablename(*it2, "bit");
				if (DV_to_bitpos[*it2] < lowbit)
					lowbit = DV_to_bitpos[*it2];
				if (DV_to_bitpos[*it2] > highbit)
					highbit = DV_to_bitpos[*it2];
			}
			DVsmask += ")";
			out_c << "\t\t & ( " << bitrel_c_expression(it->first,lowbit,highbit) << " | ~" << DVsmask << ")" << endl;
		}
	out_c << "\t\t;\n\n";

	if (minDVs > 1)
		out_c << "if (mask) {\n" << endl;
	// now conditionally process remaining DV-specific bitrels
	for (auto DVit = DV_to_bitpos.begin(); DVit != DV_to_bitpos.end(); ++DVit)
	{
		unsigned bitrelcnt = 0;
		for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
			if (it->second.size() < minDVs && std::find(it->second.begin(),it->second.end(),DVit->first)!=it->second.end())
				++bitrelcnt;
		if (bitrelcnt == 0)
			continue;

		out_c << "\tif (mask & " << DVvariablename(DVit->first, "bit") << ")\n";
		out_c << "\t\t if (\n";
		bool first = true;
		for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
			if (it->second.size() < minDVs && std::find(it->second.begin(),it->second.end(),DVit->first)!=it->second.end())
			{
				if (first)
				{
					out_c << "\t\t\t    ";
					first = false;
				} else
					out_c << "\t\t\t || ";
				out_c << "!" << bitrel_bool_expression(it->first) << "\n";
			}
		out_c << "\t\t )  mask &= ~" << DVvariablename(DVit->first, "bit") << ";\n";
	}
	if (minDVs > 1)
		out_c << "}\n" << endl;
	if (DVcnt <= 32)
		out_c << "\tdvmask[0]=mask;" << endl;
	else
		out_c << "\tdvmask[0]=(uint32_t)(mask);\n\tdvmask[1]=(uint32_t)(mask>>32);" << endl;
	out_c << "}" << endl;;
}

void output_code_v2(const map<vector<uint32>, vector<string> >& bitrel_to_DV, ostream& out_h, ostream& out_c, ostream& out_c_test, double minprob = 0.5)
{
	cout << "Generating code..." << endl;

	map<string, unsigned> DV_to_bitpos;
	for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
		for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			DV_to_bitpos[*it2];
	unsigned DVcnt = 0;
	for (auto it = DV_to_bitpos.begin(); it != DV_to_bitpos.end(); ++it,++DVcnt)
		it->second = DVcnt;
	if (DVcnt > 64)
	{
		cerr << "Error: Integer type with more than 64 bits required..." << endl;
		return;
	}
	string inttype = (DV_to_bitpos.size() <= 32) ? "uint32_t" : "uint64_t";

	output_code_header(DV_to_bitpos, bitrel_to_DV, out_h, out_c, out_c_test);

	out_c << "void ubc_check(const uint32_t W[80], uint32_t dvmask[" << ((DV_to_bitpos.size()+31)/32)<< "])\n{\n\t" << inttype << " mask = ~((" << inttype << ")(0));\n";

	// first process all multi-DV bitrels in order from most #DVs to only 2 DVs
	map<string, unsigned> DV_proc_bitrel_cnt;
	for (unsigned nrdvs = DVcnt; nrdvs > 1; --nrdvs)
	{
		for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
			if (it->second.size() == nrdvs)
			{
				double prob_ub_est = 0.0;
				unsigned lowbit = 31, highbit = 0;
				string DVsmask = "(";
				for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
				{
					DVsmask += (it2==it->second.begin()?"":"|") + DVvariablename(*it2, "bit");
					if (DV_to_bitpos[*it2] < lowbit)
						lowbit = DV_to_bitpos[*it2];
					if (DV_to_bitpos[*it2] > highbit)
						highbit = DV_to_bitpos[*it2];
					prob_ub_est += double(1)/double(1 << DV_proc_bitrel_cnt[*it2]);
					++DV_proc_bitrel_cnt[*it2];
				}
				DVsmask += ")";

#if 1
				if (prob_ub_est <= minprob)
					out_c << "\tif (mask & " + DVsmask + ")\n\t";
				out_c << "\tmask &= (" << bitrel_c_expression(it->first,lowbit,highbit) << " | ~" << DVsmask << ");" << endl;
#else
				if (prob_ub_est <= minprob)
					out_c << "\tif ((mask & " + DVsmask + ") && !" << bitrel_bool_expression(it->first) << ")" << endl;
				else
					out_c << "\tif (!" << bitrel_bool_expression(it->first) << ")" << endl;
				out_c << "\t\tmask &=  ~" + DVsmask + ";" << endl;
#endif
			}
	}

	out_c << "if (mask) {\n" << endl;
	// now conditionally process remaining DV-specific bitrels
	for (auto DVit = DV_to_bitpos.begin(); DVit != DV_to_bitpos.end(); ++DVit)
	{
		unsigned bitrelcnt = 0;
		for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
			if (it->second.size() == 1 && it->second.front() == DVit->first)
				++bitrelcnt;
		if (bitrelcnt == 0)
			continue;
		if (bitrelcnt == 1)
		{
			out_c << "\tif (mask & " << DVvariablename(DVit->first, "bit") << ")\n";
			unsigned bit=DVit->second;
			for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
				if (it->second.size() == 1 && it->second.front() == DVit->first)
					out_c << "\t\tmask &= (" << bitrel_c_expression(it->first,bit,bit) << " | ~" << DVvariablename(DVit->first, "bit") << ");" << endl;
			continue;
		}

		out_c << "\tif (mask & " << DVvariablename(DVit->first, "bit") << ")\n";
		out_c << "\t\t if (\n";
		bool first = true;
		for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
		{
			if (it->second.size() == 1 && it->second.front() == DVit->first)
			{
				if (first)
				{
					out_c << "\t\t\t    ";
					first = false;
				}
				else
					out_c << "\t\t\t || ";
				out_c << "!" << bitrel_bool_expression(it->first) << "\n";
			}
		}
		out_c << "\t\t )  mask &= ~" << DVvariablename(DVit->first, "bit") << ";\n";
	}
	out_c << "}\n" << endl;
	if (DVcnt <= 32)
		out_c << "\tdvmask[0]=mask;" << endl;
	else
		out_c << "\tdvmask[0]=(uint32_t)(mask);\n\tdvmask[1]=(uint32_t)(mask>>32);" << endl;
	out_c << "}" << endl;;
}

void output_code_v3(const map<vector<uint32>, vector<string> >& bitrel_to_DV, ostream& out_h, ostream& out_c, ostream& out_c_test)
{
	cout << "Generating code..." << endl;

	map<string, unsigned> DV_to_bitpos;
	for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
		for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
			DV_to_bitpos[*it2];
	unsigned DVcnt = 0;
	for (auto it = DV_to_bitpos.begin(); it != DV_to_bitpos.end(); ++it,++DVcnt)
		it->second = DVcnt;
	if (DVcnt > 64)
	{
		cerr << "Error: Integer type with more than 64 bits required..." << endl;
		return;
	}
	string inttype = (DV_to_bitpos.size() <= 32) ? "uint32_t" : "uint64_t";

	output_code_header(DV_to_bitpos, bitrel_to_DV, out_h, out_c, out_c_test);

	out_c << "void ubc_check(const uint32_t W[80], uint32_t dvmask[" << ((DV_to_bitpos.size()+31)/32)<< "])\n{\n\t" << inttype << " mask = ~((" << inttype << ")(0));\n";

	// now conditionally process remaining DV-specific bitrels
	for (auto DVit = DV_to_bitpos.begin(); DVit != DV_to_bitpos.end(); ++DVit)
	{
		unsigned bitrelcnt = 0;
		for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
			if (std::find(it->second.begin(), it->second.end(), DVit->first) != it->second.end())
				++bitrelcnt;
		if (bitrelcnt == 0)
			continue;

		out_c << "\t if (\t    ";
		bool first = true;
		for (auto it = bitrel_to_DV.begin(); it != bitrel_to_DV.end(); ++it)
		{
			if (std::find(it->second.begin(), it->second.end(), DVit->first) != it->second.end())
			{
				if (first)
					first = false;
				else
					out_c << "\t\t || ";
				out_c << "!" << bitrel_bool_expression(it->first) << "\n";
			}
		}
		out_c << "\t )  mask &= ~" << DVvariablename(DVit->first, "bit") << ";\n";
	}
	if (DVcnt <= 32)
		out_c << "\tdvmask[0]=mask;" << endl;
	else
		out_c << "\tdvmask[0]=(uint32_t)(mask);\n\tdvmask[1]=(uint32_t)(mask>>32);" << endl;
	out_c << "}" << endl;;
}

int main(int argc, char** argv)
{
	try
	{

		string ubcdir, outdir;
		vector<string> DVs;
		po::options_description desc("Allowed options");
		desc.add_options()
			("help,h", "Show options")
			("ubcdir,w", po::value<string>(&ubcdir)->default_value("../data/3565"), "Set directory containing ubc's for each DV")
			("outdir,o", po::value<string>(&outdir)->default_value("../../lib"), "Set directory to output ubc_check{.c,.h,_test.c}")
			("DV,d", po::value< vector<string> >(&DVs), "Select DVs (if not specified uses all DVs in workdir)")
			("store,s", "Store intermediate results")
			("load,l", "Load intermediate results")
			;
		po::variables_map vm;
		po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
		po::notify(vm);

		if (vm.count("help") || vm.count("ubcdir")==0)
		{
			cout << desc << endl;
			return 0;
		}

		set<string> DVselection(DVs.begin(), DVs.end());
		map<vector<uint32>, vector<string> > bitrel_to_DV;

		if (vm.count("load"))
		{
			vector<string> _DVs;
			set<string> _DVselection;
			map<string, bitrel> _gl_map_DV_bitrels;
			map<vector<uint32>, vector<string> > _bitrel_to_DV;
			try
			{
				cout << "Loading previously stored intermediate results." << flush;
				hc::load(_DVs, "data_DVs", hc::binary_archive); cout << "." << flush;
				hc::load(_gl_map_DV_bitrels, "data_map_DV_bitrels", hc::binary_archive); cout << "." << flush;
				hc::load(_DVselection, "data_DVselection", hc::binary_archive); cout << "." << flush;
				hc::load(_bitrel_to_DV, "data_bitrel_to_DV", hc::binary_archive); cout << "." << flush;
				cout << " done." << endl;
			}
			catch (std::exception&)
			{
				_bitrel_to_DV.clear();
				cout << " failed!" << endl;
			}
			if (!_bitrel_to_DV.empty())
			{
				DVs = std::move(_DVs);
				DVselection = std::move(_DVselection);
				gl_map_DV_bitrels = std::move(_gl_map_DV_bitrels);
				bitrel_to_DV = std::move(_bitrel_to_DV);
			}
		}

		if (bitrel_to_DV.empty())
		{
			load_bitrels(gl_map_DV_bitrels, ubcdir, DVselection);

			cout << "Applying greedy selection to exploit overlap of unavoidable bit relation space between DVs..." << endl;
			greedy_selection(gl_map_DV_bitrels, bitrel_to_DV);

			if (vm.count("store"))
			{
				cout << "Storing intermediate results" << flush;
				hc::save(DVs, "data_DVs", hc::binary_archive); cout << "." << flush;
				hc::save(gl_map_DV_bitrels, "data_map_DV_bitrels", hc::binary_archive); cout << "." << flush;
				hc::save(DVselection, "data_DVselection", hc::binary_archive); cout << "." << flush;
				hc::save(bitrel_to_DV, "data_bitrel_to_DV", hc::binary_archive); cout << "." << flush;
				cout << endl;
			}
		}

		// timings:
		// v2 (0.05) : 10.12s  // fastest
		// v1 (2)    : 12.41s
		// v1 (1)    : 16.18s  // constant-time
		// v3        : 25.55s
		double totc = 0;
		for (auto it = gl_map_DV_bitrels.begin(); it != gl_map_DV_bitrels.end(); ++it)
		{
			cout << it->first << ": " << it->second.basis.size() << endl;
			totc += double(1)/double(1<<it->second.basis.size());
		}
		cout << totc << " = 2^ " << log(totc)/log(2.0) << endl;

		cout << "Generating code files in directory " << outdir << endl;
		string c_name = outdir+"/ubc_check.c";
		string h_name = outdir+"/ubc_check.h";
		string c_test_name = outdir+"/ubc_check_verify.c";
		string c_simd_name = outdir + "/ubc_check_simd.cinc";

		ofstream ofs_c(c_name.c_str(), ios::out | ios::trunc);
		if (!ofs_c)
			throw std::runtime_error("Could not open " + c_name);
		ofstream ofs_h(h_name.c_str(), ios::out | ios::trunc);
		if (!ofs_h)
			throw std::runtime_error("Could not open " + h_name);
		ofstream ofs_c_test(c_test_name.c_str(), ios::out | ios::trunc);
		if (!ofs_c_test)
			throw std::runtime_error("Could not open " + c_test_name);
		ofstream ofs_c_simd(c_simd_name.c_str(), ios::out | ios::trunc);
		if (!ofs_c_simd)
			throw std::runtime_error("Could not open " + c_simd_name);

		output_code_simd(bitrel_to_DV, ofs_c_simd);

#if 0
		//  v3
		// very stupid straightward way: just ifs per DV
		// doesn't use redundency between DV's
		output_code_v3(bitrel_to_DV, ofs_h, ofs_c, ofs_c_test);
#endif

#if 0
		//  v1: second-fastest, constant-time if minDVs=1
		// first produces a constant-time section using bitrel with #DVs >= minDVs-parameter
		//   bitrels are ordered based on the bits involved to allow further local optimizations by the compiler
		// secondly produces a straightforward if-section like v3, per DV checks its remaining bitrels without further using redundency
		// minDVs=2 clearly optimal
		unsigned minDVs = 1;
		output_code_v1(bitrel_to_DV, ofs_h, ofs_c, ofs_c_test, minDVs);
#endif

#if 1
		//  v2: fastest
		// first produces a constant-time section using bitrel with #DVs from high to low
		//   bitrels are only included if the estimated probability
		//   that one of its DV's is still active (after checking the previous bitrels)
		//   is at least the minprob parameter
		// secondly produces a straightforward if-section like v3, per DV checks its remaining bitrels without further using redundency
		// optimum lies between 0.16 and 0.08: 0.1
		double minprob = 0.1;
		output_code_v2(bitrel_to_DV, ofs_h, ofs_c, ofs_c_test, minprob);
#endif

		ofs_c.close();
		ofs_h.close();
		ofs_c_test.close();

	}
	catch (exception & e)
	{
		cerr << "Exception: " << e.what() << endl;
	}
	catch (...)
	{
		cerr << "Unknown exception" << endl;
	}
	return 0;
}


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

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

//[register_box
//` Show the use of the macro BOOST_GEOMETRY_REGISTER_BOX

#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/geometries/register/box.hpp>

struct my_point
{
    double x, y;
};

struct my_box
{
    my_point ll, ur;
};

// Register the point type
BOOST_GEOMETRY_REGISTER_POINT_2D(my_point, double, cs::cartesian, x, y)

// Register the box type, also notifying that it is based on "my_point"
BOOST_GEOMETRY_REGISTER_BOX(my_box, my_point, ll, ur)

int main()
{
    my_box b = boost::geometry::make<my_box>(0, 0, 2, 2);
    std::cout << "Area: "  << boost::geometry::area(b) << std::endl;
    return 0;
}

//]

//[register_box_output
/*`
Output:
[pre
Area: 4
]
*/
//]


/*
 * This is part of the fl library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2015 Max Planck Society,
 * 				 Autonomous Motion Department,
 * 			     Institute for Intelligent Systems
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * @date 2015
 * @author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * Max-Planck-Institute for Intelligent Systems
 */

#include <gtest/gtest.h>

#include <vector>

#include <fl/distribution/discrete_distribution.hpp>
#include <fl/distribution/gaussian.hpp>
#include <fl/util/types.hpp>

#include <Eigen/Core>
#include <Eigen/Eigenvalues>

TEST(discrete_distribution, default_initialization)
{
    typedef Eigen::Vector3d Variate;
    typedef fl::DiscreteDistribution<Variate> DiscreteDistribution;

    fl::Real e = 0.000000001;

    DiscreteDistribution distribution;

    EXPECT_TRUE(distribution.size() == 1);
    EXPECT_TRUE(distribution.dimension() == 3);

    EXPECT_TRUE(std::fabs(distribution.prob_mass(0) - 1.0) < e);
    EXPECT_TRUE(std::fabs(distribution.log_prob_mass(0)) < e);
    EXPECT_TRUE(std::fabs(distribution.entropy()) < e);
    EXPECT_TRUE(std::fabs(distribution.kl_given_uniform()) < e);
}

TEST(discrete_distribution, max)
{
    typedef Eigen::Matrix<int, 1, 1> Variate;
    typedef fl::DiscreteDistribution<Variate> DiscreteDistribution;
    typedef DiscreteDistribution::Function Function;
    typedef std::vector<Variate> Locations;

    int N_locations = 10;

    // random prob mass fct
    Function pmf = Function::Random(N_locations).abs() + 0.01;
    pmf /= pmf.sum();

    // create discrete distr
    DiscreteDistribution discrete_distribution;
    discrete_distribution.log_unnormalized_prob_mass(pmf.log());

    for(int i = 0; i < N_locations; i++)
        discrete_distribution.location(i)(0) = i;

    int max_index;
    pmf.maxCoeff(&max_index);

    EXPECT_TRUE(discrete_distribution.max()(0) == max_index);
}

TEST(discrete_distribution, moments)
{
    typedef Eigen::Vector3d Variate;
    typedef Eigen::Matrix3d Covariance;
    typedef Variate::Scalar Scalar;
    typedef fl::DiscreteDistribution<Variate> DiscreteDistribution;
    typedef DiscreteDistribution::Function Function;

    // pick some mean and covariance
    Covariance covariance;
    covariance  <<  4.4, 2.1, -1.3,
                    2.2, 5.6,  1.2,
                   -1.2, 1.9,  3.9;
    covariance = covariance * covariance.transpose();

    Variate mean;
    mean << 2.1, 50.2, 20.1;

    // create gaussian
    fl::Gaussian<Variate> gaussian;
    gaussian.mean(mean);
    gaussian.covariance(covariance);

    // generate a sum of delta from gaussian
    DiscreteDistribution discrete_distribution;
    discrete_distribution.log_unnormalized_prob_mass(Function::Zero(100000));

    for(int i = 0; i < discrete_distribution.size(); i++)
    {
        discrete_distribution.location(i) = gaussian.sample();
    }

    // compare mean and covariance
    Covariance covariance_delta =
           discrete_distribution.covariance().inverse() * gaussian.covariance();

    EXPECT_TRUE(covariance_delta.isApprox(Covariance::Identity(), 0.1));

    EXPECT_TRUE((gaussian.square_root().inverse() *
                             (discrete_distribution.mean()-mean)).norm() < 0.1);
}

TEST(discrete_distribution, entropy)
{
    typedef Eigen::Vector3d Variate;
    typedef Variate::Scalar Scalar;
    typedef fl::DiscreteDistribution<Variate> DiscreteDistribution;
    typedef DiscreteDistribution::Function Function;

    int N = 100000;

    // check entropy of uniform distribution
    DiscreteDistribution discrete_distribution;
    discrete_distribution.log_unnormalized_prob_mass(Function::Zero(N));

    EXPECT_TRUE(fabs(std::log(double(discrete_distribution.size()))
                     - discrete_distribution.entropy()) < 0.0000001);

    EXPECT_TRUE(fabs(discrete_distribution.kl_given_uniform()) < 0.0000001);

    // check entropy of certain distribution
    Function log_pmf = Function::Constant(N,-std::numeric_limits<double>::max());
    log_pmf(0) = 0;
    discrete_distribution.log_unnormalized_prob_mass(log_pmf);

    EXPECT_TRUE(fabs(discrete_distribution.entropy()) < 0.0000001);

    EXPECT_TRUE(fabs(std::log(double(discrete_distribution.size()))
                     - discrete_distribution.kl_given_uniform()) < 0.0000001);
}

TEST(discrete_distribution, sampling)
{
    typedef Eigen::Matrix<int, 1, 1> Variate;
    typedef fl::DiscreteDistribution<Variate> DiscreteDistribution;
    typedef DiscreteDistribution::Function Function;
    typedef std::vector<Variate> Locations;

    int N_locations = 10;
    int N_samples   = 1000000;

    // random prob mass fct
    Function pmf = Function::Random(N_locations).abs() + 0.01;
    pmf /= pmf.sum();

    // create discrete distr
    DiscreteDistribution discrete_distribution;
    discrete_distribution.log_unnormalized_prob_mass(pmf.log());

    for(int i = 0; i < N_locations; i++)
        discrete_distribution.location(i)(0) = i;

    // generate empirical pmf
    Function empirical_pmf = Function::Zero(N_locations);
    for(int i = 0; i < N_samples; i++)
    {
        empirical_pmf(discrete_distribution.sample()(0)) += 1./N_samples;
    }

    // make sure that pmf and empirical pmf are similar
    for(int i = 0; i < pmf.size(); i++)
    {
        EXPECT_TRUE(fabs(pmf[i] - empirical_pmf[i]) < 0.01);
    }
}

TEST(discrete_distribution, sampling_index)
{
//    typedef Eigen::Matrix<int, 1, 1> Variate;
    typedef fl::DiscreteDistribution<fl::ScalarMatrix> DiscreteDistribution;
    typedef DiscreteDistribution::Function Function;

    int N_locations = 10;
    int N_samples   = 1000000;

    // random prob mass fct
    Function pmf = Function::Random(N_locations).abs() + 0.01;
    pmf /= pmf.sum();

    // create discrete distr
    DiscreteDistribution discrete_distribution;
    discrete_distribution.log_unnormalized_prob_mass(pmf.log());

    for(int i = 0; i < N_locations; i++)
        discrete_distribution.location(i) = i;

    for(int i = 0; i < N_samples; i++)
    {
        int index;
        int sample = discrete_distribution.sample(index);

        EXPECT_TRUE(index == sample);
    }
}


#include "stdafx.h"

#include "problem.hpp"

#include <fstream>
#include <vector>
#include <unordered_map>
#include <boost/algorithm/string.hpp>

struct advent_2017_11 : problem
{
	advent_2017_11() noexcept : problem(2017, 11) {
	}

protected:
	enum struct compass
	{
		n,
		ne,
		se,
		s,
		sw,
		nw,
	};

	compass str_to_direction(const std::string& str) {
		if(str == "n") {
			return compass::n;
		} else if(str == "ne") {
			return compass::ne;
		} else if(str == "se") {
			return compass::se;
		} else if(str == "s") {
			return compass::s;
		} else if(str == "sw") {
			return compass::sw;
		} else if(str == "nw") {
			return compass::nw;
		} else {
			__assume(0);
		}
	}

	std::vector<compass> directions;

	void prepare_input(std::ifstream& fin) override {
		std::string line;
		std::getline(fin, line);
		std::vector<std::string> raw_directions;
		boost::split(raw_directions, line, [](char c) { return c == ','; });
		std::transform(std::begin(raw_directions), std::end(raw_directions), std::back_inserter(directions), [&](const std::string& str) {
			return str_to_direction(str);
		});
	}

	std::size_t greatest_distance = 0;
	std::size_t current_distance = 0;

	struct hex_coord
	{
		std::ptrdiff_t x, y, z;

		hex_coord& operator+=(compass d) noexcept {
			switch(d) {
			case compass::n:      ++y; --z; break;
			case compass::ne: ++x;      --z; break;
			case compass::se: ++x; --y;      break;
			case compass::s:      --y; ++z; break;
			case compass::sw: --x;      ++z; break;
			case compass::nw: --x; ++y;      break;
			}
			return *this;
		}
	};

	std::size_t distance_from_origin(hex_coord c) {
		return gsl::narrow<std::size_t>((std::abs(c.x) + std::abs(c.y) + std::abs(c.z)) / 2);
	}

	void precompute() override {
		hex_coord position{ 0, 0, 0 };
		std::for_each(std::begin(directions), std::end(directions), [&](compass d) {
			position += d;
			current_distance = distance_from_origin(position);
			greatest_distance = std::max(greatest_distance, current_distance);
		});
	}

	std::string part_1() override {
		return std::to_string(current_distance);
	}

	std::string part_2() override {
		return std::to_string(greatest_distance);
	}
};

REGISTER_SOLVER(2017, 11);


/* ---------------------------------------------------------------------
 *
 * Copyright (C) 1999 - 2021 by the deal.II authors
 *
 * This file is part of the deal.II library.
 *
 * The deal.II library is free software; you can use it, redistribute
 * it, and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * The full text of the license can be found in the file LICENSE.md at
 * the top level directory of deal.II.
 *
 * ---------------------------------------------------------------------
 *
 * Author: Wolfgang Bangerth, University of Heidelberg, 1999
 */

// @sect3{Include files}

// 前面几个（很多）include文件已经在前面的例子中使用过了，所以我们在这里不再解释它们的含义。

#include <deal.II/grid/tria.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/matrix_tools.h>
#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/sparse_matrix.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/precondition.h>

#include <deal.II/numerics/data_out.h>
#include <fstream>
#include <iostream>

// 这是新的，但是：在前面的例子中，我们从线性求解器得到了一些不需要的输出。如果我们想抑制它，我们必须包括这个文件，并在程序的某个地方添加一行字（见下面的main()函数）。

#include <deal.II/base/logstream.h>

// 最后一步，和以前的程序一样，是将所有deal.II的类和函数名导入全局命名空间中。

using namespace dealii;
// @sect3{The Step4 class template}

// 这又是前面例子中的 Step4 类。唯一不同的是，我们现在把它声明为一个带有模板参数的类，而模板参数当然是我们要解决拉普拉斯方程的空间维度。当然，几个成员变量也取决于这个维度，特别是Triangulation类，它必须分别表示四边形或六面体。除此以外，一切都和以前一样。

template <int dim>
class Step4
{
public:
  Step4();
  void run();

private:
  void make_grid();
  void setup_system();
  void assemble_system();
  void solve();
  void output_results() const;

  Triangulation<dim> triangulation;
  FE_Q<dim>          fe;
  DoFHandler<dim>    dof_handler;

  SparsityPattern      sparsity_pattern;
  SparseMatrix<double> system_matrix;

  Vector<double> solution;
  Vector<double> system_rhs;
};
// @sect3{Right hand side and boundary values}

// 在下文中，我们又声明了两个类，表示右手边和非均质的Dirichlet边界值。两者都是一个二维空间变量的函数，所以我们也将它们声明为模板。

// 这些类中的每一个都是从一个共同的、抽象的基类Function派生出来的，它声明了所有函数都必须遵循的共同接口。特别是，具体的类必须重载 value 函数，该函数接收二维空间中的一个点作为参数，并将该点的值作为 double 变量返回。

//  value 函数需要第二个参数，我们在这里将其命名为 component  : 这只适用于矢量值函数，你可能想访问点 p 处的矢量的某个分量。然而，我们的函数是标量的，所以我们不需要担心这个参数，在函数的实现中也不会使用它。在库的头文件中，Function基类对 value 函数的声明中，分量的默认值为0，所以我们在访问右侧的 value 函数时，只需要一个参数，即我们要评估函数的点。然后，对于标量函数，可以简单地省略分量的值。

// 函数对象在库中很多地方都有使用（例如，在 step-3 中我们使用了一个 Functions::ZeroFunction 实例作为 VectorTools::interpolate_boundary_values) 的参数，这是我们定义一个继承自Function的新类的第一个教程。由于我们只调用 Function::value(), ，我们可以只用一个普通的函数（这就是 step-5 中的做法），但由于这是一个教程，为了举例说明，我们继承了Function。

template <int dim>
class RightHandSide : public Function<dim>
{
public:
  virtual double value(const Point<dim> & p,
                       const unsigned int component = 0) const override;
};

template <int dim>
class BoundaryValues : public Function<dim>
{
public:
  virtual double value(const Point<dim> & p,
                       const unsigned int component = 0) const override;
};

// 如果你不熟悉上述函数声明中的关键字 "virtual "和 "override "是什么意思，你可能会想看看你最喜欢的C++书籍或在线教程，如http:www.cplusplus.com/doc/tutorial/polymorphism/ 。从本质上讲，这里发生的事情是Function<dim>是一个 "抽象 "基类，它声明了某种 "接口"--一组可以在这类对象上调用的函数。但它实际上并没有*实现*这些函数：它只是说 "Function对象是这样的"，但它实际上是什么样的函数，则留给实现了`value()`函数的派生类。

// 从另一个类中派生出一个类，通常称为 "is-a "关系函数。在这里，`RightHandSide`类 "是一个 "函数类，因为它实现了Function基类所描述的接口。("value() "函数的实际实现在下面的代码块中)。那么`virtual`关键字意味着 "是的，这里的函数可以被派生类覆盖"，而`override`关键字意味着 "是的，这实际上是一个我们知道已经被声明为基类一部分的函数"。覆盖 "关键字不是严格必要的，但它是防止打字错误的一个保险。如果我们把函数的名字或一个参数的类型弄错了，编译器会警告我们说："你说这个函数覆盖了基类中的一个函数，但实际上我不知道有任何这样的函数有这个名字和这些参数。"

// 但回到这里的具体案例。在本教程中，我们选择2D中的函数 $4(x^4+y^4)$ ，或者3D中的 $4(x^4+y^4+z^4)$ 作为右手边。我们可以用空间维度上的if语句来写这个区别，但这里有一个简单的方法，通过使用一个短循环，也允许我们在一维（或四维，如果你想这样做）中使用相同的函数。 幸运的是，编译器在编译时就知道循环的大小（记住，在你定义模板时，编译器不知道 dim 的值，但当它后来遇到语句或声明 RightHandSide@<2@> 时，它将采取模板，用2替换所有出现的dim，并编译出结果函数）。 换句话说，在编译这个函数的时候，主体将被执行的次数是已知的，编译器可以将循环所需的开销降到最低；结果将和我们马上使用上面的公式一样快。

// 最后要注意的是， Point@<dim@> 表示二维空间中的一个点，它的各个组成部分（即 $x$ 、 $y$ 、...坐标）可以像C和C++中一样用（）运算符访问（事实上，[]运算符也同样有效），索引从0开始。

template <int dim>
double RightHandSide<dim>::value(const Point<dim> &p,
                                 const unsigned int /*component*/) const
{
  double return_value = 0.0;
  for (unsigned int i = 0; i < dim; ++i)
    return_value += 4.0 * std::pow(p(i), 4.0);

  return return_value;
}

// 作为边界值，我们选择二维的 $x^2+y^2$ ，三维的 $x^2+y^2+z^2$ 。这恰好等于从原点到我们想评估函数的点的矢量的平方，而不考虑维度。所以这就是我们的返回值。

template <int dim>
double BoundaryValues<dim>::value(const Point<dim> &p,
                                  const unsigned int /*component*/) const
{
  return p.square();
}

//  @sect3{Implementation of the Step4 class}

// 接下来是利用上述函数的类模板的实现。和以前一样，我们将把所有东西写成模板，这些模板有一个形式参数 dim ，在我们定义模板函数时，我们假设这个参数是未知的。只有在以后，编译器才会发现 Step4@<2@> (in the main 函数的声明，实际上），并在编译整个类时将 dim 替换成2，这个过程被称为 "模板的实例化"。这样做的时候，它也会用 RightHandSide@<dim@> 的实例替换 RightHandSide@<2@> ，并从类模板中实例化后一个类。

// 事实上，编译器也会在 main() 中找到一个 Step4@<3@> 声明。这将导致它再次回到一般的 Step4@<dim@> 模板，替换所有出现的 dim ，这次是3，并第二次编译这个类。注意这两个实例  Step4@<2@>  和  Step4@<3@>  是完全独立的类；它们唯一的共同特征是它们都是从同一个通用模板中实例化出来的，但是它们不能相互转换，例如，它们没有共享代码（两个实例都是完全独立编译的）。

//  @sect4{Step4::Step4}

// 在这个介绍之后，这里是  Step4  类的构造函数。它指定了所需的有限元素的多项式程度，并将DoFHandler与三角形关联起来，就像在前面的例子程序中一样，  step-3  。

template <int dim>
Step4<dim>::Step4()
  : fe(1)
  , dof_handler(triangulation)
{}
// @sect4{Step4::make_grid}

// 网格的创建在本质上是与维度有关的东西。然而，只要领域在二维或三维中足够相似，库就可以为你抽象。在我们的例子中，我们想再次在二维的正方形 $[-1,1]\times [-1,1]$ 上求解，或者在三维的立方体 $[-1,1] \times [-1,1] \times [-1,1]$ 上求解；两者都可以被称为 GridGenerator::hyper_cube(), ，因此我们可以在任何维度上使用同一个函数。当然，在二维和三维中创建超立方体的函数有很大的不同，但这是你不需要关心的事情。让库来处理这些困难的事情。

template <int dim>
void Step4<dim>::make_grid()
{
  GridGenerator::hyper_cube(triangulation, -1, 1);
  triangulation.refine_global(4);

  std::cout << "   Number of active cells: " << triangulation.n_active_cells()
            << std::endl
            << "   Total number of cells: " << triangulation.n_cells()
            << std::endl;
}
// @sect4{Step4::setup_system}

// 这个函数看起来和前面的例子完全一样，尽管它执行的动作在细节上有很大的不同，如果 dim 刚好是3。从用户的角度来看，唯一显著的区别是所产生的单元格数量，在三个空间维度中比两个空间维度中要高得多

template <int dim>
void Step4<dim>::setup_system()
{
  dof_handler.distribute_dofs(fe);

  std::cout << "   Number of degrees of freedom: " << dof_handler.n_dofs()
            << std::endl;

  DynamicSparsityPattern dsp(dof_handler.n_dofs());
  DoFTools::make_sparsity_pattern(dof_handler, dsp);
  sparsity_pattern.copy_from(dsp);

  system_matrix.reinit(sparsity_pattern);

  solution.reinit(dof_handler.n_dofs());
  system_rhs.reinit(dof_handler.n_dofs());
}
// @sect4{Step4::assemble_system}

// 与前面的例子不同，我们现在想使用一个非恒定的右侧函数和非零边界值。这两个任务都是很容易实现的，只需在矩阵和右手边的组合中增加几行代码即可。

// 更有趣的是，我们将矩阵和右手边的向量维度独立组装起来的方式：与二维的情况根本没有区别。由于这个函数中使用的重要对象（正交公式、FEValues）也通过模板参数的方式依赖于维度，它们可以为这个函数所编译的维度正确设置一切。通过使用模板参数声明所有可能依赖于维度的类，库可以为你完成几乎所有的工作，你不需要关心大多数事情。

template <int dim>
void Step4<dim>::assemble_system()
{
  QGauss<dim> quadrature_formula(fe.degree + 1);

// 我们希望有一个非恒定的右手，所以我们使用上面声明的类的一个对象来生成必要的数据。由于这个右侧对象只在本函数中局部使用，所以我们在这里把它声明为一个局部变量。

  RightHandSide<dim> right_hand_side;

// 与之前的例子相比，为了评估非恒定右手函数，我们现在还需要我们目前所在单元上的正交点（之前，我们只需要FEValues对象中的形状函数的值和梯度，以及正交权重， FEValues::JxW() ）。我们可以通过给FEValues对象添加#update_quadrature_points标志来让它为我们做事。

  FEValues<dim> fe_values(fe,
                          quadrature_formula,
                          update_values | update_gradients |
                            update_quadrature_points | update_JxW_values);

// 然后我们再次定义与前面程序中相同的缩写。这个变量的值当然取决于我们现在使用的维度，但是FiniteElement类为你做了所有必要的工作，你不需要关心与维度有关的部分。

  const unsigned int dofs_per_cell = fe.n_dofs_per_cell();

  FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
  Vector<double>     cell_rhs(dofs_per_cell);

  std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);

// 接下来，我们又要在所有的单元格上进行循环，并汇集局部贡献。 请注意，一个单元在两个空间维度上是一个四边形，但在三维上是一个六面体。事实上， active_cell_iterator 的数据类型是不同的，这取决于我们所处的维度，但对外界来说，它们看起来是一样的，你可能永远不会看到区别。在任何情况下，真正的类型是通过使用`auto`来隐藏的。

  for (const auto &cell : dof_handler.active_cell_iterators())
    {
      fe_values.reinit(cell);
      cell_matrix = 0;
      cell_rhs    = 0;

// 现在我们要把本地矩阵和右手边组合起来。这个过程和前面的例子完全一样，但是现在我们重新调整循环的顺序（我们可以安全地这样做，因为它们是相互独立的），并尽可能地合并本地矩阵和本地向量的循环，使事情变得更快。

// 组装右手边与我们在 step-3 中的做法有唯一的区别：我们没有使用值为1的常数右手边，而是使用代表右手边的对象并在正交点对其进行评估。

      for (const unsigned int q_index : fe_values.quadrature_point_indices())
        for (const unsigned int i : fe_values.dof_indices())
          {
            for (const unsigned int j : fe_values.dof_indices())
              cell_matrix(i, j) +=
                (fe_values.shape_grad(i, q_index) * // grad phi_i(x_q)
                 fe_values.shape_grad(j, q_index) * // grad phi_j(x_q)
                 fe_values.JxW(q_index));           // dx

            const auto &x_q = fe_values.quadrature_point(q_index);
            cell_rhs(i) += (fe_values.shape_value(i, q_index) * // phi_i(x_q)
                            right_hand_side.value(x_q) *        // f(x_q)
                            fe_values.JxW(q_index));            // dx
          }

// 作为对这些循环的最后说明：当我们将局部贡献集合到 cell_matrix(i,j) 时，我们必须将形状函数 $i$ 和 $j$ 在点号q_index的梯度相乘并与标量权重JxW相乘。这就是实际发生的情况。  fe_values.shape_grad(i,q_index) 返回一个 dim 维向量，由 Tensor@<1,dim@> 对象表示，将其与 fe_values.shape_grad(j,q_index) 的结果相乘的运算器*确保两个向量的 dim 分量被适当收缩，结果是一个标量浮点数，然后与权重相乘。在内部，这个操作符*确保对向量的所有 dim 分量都能正确发生，无论 dim 是2、3还是其他空间维度；从用户的角度来看，这并不值得费心，然而，如果想独立编写代码维度，事情就会简单很多。

// 随着本地系统的组装，转移到全局矩阵和右手边的工作与之前完全一样，但在这里我们再次合并了一些循环以提高效率。

      cell->get_dof_indices(local_dof_indices);
      for (const unsigned int i : fe_values.dof_indices())
        {
          for (const unsigned int j : fe_values.dof_indices())
            system_matrix.add(local_dof_indices[i],
                              local_dof_indices[j],
                              cell_matrix(i, j));

          system_rhs(local_dof_indices[i]) += cell_rhs(i);
        }
    }

// 作为这个函数的最后一步，我们希望在这个例子中拥有非均质的边界值，与之前的例子不同。这是一个简单的任务，我们只需要用一个描述我们想使用的边界值的类的对象（即上面声明的 BoundaryValues 类）来替换那里使用的 Functions::ZeroFunction 。

// 函数 VectorTools::interpolate_boundary_values() 只对标有边界指标0的面起作用（因为我们在下面的第二个参数中说该函数应该对其起作用）。如果有的面的边界指标不是0，那么函数interpolate_boundary_values将对这些面不起作用。对于拉普拉斯方程来说，什么都不做相当于假设在边界的这些部分，零诺伊曼边界条件成立。

  std::map<types::global_dof_index, double> boundary_values;
  VectorTools::interpolate_boundary_values(dof_handler,
                                           0,
                                           BoundaryValues<dim>(),
                                           boundary_values);
  MatrixTools::apply_boundary_values(boundary_values,
                                     system_matrix,
                                     solution,
                                     system_rhs);
}
// @sect4{Step4::solve}

// 解决线性方程组是在大多数程序中看起来几乎相同的事情。特别是，它与维度无关，所以这个函数是从前面的例子中逐字复制的。

template <int dim>
void Step4<dim>::solve()
{
  SolverControl            solver_control(1000, 1e-12);
  SolverCG<Vector<double>> solver(solver_control);
  solver.solve(system_matrix, solution, system_rhs, PreconditionIdentity());

// 不过我们做了一个补充：由于我们抑制了线性求解器的输出，我们必须手工打印迭代次数。

  std::cout << "   " << solver_control.last_step()
            << " CG iterations needed to obtain convergence." << std::endl;
}
// @sect4{Step4::output_results}

// 这个函数也做了  step-3  中各自的工作。这里也没有改变维度的独立性。

// 由于程序将同时运行拉普拉斯求解器的2D和3D版本，我们使用文件名中的维度为每次运行生成不同的文件名（在一个更好的程序中，我们将检查 dim 是否可以有2或3以外的其他值，但为了简洁起见，我们在这里忽略了这一点）。

template <int dim>
void Step4<dim>::output_results() const
{
  DataOut<dim> data_out;

  data_out.attach_dof_handler(dof_handler);
  data_out.add_data_vector(solution, "solution");

  data_out.build_patches();

  std::ofstream output(dim == 2 ? "solution-2d.vtk" : "solution-3d.vtk");
  data_out.write_vtk(output);
}

//  @sect4{Step4::run}

// 这是一个对所有事情都有最高级别控制的函数。除了一行额外的输出外，它与前面的例子相同。

template <int dim>
void Step4<dim>::run()
{
  std::cout << "Solving problem in " << dim << " space dimensions."
            << std::endl;

  make_grid();
  setup_system();
  assemble_system();
  solve();
  output_results();
}
// @sect3{The main function}

// 这是主函数。它看起来也大多像 step-3 中的内容，但如果你看下面的代码，注意我们是如何首先创建一个 Step4@<2@> 类型的变量（迫使编译器用 dim replaced by 2 编译类模板）并运行一个2d模拟，然后我们用3d做整个事情。

// 在实践中，这可能不是你经常做的事情（你可能要么想解决一个2D的问题，要么想解决一个3D的问题，但不会同时解决这两个问题）。然而，它展示了一种机制，我们可以在一个地方简单地改变我们想要的维度，从而迫使编译器为我们要求的维度重新编译独立的类模板。这里的重点在于，我们只需要改变一个地方。这使得在计算速度较快的2D环境下调试程序变得非常简单，然后将一个地方切换到3，在3D环境下运行计算量大得多的程序，进行 "真实 "的计算。

// 这两个区块中的每一个都用大括号括起来，以确保 laplace_problem_2d 这个变量在我们继续为3D情况分配内存之前就已经超出了范围（并释放了它所持有的内存）。如果没有额外的大括号， laplace_problem_2d 变量只会在函数结束时被销毁，也就是在运行完3d问题后被销毁，而且会在3d运行时不必要地占用内存，而实际使用它。

int main()
{
  {
    Step4<2> laplace_problem_2d;
    laplace_problem_2d.run();
  }

  {
    Step4<3> laplace_problem_3d;
    laplace_problem_3d.run();
  }

  return 0;
}


#include <boost/assign/std/vector.hpp>
#include <cmath>
#include <cradle/geometry/distance.hpp>

#include <cradle/test.hpp>

using namespace boost::assign;
using namespace cradle;

TEST_CASE("point_line_segment_2d_test")
{
    line_segment<2, double> ls(
        make_vector<double>(0, 0), make_vector<double>(0, 5));
    vector2d cp;
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(ls, make_vector<double>(1, 2), &cp), 1.);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(0, 2));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(ls, make_vector<double>(-3, 3), &cp), 3.);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(0, 3));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(ls, make_vector<double>(0, 7), &cp), 2.);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(0, 5));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(ls, make_vector<double>(-3, -4), &cp), 5.);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(0, 0));

    ls = line_segment<2, double>(
        make_vector<double>(0, 0), make_vector<double>(3, 3));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(ls, make_vector<double>(-3, -4), &cp), 5.);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(0, 0));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(ls, make_vector<double>(3, 5), &cp), 2.);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(3, 3));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(ls, make_vector<double>(0, 4), &cp), sqrt(8.));
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(2, 2));
}

TEST_CASE("point_polygon_test")
{
    polygon2 poly;
    {
        std::vector<vertex2> vertices;
        vertices += make_vector<double>(0, 0), make_vector<double>(0, 6),
            make_vector<double>(6, 6);
        initialize(&poly.vertices, vertices);
    }

    vector2d cp;
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(poly, make_vector<double>(7, 6), &cp), 1.);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(6, 6));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(poly, make_vector<double>(1, 4), &cp), -1.);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(0, 4));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(poly, make_vector<double>(-1, -1), &cp), sqrt(2.));
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(0, 0));
}

TEST_CASE("point_polyset_test")
{
    polygon2 poly, hole;
    {
        std::vector<vertex2> vertices;
        vertices += make_vector<double>(-2, -2), make_vector<double>(-2, 2),
            make_vector<double>(2, 2), make_vector<double>(2, -2);
        initialize(&poly.vertices, vertices);
    }
    {
        std::vector<vertex2> vertices;
        vertices += make_vector<double>(-1, -1), make_vector<double>(-1, 1),
            make_vector<double>(1, 1), make_vector<double>(1, -1);
        initialize(&hole.vertices, vertices);
    }
    polyset area;
    add_polygon(area, poly);
    add_hole(area, hole);

    CRADLE_CHECK_ALMOST_EQUAL(get_area(area), 12.);

    REQUIRE(!is_inside(area, make_vector<double>(-3, 3)));
    REQUIRE(!is_inside(area, make_vector<double>(0, 0)));
    REQUIRE(is_inside(area, make_vector<double>(-1.5, 1.5)));

    vector2d cp;
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(area, make_vector<double>(0.5, 0), &cp), 0.5);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(1, 0));
    CRADLE_CHECK_ALMOST_EQUAL(distance(area, make_vector<double>(0, 0)), 1.);
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(area, make_vector<double>(1.25, 1), &cp), -0.25);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(1, 1));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(area, make_vector<double>(1.75, 1), &cp), -0.25);
    CRADLE_CHECK_ALMOST_EQUAL(cp, make_vector<double>(2, 1));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(area, make_vector<double>(2.5, 1)), 0.5);
}

TEST_CASE("point_plane_test")
{
    plane<double> plane(
        make_vector<double>(0, 0, 0), make_vector<double>(1, 0, 0));
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(plane, make_vector<double>(0, 0, 0)), 0.);
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(plane, make_vector<double>(-7.1, 0, 0)), -7.1);
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(plane, make_vector<double>(13, 0, 0)), 13.);

    plane.point = make_vector<double>(0, 0, 1);
    plane.normal = unit(make_vector<double>(1, 0, 1));
    double srt = std::sqrt(2.);
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(plane, make_vector<double>(0, 0, 0)), -1 / srt);
    CRADLE_CHECK_ALMOST_EQUAL(
        distance(plane, make_vector<double>(0, 0, 6)), 5 / srt);
    CRADLE_CHECK_ALMOST_EQUAL(
        distance2(plane, make_vector<double>(0, 0, 0)), -0.5);
    CRADLE_CHECK_ALMOST_EQUAL(
        distance2(plane, make_vector<double>(0, 0, 6)), 12.5);
    CRADLE_CHECK_ALMOST_EQUAL(
        absolute_distance2(plane, make_vector<double>(0, 0, 0)), 0.5);
    CRADLE_CHECK_ALMOST_EQUAL(
        absolute_distance2(plane, make_vector<double>(0, 0, 6)), 12.5);
}