#include <koinos/system/system_calls.hpp>

#include <koinos/contracts/resources/resources.h>

#include <boost/multiprecision/cpp_int.hpp>

using namespace koinos;
using namespace koinos::contracts::resources;

using int128_t = boost::multiprecision::int128_t;

enum entries : uint32_t
{
   get_resource_limits_entry     = 0,
   consume_block_resources_entry = 1,
   get_resource_markets_entry    = 2
};

namespace constants {

constexpr std::size_t max_buffer_size         = 2048;
const std::string market_key                  = "market";

// These are tuned really low, but we want to test constraints with low trx volume
constexpr uint64_t target_blocks_per_week         = 60480;
constexpr uint64_t target_utilized_supply         = 10000000000000;

constexpr uint64_t disk_budget_per_block          = 39600; // 10G per month
constexpr uint64_t max_disk_per_block             = 200 << 10; // 200k
constexpr uint64_t network_budget_per_block       = 1 << 18; // 256k block
constexpr uint64_t max_network_per_block          = 1 << 20; // 1M block
constexpr uint64_t compute_budget_per_block       = 1'000'000;
constexpr uint64_t max_compute_per_block          = 10'000'000;

// Exponential decay constant for 1 month half life
// Constant is ( -ln(2) * num_blocks ) * 2^64
// constexpr uint64_t decay_constant                 = 18446694743881045523ull;

// Exponential decay constant for 1 week half life
constexpr uint64_t decay_constant                 = 18446532661087609961ull;

} // constants

namespace state {

system::object_space contract_space()
{
   system::object_space obj_space;
   auto contract_id = system::get_contract_id();
   obj_space.mutable_zone().set( reinterpret_cast< const uint8_t* >( contract_id.data() ), contract_id.size() );
   obj_space.set_id( 0 );
   return obj_space;
}

}

using get_resource_limits_result        = chain::get_resource_limits_result;
using consume_block_resources_arguments = chain::consume_block_resources_arguments;
using consume_block_resources_result    = chain::consume_block_resources_result;

void initialize_markets( resource_markets& markets )
{
   markets.mutable_disk_storage().set_resource_supply( constants::disk_budget_per_block * constants::target_blocks_per_week );
   markets.mutable_disk_storage().set_rc_reserve( constants::target_utilized_supply );
   markets.mutable_disk_storage().set_block_budget( constants::disk_budget_per_block );
   markets.mutable_disk_storage().set_block_limit( constants::max_disk_per_block );

   markets.mutable_network_bandwidth().set_resource_supply( constants::network_budget_per_block * constants::target_blocks_per_week );
   markets.mutable_network_bandwidth().set_rc_reserve( constants::target_utilized_supply );
   markets.mutable_network_bandwidth().set_block_budget( constants::network_budget_per_block );
   markets.mutable_network_bandwidth().set_block_limit( constants::max_network_per_block );

   markets.mutable_compute_bandwidth().set_resource_supply( constants::compute_budget_per_block * constants::target_blocks_per_week );
   markets.mutable_compute_bandwidth().set_rc_reserve( constants::target_utilized_supply );
   markets.mutable_compute_bandwidth().set_block_budget( constants::compute_budget_per_block );
   markets.mutable_compute_bandwidth().set_block_limit( constants::max_compute_per_block );
}

resource_markets get_markets()
{
   resource_markets markets;
   if ( !system::get_object( state::contract_space(), constants::market_key, markets ) )
   {
      initialize_markets( markets );
   }

   return markets;
}

std::pair< uint64_t, uint64_t > calculate_market_limit( const market& m )
{
   auto resource_limit = std::min( m.resource_supply() - 1, m.block_limit() );
   auto k = int128_t( m.resource_supply() ) * int128_t( m.rc_reserve() );
   auto new_supply = m.resource_supply() - resource_limit;
   auto consumed_rc = ( ( k + ( new_supply - 1 ) ) / new_supply ) - m.rc_reserve();
   auto rc_cost = ( ( consumed_rc + ( resource_limit - 1 ) ) / resource_limit ).convert_to< uint64_t >();
   return std::make_pair( resource_limit, rc_cost );
}

get_resource_limits_result get_resource_limits()
{
   auto markets = get_markets();

   auto [disk_limit,    disk_cost]    = calculate_market_limit( markets.disk_storage() );
   auto [network_limit, network_cost] = calculate_market_limit( markets.network_bandwidth() );
   auto [compute_limit, compute_cost] = calculate_market_limit( markets.compute_bandwidth() );

   get_resource_limits_result res;
   res.mutable_value().set_disk_storage_limit( disk_limit );
   res.mutable_value().set_disk_storage_cost( disk_cost );
   res.mutable_value().set_network_bandwidth_limit( network_limit );
   res.mutable_value().set_network_bandwidth_cost( network_cost );
   res.mutable_value().set_compute_bandwidth_limit( compute_limit );
   res.mutable_value().set_compute_bandwidth_cost( compute_cost );

   return res;
}

void update_market( market& m, uint64_t consumed )
{
   auto k = int128_t( m.resource_supply() ) * int128_t( m.rc_reserve() );
   m.set_resource_supply( m.resource_supply() + m.block_budget() - consumed );
   m.set_resource_supply( ( ( int128_t( m.resource_supply() ) * constants::decay_constant ) >> 64 ).convert_to< uint64_t >() );
   m.set_rc_reserve( ( ( k + ( m.resource_supply() - 1 ) ) / m.resource_supply() ).convert_to< uint64_t >() );
}

consume_block_resources_result consume_block_resources( const consume_block_resources_arguments& args )
{
   consume_block_resources_result res;
   res.set_value( false );

   const auto [ caller, privilege ] = system::get_caller();
   if ( privilege != chain::privilege::kernel_mode )
   {
      system::print( "consume_block_resources must be called from kernel context" );
      return res;
   }

   auto markets = get_markets();

   if (  markets.disk_storage().resource_supply()      <= args.disk_storage_consumed()
      || markets.network_bandwidth().resource_supply() <= args.network_bandwidth_consumed()
      || markets.compute_bandwidth().resource_supply() <= args.network_bandwidth_consumed() )
   {
      return res;
   }

   update_market( markets.mutable_disk_storage(),      args.disk_storage_consumed() );
   update_market( markets.mutable_network_bandwidth(), args.network_bandwidth_consumed() );
   update_market( markets.mutable_compute_bandwidth(), args.compute_bandwidth_consumed() );

   system::put_object( state::contract_space(), constants::market_key, markets );

   res.set_value( true );
   return res;
}

int main()
{
   auto entry_point = system::get_entry_point();
   auto args = system::get_contract_arguments();

   std::array< uint8_t, constants::max_buffer_size > retbuf;

   koinos::read_buffer rdbuf( (uint8_t*)args.c_str(), args.size() );
   koinos::write_buffer buffer( retbuf.data(), retbuf.size() );

   switch( std::underlying_type_t< entries >( entry_point ) )
   {
      case entries::get_resource_limits_entry:
      {
         auto res = get_resource_limits();
         res.serialize( buffer );
         break;
      }
      case entries::consume_block_resources_entry:
      {
         consume_block_resources_arguments arg;
         arg.deserialize( rdbuf );

         auto res = consume_block_resources( arg );
         res.serialize( buffer );
         break;
      }
      case entries::get_resource_markets_entry:
      {
         get_resource_markets_result res;
         res.set_value( get_markets() );
         res.serialize( buffer );
         break;
      }
      default:
         return 1;
   }

   std::string retval( reinterpret_cast< const char* >( buffer.data() ), buffer.get_size() );
   system::set_contract_result_bytes( retval );

   return 0;
}


#include "Version.h"
#include "AvatarPCL.h"

#ifdef OPENARK_PCL_ENABLED
#include <pcl/conversions.h>
#include <boost/smart_ptr.hpp>

namespace ark {
namespace avatar_pcl {
pcl::PointCloud<pcl::PointXYZ>::Ptr getCloud(const Avatar& ava) {
    auto pointCloud =
        pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
    pointCloud->points.resize(ava.model.numPoints());
    pointCloud->getMatrixXfMap().block<3, Eigen::Dynamic>(
        0, 0, 3, pointCloud->size()) = ava.cloud.cast<float>();
    return pointCloud;
}

pcl::PointCloud<pcl::PointXYZ>::Ptr getJointCloud(const Avatar& ava) {
    auto pointCloud =
        pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
    pointCloud->resize(ava.model.numJoints());
    pointCloud->getMatrixXfMap().block<3, Eigen::Dynamic>(
        0, 0, 3, pointCloud->size()) = ava.jointPos.cast<float>();
    return pointCloud;
}

pcl::PolygonMesh::Ptr getMesh(const Avatar& ava) {
    auto pclCloud = getCloud(ava);
    auto mesh = boost::make_shared<pcl::PolygonMesh>();
    pcl::toPCLPointCloud2(*pclCloud, mesh->cloud);

    mesh->polygons.reserve(ava.model.numFaces());
    for (int i = 0; i < ava.model.numFaces(); ++i) {
        mesh->polygons.emplace_back();
        auto& face = mesh->polygons.back().vertices;
        face.resize(3);
        for (int j = 0; j < 3; ++j) face[j] = ava.model.mesh(j, i);
    }
    return mesh;
}
}  // namespace avatar_pcl
}  // namespace ark
#endif


/* Copyright (c) 2021, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 *
 * All rights reserved.
 *
 * The "ISAAC - Integrated System for Autonomous and Adaptive Caretaking
 * platform" software is licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

#include <ff_common/init.h>
#include <ff_common/thread.h>
#include <ff_common/utils.h>
#include <config_reader/config_reader.h>
#include <camera/camera_params.h>
#include <camera/camera_model.h>
#include <dense_map_utils.h>
#include <texture_processing.h>

#include <boost/filesystem.hpp>

#include <gflags/gflags.h>
#include <glog/logging.h>

#include <cmath>

// Project a given image and camera onto a given mesh, and save an .obj file

DEFINE_string(mesh, "", "The mesh to project onto.");

DEFINE_string(image, "", "The image to orthoproject. It should be distorted, as extracted "
              "from a bag.");

DEFINE_string(camera_to_world, "",
              "The camera to world file, as written by the geometry mapper. For example: "
              "run/1616779788.2920296_nav_cam_to_world.txt.");

DEFINE_string(camera_name, "", "The the camera name. For example: 'sci_cam'.");

DEFINE_string(image_list, "", "The list of images to orthoproject, one per line, "
              "unless specified individually as above.");

DEFINE_string(camera_list, "", "The list of cameras to world transforms use, one per line, "
              "unless specified individually as above.");

DEFINE_int32(num_exclude_boundary_pixels, 0,
             "Exclude pixels closer to the boundary than this when texturing.");

DEFINE_string(output_prefix, "", "The output prefix. The texture name will be"
              " <output_prefix>-<image base name without extension>.obj.");

int main(int argc, char** argv) {
  ff_common::InitFreeFlyerApplication(&argc, &argv);

  if ((FLAGS_image.empty() || FLAGS_camera_to_world.empty()) &&
      (FLAGS_image_list.empty() || FLAGS_camera_list.empty()))
    LOG(FATAL) << "Must specify either an image and camera, or an image list and camera list.";

  if (FLAGS_mesh.empty() || FLAGS_camera_name.empty() || FLAGS_output_prefix.empty())
    LOG(FATAL) << "Not all inputs were specified.";

  // Load the mesh
  mve::TriangleMesh::Ptr mesh;
  std::shared_ptr<mve::MeshInfo> mesh_info;
  std::shared_ptr<tex::Graph> graph;
  std::shared_ptr<BVHTree> bvh_tree;
  dense_map::loadMeshBuildTree(FLAGS_mesh, mesh, mesh_info, graph, bvh_tree);

  // Load the camera intrinsics
  config_reader::ConfigReader config;
  config.AddFile("cameras.config");
  if (!config.ReadFiles()) LOG(FATAL) << "Could not read the configuration file.";
  std::cout << "Using camera: " << FLAGS_camera_name << std::endl;
  camera::CameraParameters cam_params(&config, FLAGS_camera_name.c_str());

  std::vector<std::string> images, cameras;
  if (!FLAGS_image.empty() && !FLAGS_camera_to_world.empty()) {
    images.push_back(FLAGS_image);
    cameras.push_back(FLAGS_camera_to_world);
  } else {
    std::string val;
    std::ifstream ifs(FLAGS_image_list);
    while (ifs >> val)
      images.push_back(val);
    ifs.close();
    ifs = std::ifstream(FLAGS_camera_list);
    while (ifs >> val)
      cameras.push_back(val);
    ifs.close();
  }

  if (images.size() != cameras.size())
    LOG(FATAL) << "As many images as cameras must be specified.\n";

  for (size_t it = 0; it < images.size(); it++) {
    cv::Mat image = cv::imread(images[it]);

    Eigen::Affine3d cam_to_world;
    dense_map::readAffine(cam_to_world, cameras[it]);

    std::string prefix = FLAGS_output_prefix + "-" +
      boost::filesystem::path(images[it]).stem().string();

    dense_map::meshProject(mesh, bvh_tree, image, cam_to_world.inverse(), cam_params,
                           FLAGS_num_exclude_boundary_pixels, prefix);
  }

  return 0;
}


#pragma once
#include <string>
#include <atomic>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <petuum_ps_common/include/petuum_ps.hpp>

#include "matrix_loader.hpp"

namespace NMF {
class NMFEngine {
    public:
        NMFEngine();
        ~NMFEngine();
        void Start();
    private:
        std::atomic<int> thread_counter_;

        // petuum parameters
        int client_id_, num_clients_, num_worker_threads_;
        float maximum_running_time_;

        // objective function parameters
        int rank_;

        // minibatch and evaluate parameters
        int num_epochs_, minibatch_size_, num_eval_minibatch_,
            num_iter_L_per_minibatch_,
            num_eval_samples_, num_eval_per_client_;

        // optimization parameters
        float init_step_size_R_, step_size_offset_R_, step_size_pow_R_,
              init_step_size_L_, step_size_offset_L_, step_size_pow_L_,
              init_L_low_, init_L_high_, init_R_low_, init_R_high_;

        // input and output
        std::string data_file_, input_data_format_, output_path_,
            output_data_format_, cache_path_;
        int is_partitioned_;
        int load_cache_;

        // matrix loader for data X and S
        MatrixLoader<float> X_matrix_loader_, L_matrix_loader_;

        // timer
        boost::posix_time::ptime initT_;

        // Save results to disk
        void SaveResults(int thread_id, petuum::Table<float> & R_table,
                petuum::Table<float> & loss_table);

        // Init B with random values and normalize elements to have unit norm
        void InitRand(int thread_id, petuum::Table<float> & R_table);

        // Load B and S from disk
        void LoadCache(int thread_id, petuum::Table<float> & R_table);
};
}; // namespace NMF


/* boosting_training_tool.cc                                       -*- C++ -*-
   Jeremy Barnes, 12 June 2003
   Copyright (c) 2003 Jeremy Barnes.  All rights reserved.
   $Source$

   Tool to use to train boosting with.  Very similar in spirit to the MLP
   training tool.
*/

#include "jml/boosting/training_data.h"
#include "jml/boosting/dense_features.h"
#include "jml/boosting/sparse_features.h"
#include "jml/boosting/classifier.h"
#include "jml/utils/command_line.h"
#include "jml/utils/file_functions.h"
#include "jml/utils/filter_streams.h"
#include "jml/utils/parse_context.h"
#include <boost/multi_array.hpp>
#include "jml/utils/sgi_numeric.h"
#include "jml/utils/vector_utils.h"
#include "jml/stats/distribution.h"
#include "jml/stats/sparse_distribution.h"
#include "jml/sections/sink_stream.h"
#include "jml/stats/distribution_ops.h"

#include <iterator>
#include <iostream>
#include <set>

using namespace std;

using namespace ML;
using namespace Math;
using namespace Stats;

/** Return the number of the maximum label in the file. */
sparse_distribution<int, size_t>
file_label_counts(const string & filename)
{
    File_Read_Buffer file(filename);
    Parse_Context context(filename, file.start(), file.end());

    sparse_distribution<int, size_t> result;

    context.skip_line();  // skip header line
    while (context) {
        int label = context.expect_unsigned();
        result[label] += 1;
        context.skip_line();
    }

    cerr << context.get_line() << " lines scanned." << endl;
    cerr << context.get_pos() - context.get_start() << " bytes total"
         << endl;

    return result;
}

/** Return the maximum number of labels in all of the files. */
sparse_distribution<int, size_t>
get_label_counts(const vector<string> & filenames)
{
    sparse_distribution<int, size_t> result;
    for (unsigned i = 0;  i < filenames.size();  ++i)
        result += file_label_counts(filenames[i]);
    return result;
}

int main(int argc, char ** argv)
try
{
    ios::sync_with_stdio(false);

    bool data_is_sparse     = false;
    int verbosity           = 1;
    string classifier_file;
    string output_filename;

    vector<string> extra;
    {
        using namespace CmdLine;

        static const Option classifier_options[] = {
            { "classifier-file", 'C', classifier_file, classifier_file,
              false, "load classifier from FILE", "FILE" },
            Last_Option
        };

        static const Option data_options[] = {
            { "sparse-data", 'S', NO_ARG, flag(data_is_sparse),
              false, "dataset is in sparse format" },
            Last_Option
        };

        static const Option output_options[] = {
            { "quiet", 'q', NO_ARG, assign(verbosity, 0),
              false, "don't write any non-fatal output" },
            { "verbosity", 'v', optional(2), verbosity,
              false, "set verbosity to LEVEL (0-3)", "LEVEL" },
            { "output-file", 'o', output_filename, output_filename,
              false, "write output to FILE", "FILE" },
            Last_Option
        };

        static const Option options[] = {
            group("Classifier options", classifier_options),
            group("Data options", data_options),
            group("Output options",   output_options),
            Help_Options,
            Last_Option };

        Command_Line_Parser parser("boosting_testing_tool", argc, argv,
                                   options);

        bool res = parser.parse();
        if (res == false) exit(1);

        extra.insert(extra.end(), parser.extra_begin(), parser.extra_end());
    }

    /* The rest of the options are training sets.  If we have specified a
       training split, then we will discard some of it. */

    if (extra.empty()) {
        cerr << "error: need to specify (at least) training data" << endl;
        exit(1);
    }

    /* Get the label counts by scanning the datasets. */
    sparse_distribution<int, size_t> labels = get_label_counts(extra);
    cerr << "labels[0] = " << labels[0] << "  labels[1] = " << labels[1]
         << endl;

    if (verbosity > 0) {
        cerr << labels.size() << " unique labels: ";
        size_t total = labels.total();
        for (map<int, size_t>::const_iterator it = labels.begin();
             it != labels.end();  ++it) {
            cerr << format("%d (%zd/%.1f%%) ", it->first, it->second,
                           (double)it->second / (double)total * 100.0);
        }
        cerr << endl;
    }

    size_t label_count = 0;
    if (!labels.empty()) {
        sparse_distribution<int, size_t>::const_iterator it = labels.end();
        --it;
        label_count = it->first + 1;
    }
    else throw Exception("No training data, therefore no labels");

    /* Raw data. */
    std::shared_ptr<Feature_Space> feature_space;
    vector<std::shared_ptr<Training_Data> > data(extra.size());

    /* Broken down and split up datasets.  First one is training, second is
       validation, any after that are testing. */
    vector<std::shared_ptr<Training_Data> > testing;

    /* Variables for when we are sparse. */
    std::shared_ptr<Sparse_Feature_Space> sparse_feature_space;
    vector<std::shared_ptr<Sparse_Training_Data> > sparse_data(extra.size());

    /* Variables for when we are dense. */
    std::shared_ptr<Dense_Feature_Space> dense_feature_space;
    vector<std::shared_ptr<Dense_Training_Data> > dense_data(extra.size());

    /* Set up the feature space. */
    if (data_is_sparse) {
        sparse_feature_space.reset(new Sparse_Feature_Space());
        feature_space = sparse_feature_space;
    }
    else {
        dense_feature_space.reset(new Dense_Feature_Space());
        feature_space = dense_feature_space;
    }

    /* First, read in all of the data. */
    for (unsigned i = 0;  i < extra.size();  ++i) {
        //cerr << "i = " << i << "  extra[i] = " << extra[i] << endl;

        if (data_is_sparse) {
            sparse_data[i]
                .reset(new Sparse_Training_Data(extra[i], sparse_feature_space,
                                                label_count));
            data[i] = sparse_data[i];
        }
        else {
            dense_data[i]
                .reset(new Dense_Training_Data(extra[i], dense_feature_space,
                                               label_count));
            data[i] = dense_data[i];
        }

        if (verbosity > 0)
            cerr << "dataset \'" << extra[i] << "\': "
                 << data[i]->all_features().size() << " features, "
                 << data[i]->example_count() << " rows." << endl;
        cerr << "label freq: " << data[i]->label_freq << endl;
    }

    if (verbosity > 0) {
        unsigned testing_rows = 0;
        for (unsigned i = 0;  i < testing.size();  ++i) {
            testing_rows += testing[i]->example_count();
        }

        cerr << "data size: " << testing_rows << endl;
    }

    /* Load the classifier. */
    if (classifier_file == "")
        throw Exception("Need to specify a classifier to test.");
    Classifier classifier;
    classifier.load(classifier_file, feature_space);

    if (labels.size() > classifier.label_count())
        throw Exception(format("%zd labels in classifier but %zd found",
                               classifier.label_count(), labels.size()));

    filter_ostream out(output_filename);
    out << feature_space->print() << "\n";

    /* Test all of the testing datasets. */
    for (unsigned i = 0;  i < data.size();  ++i) {
        for (unsigned x = 0;  x < data[i]->example_count();  ++x) {
            distribution<float> result
                = classifier.predict(*(*data[i])[x].features);
            cerr << "result = " << result << endl;
            out << (*data[i])[x].label << " "
                << feature_space->print(*(*data[i])[x].features);
            if (feature_space->type() == Feature_Space::SPARSE) {
                for (unsigned i = 0;  i < result.size();  ++i)
                    out << format(" inp%d:%f", i, result[i]);
            }
            out << "\n";
        }
    }
}
catch (const std::exception & exc) {
    cerr << "error: " << exc.what() << endl;
    exit(1);
}


#ifndef BOOST_MPL_MIN_ELEMENT_HPP_INCLUDED
#define BOOST_MPL_MIN_ELEMENT_HPP_INCLUDED

// Copyright David Abrahams 2004
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/mpl for documentation.

// $Source$
// $Date: 2008-03-22 17:45:55 -0400 (Sat, 22 Mar 2008) $
// $Revision: 43798 $

#include <boost/mpl/max_element.hpp>
#include <boost/mpl/not.hpp>

namespace boost { namespace mpl {

BOOST_MPL_AUX_COMMON_NAME_WKND(min_element)

template<
      typename BOOST_MPL_AUX_NA_PARAM(Sequence)
    , typename Predicate = less<_,_>
    >
struct min_element
    : max_element<
          Sequence
        , mpl::not_<Predicate>
        >
{
};

BOOST_MPL_AUX_NA_SPEC(1, min_element)

}}

#endif // BOOST_MPL_MIN_ELEMENT_HPP_INCLUDED


/*
@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/detail/assert.hpp>
#include <boost/hana/integral.hpp>
#include <boost/hana/list/instance.hpp>
#include <boost/hana/map.hpp>
#include <boost/hana/maybe.hpp>
#include <boost/hana/pair.hpp>
#include <boost/hana/type.hpp>
using namespace boost::hana;

int main() {
    //! [main]
    BOOST_HANA_CONSTANT_ASSERT(lookup(list(int_<1>, type<int>, '3'), type<int>) == just(type<int>));
    BOOST_HANA_CONSTANT_ASSERT(lookup(list(int_<1>, type<int>, '3'), type<void>) == nothing);

    BOOST_HANA_CONSTEXPR_LAMBDA auto m = map(
        pair(1, 'x'),
        pair(type<float>, 3.3),
        pair(type<char>, type<int>)
    );
    BOOST_HANA_CONSTEXPR_ASSERT(lookup(m, type<float>) == just(3.3));
    //! [main]
}


/* CirKit: A circuit toolkit
 * Copyright (C) 2009-2015  University of Bremen
 * Copyright (C) 2015-2017  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "visit_solutions.hpp"

#include <map>

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/logic/tribool_io.hpp>

#include <core/utils/bitset_utils.hpp>

namespace std
{

template<>
struct less<std::vector<boost::tribool>>
{
  bool operator()( const std::vector<boost::tribool>& v1, const std::vector<boost::tribool>& v2 ) const
  {
    assert( v1.size() == v2.size() );

    auto i = 0u;
    while ( i < v1.size() )
    {
      const auto& t1 = v1[i];
      const auto& t2 = v2[i];

      if ( t1 != t2 )
      {
        if ( boost::indeterminate( t1 ) ) { return true; }
        if ( boost::indeterminate( t2 ) ) { return false; }
        return !t1 && t2;
      }

      ++i;
    }

    return true;
  }
};

}

namespace cirkit
{

using boost::adaptors::transformed;
using boost::tribool;

/******************************************************************************
 * Types                                                                      *
 ******************************************************************************/

/******************************************************************************
 * Private functions                                                          *
 ******************************************************************************/

void visit_solutions_rec( unsigned level, const bdd& n, boost::dynamic_bitset<>& x, const visit_solutions_func& f )
{
  if ( n.index == 0u )
  {
    return;
  }
  if ( n.var() > level )
  {
    x.reset( level ); visit_solutions_rec( level + 1u, n, x, f );
    x.set( level );   visit_solutions_rec( level + 1u, n, x, f );
  }
  else if ( n.index == 1u )
  {
    f( x );
  }
  else
  {
    if ( n.low().index != 0u )
    {
      x.reset( level ); visit_solutions_rec( level + 1u, n.low(), x, f );
    }
    if ( n.high().index != 0u )
    {
      x.set( level );   visit_solutions_rec( level + 1u, n.high(), x, f );
    }
  }
}

void visit_paths_rec( const bdd& n, std::vector<tribool>& x, const visit_paths_func& f )
{
  switch ( n.index )
  {
  case 0u:
    return;
  case 1u:
    f( x );
    break;
  default:
    x[n.var()] = false; visit_paths_rec( n.low(), x, f );
    std::fill( x.begin() + n.var(), x.end(), dontcare );
    x[n.var()] = true;  visit_paths_rec( n.high(), x, f );
  }
}

char to_char( const tribool& t )
{
  return indeterminate( t ) ? '-' : ( static_cast<bool>( t ) ? '1' : '0' );
}

/******************************************************************************
 * Public functions                                                           *
 ******************************************************************************/

void visit_solutions( const bdd& n, const visit_solutions_func& f )
{
  if ( n.index != 0u )
  {
    boost::dynamic_bitset<> x( n.manager->num_vars() );
    visit_solutions_rec( 0u, n, x, f );
  }
}

void visit_paths( const bdd& n, const visit_paths_func& f )
{
  if ( n.index != 0u )
  {
    std::vector<tribool> x( n.manager->num_vars(), dontcare );
    visit_paths_rec( n, x, f );
  }
}

void print_paths( const bdd& n, std::ostream& os )
{
  visit_paths( n, [&]( const std::vector<tribool>& cube ) {
      boost::copy( cube | transformed( to_char ), std::ostream_iterator<char>( os ) );
      os << " 1" << std::endl;
    } );
}

void print_paths( const std::vector<bdd>& ns, std::ostream& os )
{
  std::map<std::vector<tribool>, boost::dynamic_bitset<>> pla;
  auto idx = 0u;

  auto visitor = [&]( const std::vector<tribool>& cube ) {
    auto it = pla.find( cube );
    if ( it == pla.end() )
    {
      pla.insert( {cube, onehot_bitset( ns.size(), idx )} );
    }
    else
    {
      it->second.set( idx );
    }
  };

  for ( idx = 0u; idx < ns.size(); ++idx )
  {
    visit_paths( ns[idx], visitor );
  }

  /* now print */
  for ( const auto& line : pla )
  {
    std::string bs;
    to_string( line.second, bs );
    boost::reverse( bs );

    boost::copy( line.first | transformed( to_char ), std::ostream_iterator<char>( os ) );
    os << " " << bs << std::endl;
  }
}

}

// Local Variables:
// c-basic-offset: 2
// eval: (c-set-offset 'substatement-open 0)
// eval: (c-set-offset 'innamespace 0)
// End:


/* boost random/ranlux.hpp header file
 *
 * Copyright Jens Maurer 2002
 * Distributed under the Boost Software License, Version 1.0. (See
 * accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * See http://www.boost.org for most recent version including documentation.
 *
 * $Id$
 *
 * Revision history
 *  2001-02-18  created
 */

#ifndef BOOST_RANDOM_RANLUX_HPP
#define BOOST_RANDOM_RANLUX_HPP

#include <boost/config.hpp>
#include <boost/random/subtract_with_carry.hpp>
#include <boost/random/discard_block.hpp>

namespace boost {

namespace random {

namespace detail {
/**
 * The ranlux family of generators are described in
 *
 *  @blockquote
 *  "A portable high-quality random number generator for lattice field theory
 *  calculations", M. Luescher, Computer Physics Communications, 79 (1994)
 *  pp 100-110.
 *  @endblockquote
 *
 * The levels are given in
 *
 *  @blockquote
 *  "RANLUX: A Fortran implementation of the high-quality
 *  pseudorandom number generator of Luescher", F. James,
 *  Computer Physics Communications 79 (1994) 111-114
 *  @endblockquote
 */
class ranlux_documentation {};
}

typedef subtract_with_carry_engine<uint32_t, 24, 10, 24> ranlux_base;
typedef subtract_with_carry_01_engine<float, 24, 10, 24> ranlux_base_01;
typedef subtract_with_carry_01_engine<double, 48, 10, 24> ranlux64_base_01;

/** @copydoc boost::random::detail::ranlux_documentation */
typedef discard_block_engine<ranlux_base, 223, 24> ranlux3;
/** @copydoc boost::random::detail::ranlux_documentation */
typedef discard_block_engine<ranlux_base, 389, 24> ranlux4;

/** @copydoc boost::random::detail::ranlux_documentation */
typedef discard_block_engine<ranlux_base_01, 223, 24> ranlux3_01;
/** @copydoc boost::random::detail::ranlux_documentation */
typedef discard_block_engine<ranlux_base_01, 389, 24> ranlux4_01;

/** @copydoc boost::random::detail::ranlux_documentation */
typedef discard_block_engine<ranlux64_base_01, 223, 24> ranlux64_3_01;
/** @copydoc boost::random::detail::ranlux_documentation */
typedef discard_block_engine<ranlux64_base_01, 389, 24> ranlux64_4_01;

#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
typedef subtract_with_carry_engine<uint64_t, 48, 10, 24> ranlux64_base;
/** @copydoc boost::random::detail::ranlux_documentation */
typedef discard_block_engine<ranlux64_base, 223, 24> ranlux64_3;
/** @copydoc boost::random::detail::ranlux_documentation */
typedef discard_block_engine<ranlux64_base, 389, 24> ranlux64_4;
#endif /* !BOOST_NO_INT64_T && !BOOST_NO_INTEGRAL_INT64_T */

typedef subtract_with_carry_engine<uint32_t, 24, 10, 24> ranlux24_base;
typedef subtract_with_carry_engine<uint64_t, 48, 5, 12> ranlux48_base;

typedef discard_block_engine<ranlux24_base, 223, 23> ranlux24;
#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
typedef discard_block_engine<ranlux48_base, 389, 11> ranlux48;
#endif
}

using random::ranlux3;
using random::ranlux4;
using random::ranlux3_01;
using random::ranlux4_01;
using random::ranlux64_3_01;
using random::ranlux64_4_01;
#if !defined(BOOST_NO_INT64_T) && !defined(BOOST_NO_INTEGRAL_INT64_T)
using random::ranlux64_3;
using random::ranlux64_4;
#endif

} // namespace boost

#endif // BOOST_RANDOM_LINEAR_CONGRUENTIAL_HPP


// Copyright (c) 2021 Inria

#include <cassert>
#include <cmath>
#include <iostream>

#include <Eigen/Core>
#include <Eigen/Dense>
#include <franka/exception.h>
#include <franka/robot.h>

#include "cartesian_franka/robot.hpp"

int main(int argc, char** argv)
{
    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " <robot-hostname>" << std::endl;
        return -1;
    }
    try {
        cartesian_franka::Robot robot(argv[1]);
        std::cout<<"Starting position:" << robot.position().transpose() << std::endl;
        std::cout<<"Starting Euler angles:" << robot.orientation().transpose() << std::endl;
        std::cout<<"Moving to the init position..." << std::endl;

        robot.init();

        std::cout<<"Init position:" << robot.position().transpose() << std::endl;
        std::cout<<"Init Euler angles:" << robot.orientation().transpose() << std::endl;

        robot.translate(Eigen::Vector3d(0.1, 0, 0));
        robot.rotate(Eigen::Vector3d(M_PI / 4., 0, 0));

    }
    catch (const franka::Exception& e) {
        std::cout << e.what() << std::endl;
        return -1;
    }

    return 0;
}


// Boost.Geometry - gis-projections (based on PROJ4)

// Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.

// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle.

// 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)

// This file is converted from PROJ4, http://trac.osgeo.org/proj
// PROJ4 is originally written by Gerald Evenden (then of the USGS)
// PROJ4 is maintained by Frank Warmerdam
// PROJ4 is converted to Boost.Geometry by Barend Gehrels

// Last updated version of proj: 5.0.0

// Original copyright notice:

// Copyright (c) 2003, 2006   Gerald I. Evenden

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#ifndef BOOST_GEOMETRY_PROJECTIONS_OMERC_HPP
#define BOOST_GEOMETRY_PROJECTIONS_OMERC_HPP

#include <boost/geometry/util/math.hpp>

#include <boost/geometry/srs/projections/impl/base_static.hpp>
#include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
#include <boost/geometry/srs/projections/impl/projects.hpp>
#include <boost/geometry/srs/projections/impl/factory_entry.hpp>
#include <boost/geometry/srs/projections/impl/pj_phi2.hpp>
#include <boost/geometry/srs/projections/impl/pj_tsfn.hpp>

namespace boost { namespace geometry
{

namespace projections
{
    #ifndef DOXYGEN_NO_DETAIL
    namespace detail { namespace omerc
    {
            template <typename T>
            struct par_omerc
            {
                T   A, B, E, AB, ArB, BrA, rB, singam, cosgam, sinrot, cosrot;
                T   v_pole_n, v_pole_s, u_0;
                int no_rot;
            };

            static const double tolerance = 1.e-7;
            static const double epsilon = 1.e-10;

            // template class, using CRTP to implement forward/inverse
            template <typename T, typename Parameters>
            struct base_omerc_ellipsoid
                : public base_t_fi<base_omerc_ellipsoid<T, Parameters>, T, Parameters>
            {
                par_omerc<T> m_proj_parm;

                inline base_omerc_ellipsoid(const Parameters& par)
                    : base_t_fi<base_omerc_ellipsoid<T, Parameters>, T, Parameters>(*this, par)
                {}

                // FORWARD(e_forward)  ellipsoid
                // Project coordinates from geographic (lon, lat) to cartesian (x, y)
                inline void fwd(T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
                {
                    static const T half_pi = detail::half_pi<T>();

                    T  s, t, U, V, W, temp, u, v;

                    if (fabs(fabs(lp_lat) - half_pi) > epsilon) {
                        W = this->m_proj_parm.E / math::pow(pj_tsfn(lp_lat, sin(lp_lat), this->m_par.e), this->m_proj_parm.B);
                        temp = 1. / W;
                        s = .5 * (W - temp);
                        t = .5 * (W + temp);
                        V = sin(this->m_proj_parm.B * lp_lon);
                        U = (s * this->m_proj_parm.singam - V * this->m_proj_parm.cosgam) / t;
                        if (fabs(fabs(U) - 1.0) < epsilon) {
                            BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
                        }
                        v = 0.5 * this->m_proj_parm.ArB * log((1. - U)/(1. + U));
                        temp = cos(this->m_proj_parm.B * lp_lon);
                        if(fabs(temp) < tolerance) {
                            u = this->m_proj_parm.A * lp_lon;
                        } else {
                            u = this->m_proj_parm.ArB * atan2((s * this->m_proj_parm.cosgam + V * this->m_proj_parm.singam), temp);
                        }
                    } else {
                        v = lp_lat > 0 ? this->m_proj_parm.v_pole_n : this->m_proj_parm.v_pole_s;
                        u = this->m_proj_parm.ArB * lp_lat;
                    }
                    if (this->m_proj_parm.no_rot) {
                        xy_x = u;
                        xy_y = v;
                    } else {
                        u -= this->m_proj_parm.u_0;
                        xy_x = v * this->m_proj_parm.cosrot + u * this->m_proj_parm.sinrot;
                        xy_y = u * this->m_proj_parm.cosrot - v * this->m_proj_parm.sinrot;
                    }
                }

                // INVERSE(e_inverse)  ellipsoid
                // Project coordinates from cartesian (x, y) to geographic (lon, lat)
                inline void inv(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
                {
                    static const T half_pi = detail::half_pi<T>();

                    T  u, v, Qp, Sp, Tp, Vp, Up;

                    if (this->m_proj_parm.no_rot) {
                        v = xy_y;
                        u = xy_x;
                    } else {
                        v = xy_x * this->m_proj_parm.cosrot - xy_y * this->m_proj_parm.sinrot;
                        u = xy_y * this->m_proj_parm.cosrot + xy_x * this->m_proj_parm.sinrot + this->m_proj_parm.u_0;
                    }
                    Qp = exp(- this->m_proj_parm.BrA * v);
                    Sp = .5 * (Qp - 1. / Qp);
                    Tp = .5 * (Qp + 1. / Qp);
                    Vp = sin(this->m_proj_parm.BrA * u);
                    Up = (Vp * this->m_proj_parm.cosgam + Sp * this->m_proj_parm.singam) / Tp;
                    if (fabs(fabs(Up) - 1.) < epsilon) {
                        lp_lon = 0.;
                        lp_lat = Up < 0. ? -half_pi : half_pi;
                    } else {
                        lp_lat = this->m_proj_parm.E / sqrt((1. + Up) / (1. - Up));
                        if ((lp_lat = pj_phi2(math::pow(lp_lat, T(1) / this->m_proj_parm.B), this->m_par.e)) == HUGE_VAL) {
                            BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
                        }
                        lp_lon = - this->m_proj_parm.rB * atan2((Sp * this->m_proj_parm.cosgam -
                            Vp * this->m_proj_parm.singam), cos(this->m_proj_parm.BrA * u));
                    }
                }

                static inline std::string get_name()
                {
                    return "omerc_ellipsoid";
                }

            };

            // Oblique Mercator
            template <typename Params, typename Parameters, typename T>
            inline void setup_omerc(Params const& params, Parameters& par, par_omerc<T>& proj_parm)
            {
                static const T fourth_pi = detail::fourth_pi<T>();
                static const T half_pi = detail::half_pi<T>();
                static const T pi = detail::pi<T>();
                static const T two_pi = detail::two_pi<T>();

                T con, com, cosph0, D, F, H, L, sinph0, p, J, gamma=0,
                  gamma0, lamc=0, lam1=0, lam2=0, phi1=0, phi2=0, alpha_c=0;
                int alp, gam, no_off = 0;

                proj_parm.no_rot = pj_get_param_b<srs::spar::no_rot>(params, "no_rot", srs::dpar::no_rot);
                alp = pj_param_r<srs::spar::alpha>(params, "alpha", srs::dpar::alpha, alpha_c);
                gam = pj_param_r<srs::spar::gamma>(params, "gamma", srs::dpar::gamma, gamma);
                if (alp || gam) {
                    lamc = pj_get_param_r<T, srs::spar::lonc>(params, "lonc", srs::dpar::lonc);
                    // NOTE: This is not needed in Boost.Geometry
                    //no_off =
                    //            /* For libproj4 compatability */
                    //            pj_param_exists(par.params, "no_off")
                    //            /* for backward compatibility */
                    //            || pj_param_exists(par.params, "no_uoff");
                    //if( no_off )
                    //{
                    //    /* Mark the parameter as used, so that the pj_get_def() return them */
                    //    pj_get_param_s(par.params, "no_uoff");
                    //    pj_get_param_s(par.params, "no_off");
                    //}
                } else {
                    lam1 = pj_get_param_r<T, srs::spar::lon_1>(params, "lon_1", srs::dpar::lon_1);
                    phi1 = pj_get_param_r<T, srs::spar::lat_1>(params, "lat_1", srs::dpar::lat_1);
                    lam2 = pj_get_param_r<T, srs::spar::lon_2>(params, "lon_2", srs::dpar::lon_2);
                    phi2 = pj_get_param_r<T, srs::spar::lat_2>(params, "lat_2", srs::dpar::lat_2);
                    if (fabs(phi1 - phi2) <= tolerance ||
                        (con = fabs(phi1)) <= tolerance ||
                        fabs(con - half_pi) <= tolerance ||
                        fabs(fabs(par.phi0) - half_pi) <= tolerance ||
                        fabs(fabs(phi2) - half_pi) <= tolerance)
                        BOOST_THROW_EXCEPTION( projection_exception(error_lat_0_or_alpha_eq_90) );
                }
                com = sqrt(par.one_es);
                if (fabs(par.phi0) > epsilon) {
                    sinph0 = sin(par.phi0);
                    cosph0 = cos(par.phi0);
                    con = 1. - par.es * sinph0 * sinph0;
                    proj_parm.B = cosph0 * cosph0;
                    proj_parm.B = sqrt(1. + par.es * proj_parm.B * proj_parm.B / par.one_es);
                    proj_parm.A = proj_parm.B * par.k0 * com / con;
                    D = proj_parm.B * com / (cosph0 * sqrt(con));
                    if ((F = D * D - 1.) <= 0.)
                        F = 0.;
                    else {
                        F = sqrt(F);
                        if (par.phi0 < 0.)
                            F = -F;
                    }
                    proj_parm.E = F += D;
                    proj_parm.E *= math::pow(pj_tsfn(par.phi0, sinph0, par.e), proj_parm.B);
                } else {
                    proj_parm.B = 1. / com;
                    proj_parm.A = par.k0;
                    proj_parm.E = D = F = 1.;
                }
                if (alp || gam) {
                    if (alp) {
                        gamma0 = aasin(sin(alpha_c) / D);
                        if (!gam)
                            gamma = alpha_c;
                    } else
                        alpha_c = aasin(D*sin(gamma0 = gamma));
                    par.lam0 = lamc - aasin(.5 * (F - 1. / F) *
                       tan(gamma0)) / proj_parm.B;
                } else {
                    H = math::pow(pj_tsfn(phi1, sin(phi1), par.e), proj_parm.B);
                    L = math::pow(pj_tsfn(phi2, sin(phi2), par.e), proj_parm.B);
                    F = proj_parm.E / H;
                    p = (L - H) / (L + H);
                    J = proj_parm.E * proj_parm.E;
                    J = (J - L * H) / (J + L * H);
                    if ((con = lam1 - lam2) < -pi)
                        lam2 -= two_pi;
                    else if (con > pi)
                        lam2 += two_pi;
                    par.lam0 = adjlon(.5 * (lam1 + lam2) - atan(
                       J * tan(.5 * proj_parm.B * (lam1 - lam2)) / p) / proj_parm.B);
                    gamma0 = atan(2. * sin(proj_parm.B * adjlon(lam1 - par.lam0)) /
                       (F - 1. / F));
                    gamma = alpha_c = aasin(D * sin(gamma0));
                }
                proj_parm.singam = sin(gamma0);
                proj_parm.cosgam = cos(gamma0);
                proj_parm.sinrot = sin(gamma);
                proj_parm.cosrot = cos(gamma);
                proj_parm.BrA = 1. / (proj_parm.ArB = proj_parm.A * (proj_parm.rB = 1. / proj_parm.B));
                proj_parm.AB = proj_parm.A * proj_parm.B;
                if (no_off)
                    proj_parm.u_0 = 0;
                else {
                    proj_parm.u_0 = fabs(proj_parm.ArB * atan(sqrt(D * D - 1.) / cos(alpha_c)));
                    if (par.phi0 < 0.)
                        proj_parm.u_0 = - proj_parm.u_0;
                }
                F = 0.5 * gamma0;
                proj_parm.v_pole_n = proj_parm.ArB * log(tan(fourth_pi - F));
                proj_parm.v_pole_s = proj_parm.ArB * log(tan(fourth_pi + F));
            }

    }} // namespace detail::omerc
    #endif // doxygen

    /*!
        \brief Oblique Mercator projection
        \ingroup projections
        \tparam Geographic latlong point type
        \tparam Cartesian xy point type
        \tparam Parameters parameter type
        \par Projection characteristics
         - Cylindrical
         - Spheroid
         - Ellipsoid
        \par Projection parameters
         - no_rot: No rotation
         - alpha: Alpha (degrees)
         - gamma: Gamma (degrees)
         - no_off: Only for compatibility with libproj, proj4 (string)
         - lonc: Longitude (only used if alpha (or gamma) is specified) (degrees)
         - lon_1 (degrees)
         - lat_1: Latitude of first standard parallel (degrees)
         - lon_2 (degrees)
         - lat_2: Latitude of second standard parallel (degrees)
         - no_uoff (string)
        \par Example
        \image html ex_omerc.gif
    */
    template <typename T, typename Parameters>
    struct omerc_ellipsoid : public detail::omerc::base_omerc_ellipsoid<T, Parameters>
    {
        template <typename Params>
        inline omerc_ellipsoid(Params const& params, Parameters const& par)
            : detail::omerc::base_omerc_ellipsoid<T, Parameters>(par)
        {
            detail::omerc::setup_omerc(params, this->m_par, this->m_proj_parm);
        }
    };

    #ifndef DOXYGEN_NO_DETAIL
    namespace detail
    {

        // Static projection
        BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION(srs::spar::proj_omerc, omerc_ellipsoid, omerc_ellipsoid)

        // Factory entry(s)
        BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(omerc_entry, omerc_ellipsoid)

        BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(omerc_init)
        {
            BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(omerc, omerc_entry)
        }

    } // namespace detail
    #endif // doxygen

} // namespace projections

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_PROJECTIONS_OMERC_HPP


// Copyright (c) 2021 fortiss GmbH
//
// Authors: Klemens Esterle and Tobias Kessler
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.

#ifndef MIQP_PLANNER_DATA_HEADER
#define MIQP_PLANNER_DATA_HEADER

#include <Eigen/Dense>
#include <unsupported/Eigen/CXX11/Tensor>

#include "common/parameter/limits_parameters.hpp"
#include "common/parameter/linearization_parameters.hpp"
#include "src/miqp_planner_settings.h"

using miqp::common::parameter::FractionParameters;
using miqp::common::parameter::LimitPerRegionParameters;
using miqp::common::parameter::PolynomialCurvatureParameters;
using miqp::common::parameter::PolynomialOrientationParameters;

namespace miqp {
namespace common {
namespace map {
typedef unsigned int PolygonId;
}  // namespace map
}  // namespace common
}  // namespace miqp

namespace miqp {
namespace planner {

typedef enum InitialStateIndices : int {
  MIQP_STATE_X = 0,
  MIQP_STATE_VX = 1,
  MIQP_STATE_AX = 2,
  MIQP_STATE_Y = 3,
  MIQP_STATE_VY = 4,
  MIQP_STATE_AY = 5,
  MIQP_INITIAL_STATE_SIZE = 6
} InitialStateIndices;

// RawResults: A 1:1 copy of the cplex decision variables after solution, mapped
// into Eigen::Tensors
struct RawResults {
  Eigen::Tensor<double, 2> u_x;             //(NrCars, N);
  Eigen::Tensor<double, 2> u_y;             //(NrCars, N);
  Eigen::Tensor<double, 2> pos_x;           //(NrCars, N);
  Eigen::Tensor<double, 2> vel_x;           //(NrCars, N);
  Eigen::Tensor<double, 2> acc_x;           //(NrCars, N);
  Eigen::Tensor<double, 2> pos_y;           //(NrCars, N);
  Eigen::Tensor<double, 2> vel_y;           //(NrCars, N);
  Eigen::Tensor<double, 2> acc_y;           //(NrCars, N);
  Eigen::Tensor<double, 2> pos_x_front_UB;  //(NrCars, N);
  Eigen::Tensor<double, 2> pos_x_front_LB;  //(NrCars, N);
  Eigen::Tensor<double, 2> pos_y_front_UB;  //(NrCars, N);
  Eigen::Tensor<double, 2> pos_y_front_LB;  //(NrCars, N);
  Eigen::Tensor<int, 3>
      notWithinEnvironmentRear;  //(NrCars, NrEnvironments, N);
  Eigen::Tensor<int, 3>
      notWithinEnvironmentFrontUbUb;  //(NrCars, NrEnvironments,N);
  Eigen::Tensor<int, 3>
      notWithinEnvironmentFrontLbUb;  //(NrCars, NrEnvironments, N);
  Eigen::Tensor<int, 3>
      notWithinEnvironmentFrontUbLb;  //(NrCars, NrEnvironments,  N);
  Eigen::Tensor<int, 3>
      notWithinEnvironmentFrontLbLb;    //(NrCars, NrEnvironments, N);
  Eigen::Tensor<int, 3> active_region;  //(NrCars, N, NrRegions);
  Eigen::Tensor<int, 2> region_change_not_allowed_x_positive;  //(NrCars, N);
  Eigen::Tensor<int, 2> region_change_not_allowed_y_positive;  //(NrCars, N);
  Eigen::Tensor<int, 2> region_change_not_allowed_x_negative;  //(NrCars, N);
  Eigen::Tensor<int, 2> region_change_not_allowed_y_negative;  //(NrCars, N);
  Eigen::Tensor<int, 2> region_change_not_allowed_combined;    //(NrCars, N);
  Eigen::Tensor<int, 4>
      deltacc;  //(NrCars, NrObstacles,  N,  MaxLinesObstacles);
  Eigen::Tensor<int, 5>
      deltacc_front;  //(NrCars, NrObstacles, N, MaxLinesObstacles, 4);  // 4 :
                      // all combinations of UBUB, UBLB, LBUB, UBUB
  Eigen::Tensor<int, 4>
      car2car_collision;  //(NumCar2CarCollisions, NumCar2CarCollisions, N, 16);
                          // 16 Idxs: Rear/rear = 1..4, Rear/front = 5..8,
                          // Front/rear = 9..12, Front/front = 13..16
  Eigen::Tensor<int, 4>
      slackvars;  //(NumCar2CarCollisions, NumCar2CarCollisions, N, 4);
                  // 4 Idxs: rear x = 1, rear y = 2, front x = 3, front y = 4
  Eigen::Tensor<int, 3> slackvarsObstacle;        //(NrCars, NrObstacles,  N)
  Eigen::Tensor<int, 4> slackvarsObstacle_front;  //(NrCars, NrObstacles,  N, 4)

  int N;
  int NrEnvironments;
  int NrRegions;
  int NrObstacles;
  int MaxLinesObstacles;
  int NrCarToCarCollisions;
  int NrCars;
};

struct ModelParameters {
  // API MultiEnvironmentConvexPolygon: std::vector containing the n polygons.
  //     each polygon is represented by an Eigen::MatrixXd with:
  //     x0, x1, x2, x3, ...
  //     y0, y1, y2, y3, ...

  // Solver Parameters
  float max_solution_time;  // default: 1e+75, limit maximum time, if cplex
                            // already found a valid integer solution, it return
                            // with success but not the global optimum
  float relative_mip_gap_tolerance;  // default: 1e-04, opimality gap
  int mipdisplay;                    // default: 2, display verbosity
                   // https://www.ibm.com/support/knowledgecenter/SSSA5P_12.9.0/ilog.odms.cplex.help/CPLEX/Parameters/topics/MIPDisplay.html
  int mipemphasis;  // default: 0, find feasible solutions fast
                    // https://www.ibm.com/support/knowledgecenter/SSSA5P_12.9.0/ilog.odms.cplex.help/CPLEX/Parameters/topics/MIPEmphasis.html
  float
      relobjdif;  // default 0.0, ignore integer solutions that are not x%
                  // better than already found ones
                  // https://www.ibm.com/support/knowledgecenter/en/SSSA5P_12.10.0/ilog.odms.cplex.help/CPLEX/Parameters/topics/RelObjDif.html
  int cutpass;  // default: 0, proposed by the tuning tool, nr of cutting planes
                // //https://www.ibm.com/support/knowledgecenter/SSSA5P_12.9.0/ilog.odms.cplex.help/CPLEX/Parameters/topics/CutPass.html
  int probe;    // default: 0, probing:  logical implications of fixing each
                // binary variable to 0 or
  // 1https://www.ibm.com/support/knowledgecenter/SSSA5P_12.9.0/ilog.odms.cplex.help/CPLEX/Parameters/topics/Probe.html
  int repairtries;  // default: 0, number of tries to repair a warmstart
                    // solution
                    // //https://www.ibm.com/support/knowledgecenter/pl/SSSA5P_12.9.0/ilog.odms.cplex.help/CPLEX/Parameters/topics/RepairTries.html
  int rinsheur;     // default: 0, relaxation induced neighborhood search (RINS)
                    // heuristic
  // //https://www.ibm.com/support/knowledgecenter/en/SS9UKU_12.9.0/com.ibm.cplex.zos.help/CPLEX/Parameters/topics/RINSHeur.html
  int varsel;  // default: 0, select branching variable: cplex automatically
               // takes 4 (best in our case) //
               // https://www.ibm.com/support/knowledgecenter/SSSA5P_12.9.0/ilog.odms.cplex.help/CPLEX/Parameters/topics/VarSel.html
  int mircuts;       // default: 0,  mixed integer rounding cuts
  int parallelmode;  // default: 0, opportunistic (-1) or deterministic (1)
                     // parallel search

  // Model Parameters
  int NumSteps;
  float ts;
  int nr_regions;
  int NumCars;
  float min_vel_x_y;
  float max_vel_x_y;
  float total_min_acc;
  float total_max_acc;
  float total_min_jerk;
  float total_max_jerk;
  Eigen::VectorXd agent_safety_distance;
  Eigen::VectorXd agent_safety_distance_slack;
  float maximum_slack;
  Eigen::VectorXd WEIGHTS_POS_X;
  Eigen::VectorXd WEIGHTS_VEL_X;
  Eigen::VectorXd WEIGHTS_ACC_X;
  Eigen::VectorXd WEIGHTS_POS_Y;
  Eigen::VectorXd WEIGHTS_VEL_Y;
  Eigen::VectorXd WEIGHTS_ACC_Y;
  Eigen::VectorXd WEIGHTS_JERK_X;
  Eigen::VectorXd WEIGHTS_JERK_Y;
  float WEIGHTS_SLACK;
  float WEIGHTS_SLACK_OBSTACLE;
  Eigen::VectorXd WheelBase;
  Eigen::VectorXd CollisionRadius;
  Eigen::VectorXd BufferReference;
  Eigen::MatrixXd IntitialState;
  Eigen::MatrixXd x_ref;
  Eigen::MatrixXd vx_ref;
  Eigen::MatrixXd y_ref;
  Eigen::MatrixXd vy_ref;
  LimitPerRegionParameters
      acc_limit_params;  // = LimitPerRegionParameters(NumCars, nr_regions);
  LimitPerRegionParameters
      jerk_limit_params;  // = LimitPerRegionParameters(NumCars, nr_regions);
  Eigen::VectorXi initial_region;
  Eigen::MatrixXi possible_region;
  int nr_obstacles;
  std::vector<std::vector<Eigen::MatrixXd> > ObstacleConvexPolygon;
  int max_lines_obstacles;
  std::vector<int> obstacle_is_soft;  // 0: hard obstacle, 1: soft obstacle
  int nr_environments;
  std::vector<Eigen::MatrixXd> MultiEnvironmentConvexPolygon;
  std::vector<miqp::common::map::PolygonId> environmentPolygonIds;
  FractionParameters fraction_parameters;
  float minimum_region_change_speed;
  PolynomialCurvatureParameters poly_curvature_params;
  PolynomialOrientationParameters poly_orientation_params;
};

// For the C API the Settings struct has to be outside of a namespace
typedef MiqpPlannerSettings Settings;

inline Settings DefaultSettings() {
  Settings s = Settings();
  s.nr_regions = 16;
  s.nr_steps = 20;
  s.nr_neighbouring_possible_regions = 1;
  s.ts = 0.25;
  s.max_solution_time = 10;
  s.relative_mip_gap_tolerance = 0.1;
  s.mipdisplay = 2;
  s.mipemphasis = 0;
  s.relobjdif = 0.0;
  s.cutpass = 0;
  s.probe = 0;
  s.repairtries = 0;
  s.rinsheur = 0;
  s.varsel = 0;
  s.mircuts = 0;
  s.precision = 12;
  s.constant_agent_safety_distance_slack = 3;
  s.minimum_region_change_speed = 2;
  s.lambda = 0.5;
  s.wheelBase = 2.8;
  s.collisionRadius = 1;
  s.slackWeight = 30;
  s.slackWeightObstacle = 2000;
  s.jerkWeight = 1;
  s.positionWeight = 2;
  s.velocityWeight = 0;
  s.acclerationWeight = 0;
  s.accLonMaxLimit = 2;
  s.accLonMinLimit = -4;
  s.jerkLonMaxLimit = 3;
  s.accLatMinMaxLimit = 1.6;
  s.jerkLatMinMaxLimit = 1.4;
  s.simplificationDistanceMap = 0.2;
  s.simplificationDistanceReferenceLine = 0.05;
  s.bufferReference = s.collisionRadius;
  s.buffer_for_merging_tolerance = 0.1;
  s.refLineInterpInc = 0.2;
  s.additionalStepsForReferenceLongerHorizon = 4;
  strcpy(s.cplexModelpath, "cplexmodel/");
  s.useSos = false;
  s.useBranchingPriorities = false;
  s.warmstartType = MiqpPlannerWarmstartType::NO_WARMSTART;
  s.parallelMode = MiqpPlannerParallelMode::AUTO;
  s.max_velocity_fitting = 20.0;
  s.buffer_cplex_outputs = false;
  s.obstacle_roi_filter = false;
  s.obstacle_roi_behind_distance = 5.0;
  s.obstacle_roi_front_distance = 30.0;
  s.obstacle_roi_side_distance = 15;
  return s;
}

inline Settings ApolloDefaultSettings() {
  Settings s = DefaultSettings();
  strcpy(s.cplexModelpath,
         "../bazel-bin/modules/planning/libplanning_component.so.runfiles/"
         "miqp_planner/cplex_modfiles/");
  s.buffer_cplex_outputs = true;
  return s;
}

}  // namespace planner
}  // namespace miqp

#endif  // MIQP_PLANNER_DATA_HEADER


// Copyright 2010-2014, D. E. Shaw Research.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt )

#ifndef BOOST_RANDOM_COUNTER_BASED_ENGINE_HPP
#define BOOST_RANDOM_COUNTER_BASED_ENGINE_HPP

#include <boost/array.hpp>
#include <boost/cstdint.hpp>
#include <boost/limits.hpp>
#include <boost/random/detail/seed.hpp>
#include <boost/random/detail/seed_impl.hpp>
#include <boost/random/detail/operators.hpp>
#include <boost/integer/static_min_max.hpp>
#include <boost/integer/static_log2.hpp>
#include <boost/integer/integer_mask.hpp>
#include <boost/random/detail/counter_traits.hpp>

#include <iosfwd>
#include <utility>
#include <stdexcept>
#include <algorithm>

#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
#include <initializer_list>
#endif

namespace boost{
namespace random{

template<typename UintType,
         typename Prf,
         unsigned CtrBits = static_unsigned_min<64u, detail::counter_traits<typename Prf::domain_type>::Nbits/2>::value,
         unsigned w = std::numeric_limits<UintType>::digits,
         typename DomainTraits = detail::counter_traits<typename Prf::domain_type>,
         typename RangeTraits = detail::counter_traits<typename Prf::range_type>,
         typename KeyTraits = detail::counter_traits<typename Prf::key_type>
>
struct counter_based_engine {
    typedef UintType result_type;
    BOOST_STATIC_CONSTANT(unsigned, word_size = w);
    BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);

    // The following typedefs *extend* the standard
    // Random Number Engine concept.
    typedef Prf prf_type;
    BOOST_STATIC_CONSTANT(unsigned, counter_bits = CtrBits);
    typedef typename Prf::domain_type domain_type;
    typedef typename Prf::range_type range_type;
    typedef typename Prf::key_type key_type;
    typedef DomainTraits domain_traits;
    typedef RangeTraits range_traits;
    typedef KeyTraits key_traits;

protected:
    BOOST_STATIC_ASSERT(CtrBits <= DomainTraits::Nbits);
    BOOST_STATIC_ASSERT(CtrBits > 0);

    BOOST_STATIC_ASSERT( std::numeric_limits<UintType>::digits >= w );
    BOOST_STATIC_CONSTANT(unsigned, CtrBitsBits = static_log2<DomainTraits::Nbits>::value);

    prf_type b;
    domain_type c;
    range_type v;
    unsigned next;

    // new values for c and next, maintaining the
    // invariant that v=b(c).
    void setctr(domain_type newc, unsigned newnext){
        c = newc;
        v = b(c);
        next = newnext;
    }

    // We avoid collisions between engines with different CtrBits by
    // embedding the value CtrBits-1 in the high few bits of the last
    // element of Prf's key.  If we didn't do this, it would be too
    // easy for counter_based_engine<Prf, N> and
    // counter_based_engine<Prf, M> to "collide", producing
    // overlapping streams.
    //
    // When we accept a key from the user, e.g., seed(arithmetic) or
    // seed(key_type), an exception is thrown by chk_highkeybits if
    // the specified key has any high bits set.  On the other hand,
    // set_highkeybits, which is called by the seed_seq constructor
    // and seeder, quietly ignores high bits in its argument.
    key_type chk_highkeybits(key_type k){
        if( KeyTraits::template clr_highbits<CtrBitsBits>(k) )
            BOOST_THROW_EXCEPTION(std::invalid_argument("counter_based_engine:: high bits of key are reserved for internal use."));
        return KeyTraits::template incr<CtrBitsBits>(k, CtrBits-1);
    }

    key_type set_highkeybits(key_type k){
        KeyTraits::template clr_highbits<CtrBitsBits>(k);
        return KeyTraits::template incr<CtrBitsBits>(k, CtrBits-1);
    }

    template <typename SeedSeq>
    key_type make_key_from_seedseq(SeedSeq& seq){
        return set_highkeybits(KeyTraits::_make_counter_from_seedseq(seq));
    }

    template <typename It>
    key_type make_key_from_range(It first, It last, It *endp){
#if 1
        // This is here because test_iterator_seed in
        // test_generator.ipp demands it.  But it serves no useful
        // purpose.  KeyTraits::make_counter safely and correctly pads
        // with zeros if there aren't enough values in the range.
        // There's no reason to throw an exception.
        typedef typename std::iterator_traits<It>::value_type it_value_type;
        const unsigned it_value_bits = std::numeric_limits<it_value_type>::digits + std::numeric_limits<it_value_type>::is_signed;
        if( std::distance(first, last)*it_value_bits < KeyTraits::Nbits )
            BOOST_THROW_EXCEPTION(std::invalid_argument("counter_based_engine: not enough bits in range"));
#endif
        // Note that unlike all(?) other engines, the construct-from-range
        // and seed-from-range methods of counter_based_engine use *all*
        // the bits in the given range.  They do not gratuitously and
        // unnecessarily truncate the values to [0, 2^32).  Thankfully,
        // this does not trip over any checks in test_generator.ipp.
        return KeyTraits::make_counter(first, last, endp);
    }

public:
    BOOST_RANDOM_DETAIL_CONSTEXPR static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; }
    BOOST_RANDOM_DETAIL_CONSTEXPR static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { return low_bits_mask_t<w>::sig_bits; }

    counter_based_engine()
        : b()
    {
        //std::cerr << "cbe()\n";
        setctr(DomainTraits::make_counter(), 0);
    }

    counter_based_engine(counter_based_engine& e)
        : b(e.b)
    {
        //std::cerr << "cbe(counter_based_engine&)\n";
        setctr(e.c, e.next);
    }

    counter_based_engine(const counter_based_engine& e)
        : b(e.b)
    {
        //std::cerr << "cbe(const counter_based_engine&)\n";
        setctr(e.c,  e.next);
    }

    counter_based_engine& operator=(const counter_based_engine& rhs){
        b = rhs.b;
        setctr(rhs.c, rhs.next);
        return *this;
    }

    // Note that the arithmetic constructor (and seed method, below)
    // takes a uintmax_t, which may be wider than a result_type.
    // Normal arithmetic promotions allow it to be called with a
    // result_type argument, but counter_based_engine does not
    // unnecessarily restrict the range of possible seeds to the width
    // of a result_type.  The constructor (and seed method) throw if
    // the value contains non-zero bits that are not allowed in the
    // seed, e.g.,
    //
    //    counter_based_engine<uint32_t, philox<2, uint32_t> >(1ull<<28);
    // or
    //    counter_based_engine<uint32_t, philox<4, uint32_t> >(1ull<<60);
    BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(counter_based_engine, boost::uintmax_t, value)
        : b(chk_highkeybits(KeyTraits::make_counter(value)))
    {
        //std::cerr << "cbe(result_type)\n";
        setctr(DomainTraits::make_counter(), 0);
    }

    BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(counter_based_engine, SeedSeq, seq)
        : b(make_key_from_seedseq(seq))
    {
        //std::cerr << "cbe(SeedSeq)\n";
        setctr(DomainTraits::make_counter(), 0);
    }

    template<class It> counter_based_engine(It& first, It last)
        // N.B.  does *NOT* throw if there are non-zero values
        // in the 'leftover' part of the range.  CALLER BEWARE!
        : b(chk_highkeybits(make_key_from_range(first, last, &first)))
    {
        //std::cerr << "cbe(range)\n";
        setctr(DomainTraits::make_counter(), 0);
    }

    template<class It> counter_based_engine(const It& first, It last)
        // N.B.  throws an invalid_argument if there are non-zero
        // values in the 'leftover' part of the range.
        : b(chk_highkeybits(make_key_from_range(first, last, 0)))
    {
        //std::cerr << "cbe(range)\n";
        setctr(DomainTraits::make_counter(), 0);
    }

    void seed(){
        //std::cerr << "cbe::seed()\n";
        b.setkey(KeyTraits::make_counter());
        setctr(DomainTraits::make_counter(), 0);
    }

    BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(counter_based_engine, boost::uintmax_t, value)
    {
        //std::cerr << "cbe::seed(arithmetic)\n";
        b.setkey(chk_highkeybits(KeyTraits::make_counter(value)));
        setctr(DomainTraits::make_counter(), 0);
    }

    BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(counter_based_engine, SeedSeq, seq){
        //std::cerr << "cbe::seed(SeedSeq)\n" << "\n";
        b.setkey(make_key_from_seedseq(seq));
        setctr(DomainTraits::make_counter(), 0);
    }

    template<class It>
    void seed(It& first, It last){
        //std::cerr << "cbe::seed(range)\n";
        //
        // N.B.  does *NOT* throw if there are non-zero values
        // in the 'leftover' part of the range.  CALLER BEWARE!
        b.setkey(chk_highkeybits(make_key_from_range(first, last, &first)));
        setctr(DomainTraits::make_counter(), 0);
    }

    template<class It>
    void seed(const It& first, It last){
        //std::cerr << "cbe::seed(range)\n";
        //
        // N.B.  throws an invalid_argument if there are non-zero
        // values in the 'leftover' part of the range.
        b.setkey(chk_highkeybits(make_key_from_range(first, last, 0)));
        setctr(DomainTraits::make_counter(), 0);
    }

    BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(counter_based_engine, lhs, rhs){
        return DomainTraits::is_equal(lhs.c, rhs.c) &&
            lhs.next == rhs.next &&
            lhs.b == rhs.b;
    }

    BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(counter_based_engine)

    BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, counter_based_engine, f){
        os << (f.next) << ' ';
        DomainTraits::insert(os, f.c) << ' ';
        KeyTraits::insert(os,  f.b.getkey());
        return os;
    }

    BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, counter_based_engine, f){
        unsigned newnext;
        is >> newnext;
        domain_type newc;
        DomainTraits::extract(is, newc);
        key_type newk;
        KeyTraits::extract(is, newk);
        if( is ){
            f.b.setkey(newk);
            f.setctr(newc, newnext);
        }
        return is;
    }

    result_type operator()(){
        if( next == results_per_counter() )
            setctr(DomainTraits::template incr<CtrBits>(c), 0);
        return RangeTraits::template at<result_type, w>(next++, v);
    }

    void discard(boost::uintmax_t skip){
        const unsigned Nresult = results_per_counter();
	unsigned newnext = next + (skip % Nresult);
        skip /= Nresult;
        if (newnext > Nresult) {
            newnext -= Nresult;
	    skip++;
        }
        // next==0 is a corner case that only occurs at the beginning
        // of the sequence.  In order for operator== to work properly,
        // we must disambiguate (next=0,c+1) from (next=Nresult, c) here.
        if(newnext==0 && skip){
            newnext = results_per_counter();
            skip -= 1;
        }
        setctr(DomainTraits::template incr<CtrBits>(c, skip), newnext);
    }

    template <class Iter>
    void generate(Iter first, Iter last)
    { detail::generate_from_int(*this, first, last); }

    // The member functions below *extend* the standard Random Number
    // Engine concept.
    //
    // The restart method, along with additional constructors and
    // seeders allow the caller to quickly 'restart' the
    // counter_based_engine with a new 'base counter'.  Restart is
    // very fast, and restarted counter_based_engines will produce
    // independent sequences as long as thier 'base counters' differ
    // in at least one bit.

    // restart - restart the counter with a new 'base counter'.  The
    //  Prf and key are unchanged.  The high CtrBits of the new base
    //  counter must be zero - those bits are incremented by the
    //  engine's operator()() and discard() members.
    void restart(domain_type base){
        if( DomainTraits::template clr_highbits<CtrBits>(base) )
            BOOST_THROW_EXCEPTION(std::invalid_argument("counter_based_engine:: high bits of key are reserved for internal use."));

        setctr(base, 0);
    }

#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
    template <typename V>
    void restart(std::initializer_list<V> il){
        restart( DomainTraits::make_counter(il) );
    }
#endif

    // Constructor and seed() method to construct or re-seed a
    // counter_based_engine from a key or a Prf and an optional base
    // counter.
    explicit counter_based_engine(key_type k, domain_type base = DomainTraits::make_counter()) :
        b(chk_highkeybits(k)), c(base), next(){
        if( DomainTraits::template clr_highbits<CtrBits>(base) )
            BOOST_THROW_EXCEPTION(std::invalid_argument("counter_based_engine base counter overlaps with counter bits"));
    }

    explicit counter_based_engine(const Prf& _b, domain_type base = DomainTraits::make_counter()) : b(_b), c(base), next(){
        chk_highkeybits(b.getkey());
        if( DomainTraits::clr_highbits<CtrBits>(base) )
            BOOST_THROW_EXCEPTION(std::invalid_argument("counter_based_engine base counter overlaps with counter bits"));
    }

    void seed(key_type k, domain_type base){
        //std::cerr << "cbe::seed(key_type, base)\n";
        *this = counter_based_engine(k, base);
    }

    void seed(const Prf& _b, domain_type base){
        //std::cerr << "cbe::seed(Prf, base)\n";
        *this = counter_based_engine(_b, base);
    }

    // results_per_counter - returns the number of random results made
    //  available by each invocation of the prf.  The total length of
    //  the sequence is results_per_counter() * 2^counter_bits.
    static unsigned results_per_counter(){
        return RangeTraits::template size<w>();
    }
};

} // namespace random
} // namespace boost

#endif // BOOST_RANDOM_COUNTER_BASED_ENGINE_HPP


#include <boost/sort/spreadsort/float_sort.hpp>


#include "ompl/geometric/planners/prm/PRMsep.h"
#include <ompl/base/PlannerData.h>
#include <ompl/base/PlannerDataGraph.h>
#include <ompl/base/goals/GoalState.h>
#include <ompl/geometric/planners/prm/ConnectionStrategy.h>
#include <ompl/base/objectives/PathLengthOptimizationObjective.h>
#include <ompl/tools/config/MagicConstants.h>
#include <boost/foreach.hpp>
#include <boost/graph/astar_search.hpp>

#include <chrono>

#define foreach BOOST_FOREACH

namespace ompl
{
    namespace magic
    {
        /** \brief The number of nearest neighbors to consider by
            default in the construction of the PRM roadmap */
        static const unsigned int DEFAULT_NEAREST_NEIGHBORS = 25;
        static const unsigned int FIND_INVALID_STATE_ATTEMPTS_WITHOUT_TERMINATION = 1000;
    }  // namespace magic
}  // namespace ompl

ompl::geometric::PRMsep::PRMsep(const base::SpaceInformationPtr &si) : ompl::geometric::PRM(si, false)
{
    setName("PRMsep");
}

ompl::geometric::PRMsep::PRMsep(const base::SpaceInformationPtr &si, base::PlannerData* pd) : PRMsep(si)
{
    setPlannerData(pd);
}

void ompl::geometric::PRMsep::clear()
{
    Planner::clear();
    sampler_.reset();
    simpleSampler_.reset();
    clearQuery();

    iterations_ = 0;
    bestCost_ = base::Cost(std::numeric_limits<double>::quiet_NaN());
}

void ompl::geometric::PRMsep::setPlannerData(base::PlannerData* pd)
{
    pd_ = pd;
    setup_ = false;
    OMPL_INFORM("PRMsep: Planner data set.");
}

void ompl::geometric::PRMsep::setup()
{
    PRM::setup();

    if(pd_ != nullptr && !planner_data_set_) {
        copyPlannerDataToGraph();
        planner_data_set_ = true;
        OMPL_INFORM("PRMsep: Set Roadmap with %d milestones and %d edges.", milestoneCount(), edgeCount());
    }

    OMPL_INFORM("PRMsep: Set up.");
}

void ompl::geometric::PRMsep::copyPlannerDataToGraph()
{
    std::vector<Vertex> inserted_vertices;

    unsigned int nv = pd_->numVertices();

    for (unsigned int i = 0; i < nv; ++i)
    {
        std::map<unsigned int, const ompl::base::PlannerDataEdge *> nbrs;
        pd_->getEdges(i, nbrs);

        std::map<unsigned int, const ompl::base::PlannerDataEdge *>::const_iterator it;

        std::vector<Vertex> neighbors;
        for (it = nbrs.begin(); it != nbrs.end(); ++it) {
            if(i > it->first) {
                neighbors.push_back(inserted_vertices[it->first]);
            }
        }

        base::State* clone = si_->cloneState(pd_->getVertex(i).getState());
        inserted_vertices.push_back(addMilestoneFromPlannerData(clone, neighbors));
    }
}

ompl::geometric::PRM::Vertex ompl::geometric::PRMsep::addMilestoneFromPlannerData(base::State *state, const std::vector<Vertex>& neighbors)
{
    std::lock_guard<std::mutex> _(graphMutex_);

    Vertex m = boost::add_vertex(g_);
    stateProperty_[m] = state;
    totalConnectionAttemptsProperty_[m] = 1;
    successfulConnectionAttemptsProperty_[m] = 0;

    // Initialize to its own (dis)connected component.
    disjointSets_.make_set(m);

    foreach (Vertex n, neighbors) {
        totalConnectionAttemptsProperty_[m]++;
        totalConnectionAttemptsProperty_[n]++;
        successfulConnectionAttemptsProperty_[m]++;
        successfulConnectionAttemptsProperty_[n]++;
        const base::Cost weight = opt_->motionCost(stateProperty_[n], stateProperty_[m]);
        const Graph::edge_property_type properties(weight);
        boost::add_edge(n, m, properties, g_);
        uniteComponents(n, m);
    }

    nn_->add(m);

    return m;
}

double ompl::geometric::PRMsep::debugFreeSpace(base::State *state)
{
    if (!sampler_)
        sampler_ = si_->allocValidStateSampler();

    if (sampler_->sample(state))
        return si_->getStateValidityChecker()->clearance(state);

    return 0.0;
}

void ompl::geometric::PRMsep::constructRoadmap(const unsigned int max_number_milestones)
{
    PRM::clear();

    if (!sampler_)
        sampler_ = si_->allocValidStateSampler();
    if (!simpleSampler_)
        simpleSampler_ = si_->allocStateSampler();

    OMPL_INFORM("PRMsep: Construct roadmap...");

    base::State *workState = si_->allocState();

    const ompl::base::StateValidityCheckerPtr& svc = si_->getStateValidityChecker();

    // collect milestones and add them to the graph without connecting them to each other
    unsigned int counter=0, rejection_counter=0;
    double sample_clearance;
    while(counter < max_number_milestones) {
        bool found = false;
        unsigned int attempts = 0;

        while (attempts < magic::FIND_INVALID_STATE_ATTEMPTS_WITHOUT_TERMINATION && !found) {
            if (sampler_->sample(workState)) {
                found = true;/*
                // check if any other Vertex is in hyper sphere around new vertex
                Vertex v = boost::add_vertex(g_);
                stateProperty_[v] = workState;

                // if in box, evaluate cost function and compare to d_obstacle. Check only for 25 nearest
                std::vector<Vertex> nn_list;
                nn_->nearestK(v, magic::DEFAULT_NEAREST_NEIGHBORS, nn_list);
                double distance;
                for (size_t i=0; i<nn_list.size() && found; i++) {
                    base::State* st = stateProperty_[nn_list[i]];
                    bool new_state = i==0;
                    if (svc->isValid(workState, distance, st, new_state) == false) {
                        found = false;
                        break;
                    }
                }
                if (!found) rejection_counter++;

                boost::remove_vertex(v, g_);*/
                counter++;
            }
            attempts++;
        }
        if(found) {
            connectionStrategy_ = KStrategy<Vertex>(magic::DEFAULT_NEAREST_NEIGHBORS, nn_);
            addMilestone(si_->cloneState(workState));
            //counter++;
            if (milestoneCount()%1000 == 0) {
                OMPL_INFORM("PRMsep: %d milestones and %d edges found. %d samples rejected meanwhile.", milestoneCount(), edgeCount(), rejection_counter);
                rejection_counter = 0;
            }
        }
        else {
            OMPL_INFORM("PRMsep: Construction of Roadmap aborted due to too many consecutive rejections.");
            break;
        }
    }

    si_->freeState(workState);

    OMPL_INFORM("PRMsep: constructed roadmap with %d milestones and %d edges.", milestoneCount(), edgeCount());
}

void ompl::geometric::PRMsep::insertStartAndGoalStates(unsigned int number_goals)
{
    // Add the valid start states as milestones
    while (const base::State *st = pis_.nextStart()) {
        startM_.push_back(addMilestone(si_->cloneState(st)));
    }

    auto *goal = dynamic_cast<base::GoalSampleableRegion *>(pdef_->getGoal().get());

    if (goal == nullptr)
    {
        OMPL_ERROR("%s: Unknown type of goal", getName().c_str());
        return;
    }

    if (!goal->couldSample())
    {
        OMPL_ERROR("%s: Insufficient states in sampleable goal region", getName().c_str());
        return;
    }

    // check all samples if they are in goal region
    /*foreach (const Vertex v, boost::vertices(g_)) {
        const base::State* st = stateProperty_[v];
        if (goal->isSatisfied(st) && goal->isStartGoalPairValid(st, stateProperty_[startM_[0]])) {
            goalM_.push_back(addMilestone(si_->cloneState(st)));
            if (goalM_.size() >= number_goals)
                break;
        }
    }*/

    /*if (goalM_.size() < number_goals) {
        const base::StateSpacePtr& space = si_->getStateSpace();
        OMPL_INFORM("PRMsep: Sample more goal states... At max %i new goals.", goal->maxSampleCount());
        for (unsigned int i=0; i<goal->maxSampleCount() && goalM_.size() < number_goals; i++)
        {
            const base::State* st = pis_.nextGoal(base::timedPlannerTerminationCondition(1.0));
            if (st)
                goalM_.push_back(addMilestone(si_->cloneState(st)));
        }
    }
    if (goalM_.empty())
    {
        OMPL_ERROR("%s: Unable to find any valid goal states", getName().c_str());
        return;
    }*/

    OMPL_INFORM("PRMsep: Found %i start states and %i goal states.", startM_.size(), goalM_.size());
}

bool ompl::geometric::PRMsep::getNewGoalState(const base::PlannerTerminationCondition &ptc, Vertex& v)
{
    auto *goal = dynamic_cast<base::GoalSampleableRegion *>(pdef_->getGoal().get());

    if (goal == nullptr)
    {
        OMPL_ERROR("%s: Unknown type of goal", getName().c_str());
        return false;
    }

    if (!goal->couldSample())
    {
        OMPL_ERROR("%s: Insufficient states in sampleable goal region", getName().c_str());
        return false;
    }

    // collect newly sampled goal states
    while (!ptc()) {
        const base::State* goal_state = pis_.nextGoal();
        if (goal_state == nullptr) {
            break;
        }
        if (goal_state && si_->isValid(goal_state)) {
            goalM_.push_back(addMilestone(si_->cloneState(goal_state)));
        }
    }

    // select next goal state to perform A* on based on cost heuristic
    int best_idx = -1;
    base::Cost best_cost(opt_->infiniteCost());
    for (size_t i=0; i<goalM_.size(); i++) {
        base::Cost cost = costHeuristic(startM_[0], goalM_[i]);
        if (opt_->isCostBetterThan(cost, best_cost)) {
            best_cost = cost;
            best_idx = (int)i;
        }
    }
    if (best_idx != -1) {
        v = goalM_[best_idx];
        goalM_.erase(goalM_.begin() + best_idx);
        return true;
    }

    return false;
}

bool ompl::geometric::PRMsep::constructOptimalSolution(const base::PlannerTerminationCondition &ptc, const std::vector<Vertex> &starts, const std::vector<Vertex> &goals,
                                                       base::PathPtr &solution)
{
    base::Goal *g = pdef_->getGoal().get();
    base::Cost sol_cost(opt_->infiniteCost());
    Vertex goal;
    goalM_.clear();

    while (!ptc()) {
        if (getNewGoalState(ptc, goal)) {
            foreach (Vertex start, starts)
            {
                // we lock because the connected components algorithm is incremental and may change disjointSets_
                graphMutex_.lock();
                bool same_component = sameComponent(start, goal);
                graphMutex_.unlock();

                if (same_component && g->isStartGoalPairValid(stateProperty_[goal], stateProperty_[start]))
                {
                    base::PathPtr p = constructSolution(start, goal);
                    if (p)
                    {
                        base::Cost pathCost = p->cost(opt_);
                        OMPL_INFORM("PRMsep: Found solution with length %f and cost %f", p->length(), pathCost.value());
                        if (opt_->isCostBetterThan(pathCost, bestCost_))
                            bestCost_ = pathCost;
                        // Check if optimization objective is satisfied
                        if (opt_->isSatisfied(pathCost))
                        {
                            solution = p;
                            return true;
                        }
                        if (opt_->isCostBetterThan(pathCost, sol_cost))
                        {
                            solution = p;
                            sol_cost = pathCost;
                        }
                    }
                }
                else
                    OMPL_WARN("PRMsep: Start/Goal pair is not connected.");
            }
        }
    }

    /*foreach (Vertex start, starts)
    {
        foreach (Vertex goal, goals)
        {
            // we lock because the connected components algorithm is incremental and may change disjointSets_
            graphMutex_.lock();
            bool same_component = sameComponent(start, goal);
            graphMutex_.unlock();

            if (same_component && g->isStartGoalPairValid(stateProperty_[goal], stateProperty_[start]))
            {
                base::PathPtr p = constructSolution(start, goal);
                if (p)
                {
                    base::Cost pathCost = p->cost(opt_);
                    OMPL_INFORM("PRMsep: Found solution with length %f and cost %f", p->length(), pathCost.value());
                    if (opt_->isCostBetterThan(pathCost, bestCost_))
                        bestCost_ = pathCost;
                    // Check if optimization objective is satisfied
                    if (opt_->isSatisfied(pathCost))
                    {
                        solution = p;
                        return true;
                    }
                    if (opt_->isCostBetterThan(pathCost, sol_cost))
                    {
                        solution = p;
                        sol_cost = pathCost;
                    }
                }
            }
            else
                OMPL_WARN("PRMsep: Start/Goal pair is not connected.");
        }
    }*/

    return solution.get() != nullptr;
}

ompl::base::PlannerStatus ompl::geometric::PRMsep::solve(const base::PlannerTerminationCondition &ptc)
{
    OMPL_INFORM("PRMsep: Search for an optimal path...");

    if (!isSetup())
        setup();

    if (boost::num_vertices(g_) == 0) {
        OMPL_INFORM("PRMsep: There is no roadmap available, construct a new one.");
        constructRoadmap(10000);
    }

    insertStartAndGoalStates(10);

    base::PathPtr sol;
    constructOptimalSolution(ptc, startM_, goalM_, sol);

    if (sol)
    {
        // sol->print(std::cout);
        OMPL_INFORM("PRMsep: Best solution has length %f and cost %f", sol->length(), sol->cost(opt_).value());
        base::PlannerSolution psol(sol);
        psol.setPlannerName(getName());
        // if the solution was optimized, we mark it as such
        psol.setOptimized(opt_, bestCost_, addedNewSolution());
        pdef_->addSolutionPath(psol);
    }

    return sol ? ompl::base::PlannerStatus::EXACT_SOLUTION : ompl::base::PlannerStatus::TIMEOUT;
}

void ompl::geometric::PRMsep::solveCtoC(const base::State* q_start, const base::State* q_goal, double& duration, double& cost)
{
    OMPL_INFORM("PRMsep: Search for an optimal path...");

    if (!isSetup())
        setup();

    if (boost::num_vertices(g_) == 0) {
        OMPL_INFORM("PRMsep: There is no roadmap available, construct a new one.");
        constructRoadmap(10000);
    }

    startM_.clear();
    startM_.push_back(addMilestone(si_->cloneState(q_start)));
    goalM_.clear();
    goalM_.push_back(addMilestone(si_->cloneState(q_goal)));

    auto start_chrono = std::chrono::steady_clock::now();
    base::PathPtr p = constructSolution(startM_[0], goalM_[0]);
    auto duration_chrono = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - start_chrono);
    duration = (double)duration_chrono.count() / (1000.0*1000.0);

    if (p) {
        base::Cost pathCost = p->cost(opt_);
        cost = pathCost.value();
    }
    else {
        cost = -1.0;
    }
}

ompl::base::Cost ompl::geometric::PRMsep::costHeuristic(Vertex v, Vertex goal) const
{
    return opt_->motionCostHeuristic(stateProperty_[v], stateProperty_[goal]); // opt_->motionCostHeuristic(stateProperty_[v], stateProperty_[goal]); // use cost-to-go heuristic
}


#define BOOST_TEST_DYN_LINK

#include <boost/test/unit_test.hpp>
#include <boost/test/results_collector.hpp>
#include "BitCommitment.h"
#include <iostream>
#include "Utilities.h"

#include <omp.h>

BOOST_AUTO_TEST_CASE(BitCommitment_test_1)
{
    mpz_class b = Utilities::StringToNumber("abc");

    double start = omp_get_wtime();
    CommitData d = GenCommitData(b);
    double end = omp_get_wtime();

    std::cout << "Bit Commitment Test 1 Timing " << end - start << "s" << std::endl;

    std::string commitHash = Hash(d);
    std::string commitR1   = d.r1;

    // Life moves on, d is suddenly revealed, and then...
    mpz_class commitHashMpz = Utilities::StringToNumber(commitHash);
    mpz_class r1Mpz = Utilities::StringToNumber(commitR1);

    BOOST_CHECK( Verify(d,commitHash,commitR1));
}

BOOST_AUTO_TEST_CASE(BitCommitment_test_2)
{
    mpz_class b = Utilities::StringToNumber("abcdefghijklmnopqrstuvwxyz");

    double start = omp_get_wtime();
    CommitData d = GenCommitData(b);
    double end = omp_get_wtime();

    std::cout << "Bit Commitment Test 2 Timing " << end - start << "s" << std::endl;

    std::string commitHash = Hash(d);
    std::string commitR1   = d.r1;

    std::string serialStr = d.Serialize();
    CommitData newD;
    newD.Deserialize(serialStr);

    // Life moves on, d is suddenly revealed, and then...
    BOOST_CHECK( Verify(newD,commitHash,commitR1));
}


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#define NT2_UNIT_MODULE "boost::dispatch::meta::is_signed"

#include <boost/simd/sdk/config/types.hpp>
#include <boost/dispatch/meta/is_signed.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/basic.hpp>

////////////////////////////////////////////////////////////////////////////////
// Test that is_signed is correct
////////////////////////////////////////////////////////////////////////////////
NT2_TEST_CASE(is_signed)
{
  using boost::dispatch::meta::is_signed;
  using namespace boost::simd;

  NT2_TEST( is_signed<double>::value        );
  NT2_TEST( is_signed<float>::value         );
  NT2_TEST( !is_signed<boost::simd::uint64_t>::value);
  NT2_TEST( !is_signed<boost::simd::uint32_t>::value);
  NT2_TEST( !is_signed<boost::simd::uint16_t>::value);
  NT2_TEST( !is_signed<boost::simd::uint8_t>::value );
  NT2_TEST( is_signed<boost::simd::int64_t>::value  );
  NT2_TEST( is_signed<boost::simd::int32_t>::value  );
  NT2_TEST( is_signed<boost::simd::int16_t>::value  );
  NT2_TEST( is_signed<boost::simd::int8_t>::value   );
  NT2_TEST( !is_signed<bool>::value         );
}

NT2_TEST_CASE(is_unsigned)
{
  using boost::dispatch::meta::is_unsigned;
  using namespace boost::simd;

  NT2_TEST( !is_unsigned<double>::value        );
  NT2_TEST( !is_unsigned<float>::value         );
  NT2_TEST(  is_unsigned<boost::simd::uint64_t>::value );
  NT2_TEST(  is_unsigned<boost::simd::uint32_t>::value );
  NT2_TEST(  is_unsigned<boost::simd::uint16_t>::value );
  NT2_TEST(  is_unsigned<boost::simd::uint8_t>::value  );
  NT2_TEST( !is_unsigned<boost::simd::int64_t>::value  );
  NT2_TEST( !is_unsigned<boost::simd::int32_t>::value  );
  NT2_TEST( !is_unsigned<boost::simd::int16_t>::value  );
  NT2_TEST( !is_unsigned<boost::simd::int8_t>::value   );
  NT2_TEST(  is_unsigned<bool>::value          );
}


#include <boost/numeric/ublas/vector_sparse.hpp>


// Copyright (c) 2015 The Nyancoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "arith_uint256.h"
#include "chainparams.h"
#include "nyancoin.h"
#include "test/test_bitcoin.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(nyancoin_tests, TestingSetup)

/**
 * the maximum block reward at a given height for a block without fees
 */
uint64_t expectedMaxSubsidy(int height) {
    if (height < 100000) {
        return 1000000 * COIN;
    } else if (height < 145000) {
        return 500000 * COIN;
    } else if (height < 200000) {
        return 250000 * COIN;
    } else if (height < 300000) {
        return 125000 * COIN;
    } else if (height < 400000) {
        return  62500 * COIN;
    } else if (height < 500000) {
        return  31250 * COIN;
    } else if (height < 600000) {
        return  15625 * COIN;
    } else {
        return  10000 * COIN;
    }
}

/**
 * the minimum possible value for the maximum block reward at a given height
 * for a block without fees
 */
uint64_t expectedMinSubsidy(int height) {
    if (height < 100000) {
        return 0;
    } else if (height < 145000) {
        return 0;
    } else if (height < 200000) {
        return 250000 * COIN;
    } else if (height < 300000) {
        return 125000 * COIN;
    } else if (height < 400000) {
        return  62500 * COIN;
    } else if (height < 500000) {
        return  31250 * COIN;
    } else if (height < 600000) {
        return  15625 * COIN;
    } else {
        return  10000 * COIN;
    }
}

BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
    int nHeight = 0;
    int nStepSize= 1;
    const CChainParams& mainParams = Params(CBaseChainParams::MAIN);
    CAmount nSum = 0;
    uint256 prevHash = uint256S("0");

    for (nHeight = 0; nHeight <= 100000; nHeight++) {
        const Consensus::Params& params = mainParams.GetConsensus(nHeight);
        CAmount nSubsidy = GetNyancoinBlockSubsidy(nHeight, params, prevHash);
        BOOST_CHECK(MoneyRange(nSubsidy));
        BOOST_CHECK(nSubsidy <= 1000000 * COIN);
        nSum += nSubsidy * nStepSize;
    }
    for (; nHeight <= 145000; nHeight++) {
        const Consensus::Params& params = mainParams.GetConsensus(nHeight);
        CAmount nSubsidy = GetNyancoinBlockSubsidy(nHeight, params, prevHash);
        BOOST_CHECK(MoneyRange(nSubsidy));
        BOOST_CHECK(nSubsidy <= 500000 * COIN);
        nSum += nSubsidy * nStepSize;
    }
    for (; nHeight < 600000; nHeight++) {
        const Consensus::Params& params = mainParams.GetConsensus(nHeight);
        CAmount nSubsidy = GetNyancoinBlockSubsidy(nHeight, params, prevHash);
        CAmount nExpectedSubsidy = (500000 >> (nHeight / 100000)) * COIN;
        BOOST_CHECK(MoneyRange(nSubsidy));
        BOOST_CHECK_EQUAL(nSubsidy, nExpectedSubsidy);
        nSum += nSubsidy * nStepSize;
    }

    //test sum +- ~10billion
    arith_uint256 upperlimit = arith_uint256("95e14ec776380000"); //108 billion doge
    BOOST_CHECK(nSum <= upperlimit);

    arith_uint256 lowerlimit = arith_uint256("7a1fe16027700000"); //88 billion doge
    BOOST_CHECK(nSum >= lowerlimit);

    // Test reward at 600k+ is constant
    const Consensus::Params& params = mainParams.GetConsensus(nHeight);
    CAmount nConstantSubsidy = GetNyancoinBlockSubsidy(nHeight, params, prevHash);
    BOOST_CHECK_EQUAL(nConstantSubsidy, 10000 * COIN);

    nConstantSubsidy = GetNyancoinBlockSubsidy(700000, params, prevHash);
    BOOST_CHECK_EQUAL(nConstantSubsidy, 10000 * COIN);
}

BOOST_AUTO_TEST_CASE(hardfork_parameters)
{
    SelectParams(CBaseChainParams::MAIN);
    const Consensus::Params& initialParams = Params().GetConsensus(0);

    BOOST_CHECK_EQUAL(initialParams.nPowTargetTimespan, 14400);
    BOOST_CHECK_EQUAL(initialParams.fAllowLegacyBlocks, true);
    BOOST_CHECK_EQUAL(initialParams.fDigishieldDifficultyCalculation, false);

    const Consensus::Params& initialParamsEnd = Params().GetConsensus(144999);
    BOOST_CHECK_EQUAL(initialParamsEnd.nPowTargetTimespan, 14400);
    BOOST_CHECK_EQUAL(initialParamsEnd.fAllowLegacyBlocks, true);
    BOOST_CHECK_EQUAL(initialParamsEnd.fDigishieldDifficultyCalculation, false);

    const Consensus::Params& digishieldParams = Params().GetConsensus(145000);
    BOOST_CHECK_EQUAL(digishieldParams.nPowTargetTimespan, 60);
    BOOST_CHECK_EQUAL(digishieldParams.fAllowLegacyBlocks, true);
    BOOST_CHECK_EQUAL(digishieldParams.fDigishieldDifficultyCalculation, true);

    const Consensus::Params& digishieldParamsEnd = Params().GetConsensus(371336);
    BOOST_CHECK_EQUAL(digishieldParamsEnd.nPowTargetTimespan, 60);
    BOOST_CHECK_EQUAL(digishieldParamsEnd.fAllowLegacyBlocks, true);
    BOOST_CHECK_EQUAL(digishieldParamsEnd.fDigishieldDifficultyCalculation, true);

    const Consensus::Params& auxpowParams = Params().GetConsensus(11327960);
    BOOST_CHECK_EQUAL(auxpowParams.nHeightEffective, 11327960);
    BOOST_CHECK_EQUAL(auxpowParams.nPowTargetTimespan, 60);
    BOOST_CHECK_EQUAL(auxpowParams.fAllowLegacyBlocks, false);
    BOOST_CHECK_EQUAL(auxpowParams.fDigishieldDifficultyCalculation, true);

    const Consensus::Params& auxpowHighParams = Params().GetConsensus(700000); // Arbitrary point after last hard-fork
    BOOST_CHECK_EQUAL(auxpowHighParams.nPowTargetTimespan, 60);
    BOOST_CHECK_EQUAL(auxpowHighParams.fAllowLegacyBlocks, false);
    BOOST_CHECK_EQUAL(auxpowHighParams.fDigishieldDifficultyCalculation, true);
}

BOOST_AUTO_TEST_SUITE_END()


#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <cctbx/math/cos_sin_table.h>

namespace cctbx { namespace math { namespace boost_python {
namespace {

  struct cos_sin_table_wrappers
  {
    typedef cos_sin_table<> w_t;

    static void
    wrap()
    {
      using namespace boost::python;
      class_<w_t>("cos_sin_table", no_init)
        .def(init<int>())
        .def("n_points", &w_t::n_points)
        .def("get", &w_t::get)
      ;
    }
  };

  void init_module()
  {
    cos_sin_table_wrappers::wrap();
  }

} // namespace <anonymous>
}}} // namespace cctbx::math::boost_python

BOOST_PYTHON_MODULE(cctbx_math_ext)
{
  cctbx::math::boost_python::init_module();
}