#include "dsa_common.h"

#include "certificate.h"

#include <boost/filesystem.hpp>
#include "module/storage.h"
#include "util/string.h"

#include <cmath>
#include <memory>
using std::unique_ptr;
#include <random>
#include <string>

#if defined(_MSC_VER)
#include <openssl/applink.c>
#endif

#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/x509v3.h>

using BIO_FILE_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
using EVP_KEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
using X509_ptr = std::unique_ptr<X509, decltype(&::X509_free)>;

#include "module/logger.h"

namespace dsa {

void generate_certificate() {
  int rc;

  RSA_ptr rsa(RSA_new(), ::RSA_free);
  BN_ptr bn(BN_new(), ::BN_free);

  if (rc = BN_set_word(bn.get(), RSA_F4) != 1) {
    LOG_FATAL(__FILENAME__,
              LOG << "BN_set_word failed!"
                  << " rc=" << rc);
  }

  if (rc = RSA_generate_key_ex(rsa.get(), 4098, bn.get(), NULL) != 1) {
    LOG_FATAL(__FILENAME__,
              LOG << "RSA_generate_key_ex failed!"
                  << " rc=" << rc);
  }

  EVP_KEY_ptr pkey(EVP_PKEY_new(), ::EVP_PKEY_free);
  if (rc = EVP_PKEY_set1_RSA(pkey.get(), rsa.get()) != 1) {
    LOG_FATAL(__FILENAME__,
              LOG << "EVP_PKEY_set1_RSA failed!"
                  << " rc=" << rc);
  }

#if 0
    // write public key
    BIO_FILE_ptr pubkey(BIO_new_file("pubkey.pem", "w"), ::BIO_free);
    if (rc = PEM_write_bio_PUBKEY(pubkey.get(), pkey.get()) != 1) {
      LOG_FATAL(__FILENAME__, LOG << "PEM_write_bio_PUBKEY failed!" << " rc=" << rc);
    }
#endif

  // write private key
  std::string privkey_fname("key.pem");
  BIO_FILE_ptr privkey(BIO_new_file(privkey_fname.c_str(), "w"), ::BIO_free);
  if (rc = PEM_write_bio_RSAPrivateKey(privkey.get(), rsa.get(), NULL, NULL, 0,
                                       NULL, NULL) != 1) {
    LOG_FATAL(__FILENAME__,
              LOG << "PEM_write_bio_RSAPrivate failed!"
                  << " rc=" << rc);
  }

  namespace fs = boost::filesystem;
  fs::permissions(privkey_fname.c_str(), fs::owner_read | fs::owner_write);

  // generate certificate
  X509_ptr x509(X509_new(), ::X509_free);

  X509_set_version(x509.get(), 2L);

  if (rc = X509_set_pubkey(x509.get(), pkey.get()) != 1) {
    LOG_FATAL(__FILENAME__,
              LOG << "X509_set_pubkey failed!"
                  << " rc=" << rc);
  }

  std::random_device rd;
  std::mt19937_64 e2(rd());
  std::uniform_int_distribution<int64_t> dist(std::llround(std::pow(2, 61)),
                                              std::llround(std::pow(2, 62)));

  ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), dist(e2));

  X509_gmtime_adj((ASN1_TIME *)X509_get_notBefore(x509.get()), 0);
  X509_gmtime_adj((ASN1_TIME *)X509_get_notAfter(x509.get()), 0x7fffffff);

  X509_NAME *name;
  name = X509_get_subject_name(x509.get());
  X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1,
                             -1, 0);
  X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC,
                             (unsigned char *)"California", -1, -1, 0);
  X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC,
                             (unsigned char *)"Berkeley", -1, -1, 0);
  X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
                             (unsigned char *)"Acuity Brands, Inc.", -1, -1, 0);
  X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC,
                             (unsigned char *)"Customers", -1, -1, 0);
  X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"*", -1,
                             -1, 0);
  if (X509_set_issuer_name(x509.get(), name) != 1) {
    LOG_FATAL(__FILENAME__, LOG << "X509_set_issuer_name failed!");
  }

  if (!X509_sign(x509.get(), pkey.get(), EVP_sha256())) {
    LOG_FATAL(__FILENAME__, LOG << "X509_sign failed!");
  }

  FILE *f = fopen("certificate.pem", "wb");
  if (!PEM_write_X509(f, x509.get())) {
    fclose(f);
    LOG_FATAL(__FILENAME__, LOG << "PEM_write_X509 failed!");
  }
  fclose(f);

  return;
}

void load_root_certificate(ssl::context &context,
                           boost::system::error_code &error_code) {
  auto &config_bucket = Storage::get_config_bucket();
  string_ certificate = string_from_storage("certificate.pem", config_bucket);
  context.add_certificate_authority(
      boost::asio::buffer(certificate.data(), certificate.size()), error_code);

  if (error_code && ERR_GET_REASON(error_code.value()) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
      LOG_FATAL(__FILENAME__, LOG << "Client failed to verify certificate");
  }
}

bool load_server_certificate(ssl::context &context,
                             boost::system::error_code &error_code) {
  auto &config_bucket = Storage::get_config_bucket();

  string_ certificate = string_from_storage("certificate.pem", config_bucket);
  context.use_certificate_chain(
      boost::asio::buffer(certificate.data(), certificate.size()), error_code);
  if (error_code != boost::system::errc::success) {
    LOG_INFO(__FILENAME__, LOG << "Server failed to load certificate.pem");
    return false;
  }

  string_ privkey = string_from_storage("key.pem", config_bucket);
  context.use_private_key(boost::asio::buffer(privkey.data(), privkey.size()),
                          boost::asio::ssl::context::pem, error_code);
  if (error_code != boost::system::errc::success) {
    LOG_INFO(__FILENAME__, LOG << "Server failed to load key.pem");
    return false;
  }

  return true;
}

}  // namespace dsa


/***********************************************************************
//      AUTHOR:  Zhengwei Xie (Mr), <xiezhengwei@hsc.pku.edu.cn>
//      COMPANY:  Department of Pharmacology, School of Basic Medical
//				Sciences, Peking University,
//				38 Xueyuan Lu, Haidian District,
//				Beijing, 100191, China
//      VERSION:  1.0
//      PAPER :
//		"Genome-scale fluxes were predicted under the guide of enzyme
//		abundance using a novel Hy-per-Cube Shrink Algorithm"
//		Zhengwei Xie, Tianyu Zhang and Qi Ouyang
***********************************************************************/

#include <map>
#include <cmath>
#include <ctime>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <stdio.h>
#include <glpk.h>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <iomanip>

#include "func.h"

using namespace std;
using namespace boost;
#define INFI 1e20
#define ERR 1e-20
#define UP 1
#define LOW 0

int BIO=1;
int ROW = -1;
double LOWCUT = 1e-1;
double MaxFlux=0.0;

map<int,int> tp;
void tp_init() {
    tp[0] = GLP_FX;
    tp[1] = GLP_DB;
    tp[2] = GLP_LO;
    tp[3] = GLP_UP;
}

int
main (int argc, char **argv)
{
	BIO = 0;
	string fname="";
	string confile="";
	string boundsfile="";
	string target_file="";
	string fvafile="";
	string flux_na="";
	string trace_na="";
	string method ="ratio";
	string help="";
	double mxx = 0;
	tp_init();
	for(int i=1; i<argc; i++) {
		if(strcmp(argv[i],"-i") == 0) {
			i++;
			cout<<"Model file : "<<argv[i]<<endl;
			fname += argv[i];
		} else if(strcmp(argv[i],"-c") == 0) {
			i++;
			cout<<"Constraint file (optional) : "<<argv[i]<<endl;
			confile += argv[i];
		} else if(strcmp(argv[i],"-l") == 0) {
			i++;
			cout<<"Inputted boudary file, optional: "<<argv[i]<<endl;
			boundsfile+= argv[i];
		} else if(strcmp(argv[i],"-b") == 0) {
			i++;
			cout<<"Enzyme abundance file (EV) : "<<argv[i]<<endl;
			target_file = argv[i];
		} else if(strcmp(argv[i],"-o") == 0) {
			i++;
			cout<<"Fluxes output file (FV) : "<<argv[i]<<endl;
			flux_na += argv[i];
		} else if(strcmp(argv[i],"--row") == 0) {
			i++;
			cout<<"Number of row in EV file : "<<argv[i]<<endl;
			ROW = atoi(argv[i]);
		}  else if(strcmp(argv[i],"--max") == 0) {
			i++;
			cout<<"Maximum value in EV (optional) : "<<argv[i]<<endl;
			mxx = atof(argv[i]);
		} else if(strcmp(argv[i],"--bio") == 0) {
			i++;
			cout<<"Column index of biomass flux: "<<argv[i]<<endl;
			BIO = atoi(argv[i]);
		} else if(strcmp(argv[i],"--fva") == 0) {
			i++;
			cout<<"Perform FVA and output the file in (optional) : "<<argv[i]<<endl;
			fvafile += argv[i];
		} else if(strcmp(argv[i],"-t") == 0) {
			i++;
			cout<<"Print trace and print to (optional) : "<<argv[i]<<endl;
			trace_na += argv[i];
		}  else if(strcmp(argv[i],"-h") == 0 || strcmp(argv[i],"--help") == 0 ) {
			help += argv[i];
		}  else {
			cout<<"Unrecognized option : "<<argv[i]<<endl;
			exit(0);
		}
	}
	if(fname.length() < 1 || help.length() > 0) {
		cout<<"		Usage : ./hcsa -i toy.mps --row 3 -b EV.txt -o flux.txt -t trace.txt\n";
		cout<<"		-i model.mps\n";
		cout<<"		-c constraint.txt: Extra Constraint file (optional)\n";
		cout<<"		-l boundary.txt: FVA file, Inputted boudary file, optional\n";
		cout<<"		-b EV.txt: Enzyme abundance file (EV)\n";
		cout<<"		-o flux.txt: Fluxes output file (FV) \n";
		cout<<"		--row N: Number of row in EV file\n";
		cout<<"		--max val: Maximum value in EV (optional) \n";
		cout<<"		--bio N: Column index of biomass flux\n";
		cout<<"		--fva variable.txt: Perform FVA and output the file in (optional) \n";
		cout<<"		-t tracefile.txt: print trace and print to (optional) \n";
		cout<<"		-h or --help : Print this help.\n";
		exit(-1);
	}
	if(ROW <= 0) {
		cout<<"Please specify the row number of target file\n";
		cout<<"     --row N \n";
		exit(-2);
	}
	//////////////////////////////////////////////////////////////
	//Loading input files
	glp_prob *lp=NULL;
	lp=glp_create_prob();
	glp_read_mps(lp,GLP_MPS_FILE,NULL,fname.c_str());

	cout<<"Successfully read model from "<<fname<<endl;
	if(strlen(confile.c_str()) > 0) {
		cout<<"Constraint file is "<<confile<<endl;
		get_constraints(lp,confile,tp);
	}
	fstream out2;
	if(flux_na.length() > 0) {
		out2.open(flux_na.c_str(),ios::out);
		cout<<"Output file is :"<<flux_na<<endl;
	} else {
		out2.open("internal_points",ios::out);
		cout<<"Output file is : internal_points. "<<endl;
	}
	fstream out3;
	if(trace_na.length() > 0) {
		out3.open(trace_na.c_str(),ios::out);
	}
	//////////////////////////////////////////////////////////////
	//FVA
	int N = glp_get_num_cols(lp);
	map<int,double> lbs;
	map<int,double> ubs;
	if(boundsfile.length()>0) {
		cout<<"Got bounds from file : "<<boundsfile<<endl;
		readbounds(&lbs,&ubs,boundsfile);
	} else {
		for(int i=1;i<=N;i++) {
			glp_set_obj_coef(lp,i,0.);
		}
		cout<<"Generating column bounds . . .\n";
		for(int i=1;i<=N;i++) {
			glp_set_obj_coef(lp,i,1);
			glp_set_obj_dir(lp,GLP_MAX);
			glp_simplex(lp,NULL);
			ubs[i] = glp_get_col_prim(lp,i);
			glp_set_obj_dir(lp,GLP_MIN);
			glp_simplex(lp,NULL);
			lbs[i] = glp_get_col_prim(lp,i);
			glp_set_obj_coef(lp,i,0);
		}
	}

	//////////////////////////////////////////////////////////////
	//
	cout<<"Initializing directions . . .\n";
	srand(time(0));

	//////////////////////////////////////////////////////////////
	vector<double> target;// = new double[row+1];
	for(int i=1;i<=N+1;i++) {
		target.push_back(0.0);
	}
	read_target(target_file,&target,ROW);

	cout<<"Running HCSA ... "<<endl;
	vector<double> flux;
	for(int i=1;i<=N+1;i++) {
		flux.push_back(0.0);
	}
	hcsa(lp,lbs,ubs,&flux,&target,&out3,method,mxx);
	cout<<"Printing out the flux distribution.\n";
	for(int i=1;i<=N;i++) {
		out2<<flux[i]<<"\n";
	}

	//////////////////////////////////////////////////////////////
	return 0;
}


#include <iostream>
#include <dlib/dnn.h>
#include <dlib/data_io.h>
#include <dlib/gui_widgets.h>

using namespace dlib;

/* ------ Define the CNN for face detection -------------
 target input image is 50 x 50
 3 downsampling layers (8x reduction)
 4 conv layers
*/

// 5x5 conv with 2x downsampling block
template <long num_filters, typename SUBNET> using con5d = con<num_filters, 5, 5, 2, 2, SUBNET>;
// 3x3 conv no downsampling block
template <long num_filters, typename SUBNET> using con3 = con<num_filters, 3, 3, 1, 1, SUBNET>;
// 8x downsampling block using 3 5x5 conv, 32 channels
template <typename SUBNET> using downsampler = relu<bn_con<con5d<32,
    relu<bn_con<con5d<32,
    relu<bn_con<con5d<32,SUBNET>>>>>>>>>;
// rest of the network: 3x3 conv with batch normalization
template <typename SUBNET> using rcon3 = relu<bn_con<con3<32, SUBNET>>>;

// finally add one-channel, 6x6 classifier layer and loss_mmod to complete the network
using net_type = loss_mmod<con<1, 6, 6, 1, 1,
    rcon3<rcon3<rcon3<downsampler<input_rgb_image_pyramid<pyramid_down<6>>>>>>>>;

// --- main ----
int main(int argc, char** argv)
{
    const std::string face_dir = "../data/faces";

    // load dataset
    std::vector<matrix<rgb_pixel>> train_images, test_images;
    std::vector<std::vector<mmod_rect>> train_boxes, test_boxes;

    load_image_dataset(train_images, train_boxes, face_dir+"/training.xml");
    load_image_dataset(test_images, test_boxes, face_dir+"/testing.xml");

    std::cout << "num train images= " << train_images.size() << "\n";
    std::cout << "num of test imamges= " << test_images.size() << "\n";

    // set mmod options- pick the minimal size of face in pixels
    mmod_options options(train_boxes, 40, 40);
    std::cout << "num detector windows" << options.detector_windows.size() << "\n";
    for (auto w : options.detector_windows)
        std::cout << "detector window width by height: " << w.width << " x " << w.height << "\n";
    std::cout << "overlap NMS IOU thresh: " << options.overlaps_nms.get_iou_thresh() << "\n";
    std::cout << "overlap NMS percent covered thresh: " << options.overlaps_nms.get_percent_covered_thresh() << "\n";

    // create the net
    net_type net(options);
    // The MMOD loss requires that the number of filters in the final network layer equal
    // options.detector_windows.size().  So we set that here as well.
    net.subnet().layer_details().set_num_filters(options.detector_windows.size());

    // setup the trainer
    dnn_trainer<net_type> trainer(net);
    trainer.set_learning_rate(0.1);
    trainer.be_verbose();
    trainer.set_synchronization_file("./MaxMarginObjectDetection.dir/mmod_sync",
        std::chrono::minutes(2));
    trainer.set_iterations_without_progress_threshold(50);

    // train the network
    std::vector<matrix<rgb_pixel>> mini_batch_images;
    std::vector<std::vector<mmod_rect>> mini_batch_labels;

    // create a random image cropper. the cropper will perform
    // rotation, cropping, and translation
    random_cropper cropper;
    cropper.set_chip_dims(200,200);
    cropper.set_min_object_size(0.2,0.2);
    dlib::rand rnd;

    // training loop
    int num_minibatch= 30;
    while (trainer.get_learning_rate() >= 1e-4)
    {
        cropper(num_minibatch, train_images, train_boxes,
            mini_batch_images, mini_batch_labels);
        // also apply random color jittering
        for (auto &img: mini_batch_images)
            disturb_colors(img, rnd);

        // train one step
        trainer.train_one_step(mini_batch_images, mini_batch_labels);
    }

    // wait for the training threads...
    trainer.get_net();
    std::cout<<"Done training!\n";

    // save network to disk
    net.clean();
    serialize("./MaxMarginObjectDetection.dir/mmod_network.dat") << net;

    // test on training data
    std::cout<<"training results: "<<
        test_object_detection_function(net, train_images, train_boxes)<<"\n";
    // test on testing data
    std::cout<<"test results: "<<
        test_object_detection_function(net, test_images, test_boxes)<<"\n";

    // print the trainer and cropper settings
    std::cout<<trainer<< cropper<<"\n";

    // look at the results on test images
    image_window win;
    for (auto&& img: test_images)
    {
        pyramid_up(img);
        auto dets= net(img);  // get detections using forward prop
        win.clear_overlay();
        win.set_image(img);
        for (auto&& d: dets)
        {
            std::cout << "detection confidence= " << d.detection_confidence
                << " rect= " << d.rect.top();
            win.add_overlay(d);
        }
        std::cin.get();  // wait for user to skip to the next image
    }

    std::system("pause");
    return 0;
}


#define BOOST_TEST_MODULE circuit_test
#include <boost/test/included/unit_test.hpp>

#include <nil/crypto3/algebra/curves/bls12.hpp>
#include <nil/crypto3/algebra/fields/bls12/base_field.hpp>
#include <nil/crypto3/algebra/fields/bls12/scalar_field.hpp>
#include <nil/crypto3/algebra/fields/arithmetic_params/bls12.hpp>
#include <nil/crypto3/algebra/curves/params/multiexp/bls12.hpp>
#include <nil/crypto3/algebra/curves/params/wnaf/bls12.hpp>

#include <nil/crypto3/zk/snark/schemes/ppzksnark/r1cs_gg_ppzksnark.hpp>

typedef algebra::curves::bls12<381> curve_type;
typedef curve_type::scalar_field_type field_type;
typedef field_type::value_type value_type;
typedef zk::snark::r1cs_gg_ppzksnark<curve_type> scheme_type;

#include "../bin/cli/src/detail/components.hpp"

using namespace nil::crypto3;
using namespace nil::crypto3::zk;

template<typename FieldType>
bool is_satisfied(uint min_salary, uint min_age, uint salary, uint age) {
    blueprint<field_type> bp;
    contest::bank_component<field_type> contest_component(bp);
    contest_component.generate_r1cs_constraints();
    contest_component.generate_r1cs_witness(min_salary, min_age, salary, age);
    return bp.is_satisfied();
}

BOOST_AUTO_TEST_SUITE(test_suite)

BOOST_AUTO_TEST_CASE(test_bank_component) {
    uint min_salary = 1000, min_age = 18;
    uint low_salary = 800, low_age = 16;
    uint big_salary = 1500, big_age = 21;

    std::cout << "Starting tests..." << std::endl;

    std::cout << "Testing valid inputs..." << std::endl;
    BOOST_CHECK(is_satisfied<field_type>(min_salary, min_age, min_salary, min_age) == true);
    BOOST_CHECK(is_satisfied<field_type>(min_salary, min_age, big_salary, big_age) == true);

    std::cout << "Testing invalid inputs..." << std::endl;
    BOOST_CHECK(is_satisfied<field_type>(min_salary, min_age, low_salary, big_age) == false);
    BOOST_CHECK(is_satisfied<field_type>(min_salary, min_age, low_salary, min_age) == false);
    BOOST_CHECK(is_satisfied<field_type>(min_salary, min_age, big_salary, low_age) == false);
    BOOST_CHECK(is_satisfied<field_type>(min_salary, min_age, min_salary, low_age) == false);
    BOOST_CHECK(is_satisfied<field_type>(min_salary, min_age, low_salary, low_age) == false);

    std::cout << "Tests completed!" << std::endl;
}
BOOST_AUTO_TEST_SUITE_END()


#include <v4r/io/eigen.h>
#include <vector>
#include <iostream>

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

namespace v4r
{
namespace io
{

bool
is_number(const std::string& s)
{
    std::string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}

bool
writeMatrixToFile (const std::string &file, const Eigen::Matrix4f & matrix)
{
    std::ofstream out (file.c_str ());
    if (!out)
    {
        std::cout << "Cannot open file.\n";
        return false;
    }

    for (size_t i = 0; i < 4; i++)
    {
        for (size_t j = 0; j < 4; j++)
        {
            out << matrix (i, j);
            if (!(i == 3 && j == 3))
                out << " ";
        }
    }
    out.close ();

    return true;
}

bool
readMatrixFromFile(const std::string &file, Eigen::Matrix4f & matrix, int padding)
{
    // check if file exists
    boost::filesystem::path path = file;
    if ( ! (boost::filesystem::exists ( path ) && boost::filesystem::is_regular_file(path)) ) {
        const std::string error_msg = "Given file path " + file + " to read matrix does not exist!";
        throw std::runtime_error (error_msg);
    }

    std::ifstream in;
    in.open (file.c_str (), std::ifstream::in);

    char linebuf[1024];
    in.getline (linebuf, 1024);
    std::string line (linebuf);
    std::vector < std::string > strs_2;
    boost::split (strs_2, line, boost::is_any_of (" "));

    for (int i = 0; i < 16; i++)
    {
        matrix (i / 4, i % 4) = static_cast<float> (atof (strs_2[padding+i].c_str ()));
    }

    return true;
}

Eigen::Matrix4f
readMatrixFromFile(const std::string &file, int padding)
{

    // check if file exists
    boost::filesystem::path path = file;
    if ( ! (boost::filesystem::exists ( path ) && boost::filesystem::is_regular_file(path)) )
        throw std::runtime_error ("Given file path to read Matrix does not exist!");

    std::ifstream in (file.c_str (), std::ifstream::in);

    char linebuf[1024];
    in.getline (linebuf, 1024);
    std::string line (linebuf);
    std::vector < std::string > strs_2;
    boost::split (strs_2, line, boost::is_any_of (" "));

    Eigen::Matrix4f matrix;
    for (int i = 0; i < 16; i++)
        matrix (i / 4, i % 4) = static_cast<float> (atof (strs_2[padding+i].c_str ()));

    return matrix;
}

template<typename T>
bool
writeVectorToFile (const std::string &file, const typename std::vector<T>& val)
{
    std::ofstream out (file.c_str ());
    if (!out)
    {
        std::cout << "Cannot open file.\n";
        return false;
    }

    for(size_t i=0; i<val.size(); i++)
        out << val[i] << " ";

    out.close ();

    return true;
}

bool
getCentroidFromFile (const std::string &file, Eigen::Vector3f & centroid)
{
    std::ifstream in;
    in.open (file.c_str (), std::ifstream::in);

    if (!in)
    {
        std::cout << "Cannot open file " << file.c_str () << ".\n";
        return false;
    }

    char linebuf[256];
    in.getline (linebuf, 256);
    std::string line (linebuf);
    std::vector < std::string > strs;
    boost::split (strs, line, boost::is_any_of (" "));
    centroid[0] = static_cast<float> (atof (strs[0].c_str ()));
    centroid[1] = static_cast<float> (atof (strs[1].c_str ()));
    centroid[2] = static_cast<float> (atof (strs[2].c_str ()));

    return true;
}

bool
writeFloatToFile (const std::string &file, const float value)
{
    std::ofstream out (file.c_str ());
    if (!out)
    {
        std::cout << "Cannot open file.\n";
        return false;
    }

    out << value;
    out.close ();

    return true;
}

bool
readFloatFromFile (const std::string &file, float& value)
{

    std::ifstream in;
    in.open (file.c_str (), std::ifstream::in);

    if (!in)
    {
        std::cout << "Cannot open file " << file.c_str () << ".\n";
        return false;
    }

    char linebuf[1024];
    in.getline (linebuf, 1024);
    value = static_cast<float> (atof (linebuf));

    return true;
}

template V4R_EXPORTS bool writeVectorToFile<float> (const std::string &, const typename std::vector<float>&);
template V4R_EXPORTS bool writeVectorToFile<double> (const std::string &, const typename std::vector<double>&);
template V4R_EXPORTS bool writeVectorToFile<int> (const std::string &, const typename std::vector<int>&);
template V4R_EXPORTS bool writeVectorToFile<size_t> (const std::string &, const typename std::vector<size_t>&);
}

}


//#define GRB_USE_APSPIE
#define GRB_USE_SEQUENTIAL

#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>

#include <graphblas/graphblas.hpp>

#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE mmio_suite

#include <boost/test/included/unit_test.hpp>
#include <test/test.hpp>

BOOST_AUTO_TEST_SUITE( mmio_suite )

// test_cc.mtx
BOOST_AUTO_TEST_CASE( mmio1 )
{
  std::vector<graphblas::Index> row_indices;
  std::vector<graphblas::Index> col_indices;
  std::vector<float> values;
  graphblas::Index nrows;
  graphblas::Index ncols;
  graphblas::Index nvals;

  // Read in test_cc.mtx
  char const *argv = "data/small/simulated_blockmodel_graph_50_nodes.mtx";
  readMtx(argv, &row_indices, &col_indices, &values, &nrows, &ncols, &nvals,
      true);

  int rhs[12] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2};
  //for( int i=0; i<12; i++ ) std::cout << row_indices[i] << "\n";
  BOOST_ASSERT_LIST( row_indices, rhs, 12 );
}

// chesapeake.mtx
BOOST_AUTO_TEST_CASE( mmio2 )
{
  std::vector<graphblas::Index> row_indices;
  std::vector<graphblas::Index> col_indices;
  std::vector<float> values;
  graphblas::Index nrows;
  graphblas::Index ncols;
  graphblas::Index nvals;

  // Read in chesapeake.mtx
  char const *argv = "data/small/simulated_blockmodel_graph_50_nodes.mtx";
  readMtx(argv, &row_indices, &col_indices, &values, &nrows, &ncols, &nvals,
      true);

  int rhs[12] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1};
  //for( int i=0; i<12; i++ ) std::cout << row_indices[i] << "\n";
  BOOST_ASSERT_LIST( row_indices, rhs, 12 );
}

BOOST_AUTO_TEST_SUITE_END()


/*
@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/integral.hpp>
using namespace boost::hana;

int main() {
    //! [main]
    auto i = integral<int, 3>; // notice no constexpr
    static_assert(value(i) == 3, "value(i) is always a constant expression!");
    //! [main]
}


#include <boost/property_map.hpp>

namespace yasmic {
  namespace impl {
    template <typename Index, typename EdgeIndex>
        class simple_csr_edge {
        public:
            Index r;
            EdgeIndex i;
            simple_csr_edge(Index row, EdgeIndex ind) : r(row), i(ind) {}
            simple_csr_edge() : r(0), i(0) {}
        }; // end simple_csr_edge
  }
} // end namespace yasmic

namespace boost {

        // add an index map for the edge type
        template<typename EdgeIndex, typename Edge>
        struct simple_csr_edge_index_map {
          typedef EdgeIndex value_type;
          typedef EdgeIndex reference;
          typedef Edge key_type;
          typedef readable_property_map_tag category;
        }; // end simple_csr_edge_index_map

    template<typename EdgeIndex, typename Edge>
    inline EdgeIndex
        get(const simple_csr_edge_index_map<EdgeIndex, Edge>&,
            const typename simple_csr_edge_index_map<EdgeIndex, Edge>::key_type& key)
    { return key.i; }
}

typedef yasmic::impl::simple_csr_edge<int,int> edge_t;

template <class EdgeIndexMap, class Edge>
void test_edge_index_map_impl(const EdgeIndexMap& m, Edge& e)
{
    using namespace boost;

    int i = 5 + get(m,e);
}

template <class EdgeIndexMap>
void test_edge_index_map(EdgeIndexMap m) {
    using namespace boost;
    edge_t e;
    test_edge_index_map_impl(m,e);

    function_requires<ReadablePropertyMapConcept<EdgeIndexMap, edge_t> >();
}

template <class EdgeComponentPropertyMap>
void test_edge_property_map(EdgeComponentPropertyMap m)
{
    using namespace boost;

    //function_requires<WritablePropertyMapConcept<EdgeComponentPropertyMap, edge_t> >();

    edge_t e;
    int ci;
    put(m,e,ci);
}

int main(int argc, char **argv)
{
    using namespace yasmic;
    using namespace boost;

    int* ci;
    typedef boost::simple_csr_edge_index_map<int,edge_t> edge_index_type;
    edge_index_type edge_index;

    test_edge_index_map(edge_index);
    test_edge_property_map(make_iterator_property_map(ci, edge_index));

}


//==============================================================================
//         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 "nt2 constants simd properties"

#include <boost/simd/include/constants/properties.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>

#include <boost/simd/sdk/simd/native.hpp>
#include <boost/dispatch/meta/as_unsigned.hpp>

#ifdef BOOST_MSVC
  #pragma warning(disable: 4146) // unary minus applied to unsigned
#endif

////////////////////////////////////////////////////////////////////////////////
// Test values for sigmask
////////////////////////////////////////////////////////////////////////////////
NT2_TEST_CASE_TPL(signmask, BOOST_SIMD_SIMD_TYPES)
{
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef boost::simd::native<T,ext_t> vd_t;
  for(std::size_t i=0; i< boost::simd::meta::cardinal_of<vd_t>::value;++i)
    NT2_TEST_EQUAL( (boost::simd::Signmask<vd_t>())[i], boost::simd::Signmask<T>() );
}

////////////////////////////////////////////////////////////////////////////////
// Test values for valmax
////////////////////////////////////////////////////////////////////////////////
NT2_TEST_CASE_TPL(valmax, BOOST_SIMD_SIMD_TYPES)
{
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef boost::simd::native<T,ext_t> vd_t;
  for(std::size_t i=0; i< boost::simd::meta::cardinal_of<vd_t>::value;++i)
    NT2_TEST_EQUAL( (boost::simd::Valmax<vd_t>())[i], boost::simd::Valmax<T>() );
}

////////////////////////////////////////////////////////////////////////////////
// Test values for valmin
////////////////////////////////////////////////////////////////////////////////
NT2_TEST_CASE_TPL(valmin, BOOST_SIMD_SIMD_TYPES)
{
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef boost::simd::native<T,ext_t> vd_t;
  for(std::size_t i=0; i< boost::simd::meta::cardinal_of<vd_t>::value;++i)
    NT2_TEST_EQUAL( (boost::simd::Valmin<vd_t>())[i], boost::simd::Valmin<T>() );
}

////////////////////////////////////////////////////////////////////////////////
// Test values for maxleftshift
////////////////////////////////////////////////////////////////////////////////
NT2_TEST_CASE_TPL(Maxleftshift, BOOST_SIMD_SIMD_TYPES)
{
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef boost::simd::native<T,ext_t> vd_t;
  for(std::size_t i=0; i< boost::simd::meta::cardinal_of<vd_t>::value;++i)
    NT2_TEST_EQUAL( (boost::simd::Maxleftshift<vd_t>())[i], boost::simd::Maxleftshift<T>() );
}

////////////////////////////////////////////////////////////////////////////////
// Test values for IEEE specs
////////////////////////////////////////////////////////////////////////////////
NT2_TEST_CASE_TPL(ieee, BOOST_SIMD_SIMD_TYPES)
{
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef boost::simd::native<T,ext_t> vd_t;
  for(std::size_t i=0; i< boost::simd::meta::cardinal_of<vd_t>::value;++i)
  {
    NT2_TEST_EQUAL( (boost::simd::Nbmantissabits<vd_t>())[i], boost::simd::Nbmantissabits<T>() );
    NT2_TEST_EQUAL( (boost::simd::Nbexponentbits<vd_t>())[i], boost::simd::Nbexponentbits<T>() );
    NT2_TEST_EQUAL( (boost::simd::Maxexponent<vd_t>())[i], boost::simd::Maxexponent<T>() );
    NT2_TEST_EQUAL( (boost::simd::Minexponent<vd_t>())[i], boost::simd::Minexponent<T>() );
    NT2_TEST_EQUAL( (boost::simd::Ldexpmask<vd_t>())[i], boost::simd::Ldexpmask<T>() );
    NT2_TEST_EQUAL( (boost::simd::Nbdigits<vd_t>())[i], boost::simd::Nbdigits<T>() );
  }
}


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

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

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

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

#ifndef BOOST_GEOMETRY_EXTENSIONS_NSPHERE_CORE_RADIUS_HPP
#define BOOST_GEOMETRY_EXTENSIONS_NSPHERE_CORE_RADIUS_HPP

#include <cstddef>

#include <boost/type_traits/remove_const.hpp>

#include <boost/geometry/core/tag.hpp>

#include <boost/geometry/extensions/nsphere/core/tags.hpp>

namespace boost { namespace geometry
{

namespace traits
{

/*!
    \brief Traits class to get/set radius of a circle/sphere/(ellipse)
    \details the radius access meta-functions give read/write access to the radius of a circle or a sphere,
    or to the major/minor axis or an ellipse, or to one of the 3 equatorial radii of an ellipsoid.

    It should be specialized per geometry, in namespace core_dispatch. Those specializations should
    forward the call via traits to the geometry class, which could be specified by the user.

    There is a corresponding generic radius_get and radius_set function
    \par Geometries:
        - n-sphere (circle,sphere)
        - upcoming ellipse
    \par Specializations should provide:
        - inline static T get(G const& geometry)
        - inline static void set(G& geometry, T const& radius)
    \ingroup traits
*/
template <typename G, typename T, std::size_t D>
struct radius_access {};

/*!
    \brief Traits class indicating the type (double,float,...) of the radius of a circle or a sphere
    \par Geometries:
        - n-sphere (circle,sphere)
        - upcoming ellipse
    \par Specializations should provide:
        - typedef T type (double,float,int,etc)
    \ingroup traits
*/
template <typename G>
struct radius_type {};

} // namespace traits

#ifndef DOXYGEN_NO_DISPATCH
namespace core_dispatch
{

template <typename Tag, typename G>
struct radius_type
{
    //typedef core_dispatch_specialization_required type;
};

/*!
    \brief radius access meta-functions, used by concept n-sphere and upcoming ellipse.
*/
template <typename Tag, typename G, typename T, std::size_t D>
struct radius_access
{
    //static inline T get(G const& ) {}
    //static inline void set(G& g, T const& value) {}
};

template <typename S>
struct radius_type<nsphere_tag, S>
{
    typedef typename traits::radius_type<S>::type type;
};

template <typename S, typename T, std::size_t D>
struct radius_access<nsphere_tag, S, T, D>
{
    BOOST_STATIC_ASSERT((D == 0));
    static inline T get(S const& s)
    {
        return traits::radius_access<S, T, D>::get(s);
    }
    static inline void set(S& s, T const& radius)
    {
        traits::radius_access<S, T, D>::set(s, radius);
    }
};

} // namespace core_dispatch
#endif // DOXYGEN_NO_DISPATCH

template <typename G>
struct radius_type
{
    typedef typename boost::remove_const<G>::type rconst;
    typedef typename core_dispatch::radius_type<typename tag<G>::type, rconst>::type type;
};

/*!
    \brief Function to get radius
    \return radius of a circle / sphere / ellipse
    \ingroup access
    \param geometry the geometry to get the radius from
    \tparam I index, for circle/sphere always zero, for ellipse major/minor axis,
        for ellipsoid one of the 3 equatorial radii
*/
template <std::size_t I, typename G>
inline typename radius_type<G>::type get_radius(G const& geometry)
{
    typedef typename boost::remove_const<G>::type rconst;

    return core_dispatch::radius_access<typename tag<G>::type, rconst,
           typename radius_type<G>::type, I>::get(geometry);
}

/*!
    \brief Function to set the radius of a circle / sphere / (ellipse)
    \ingroup access
    \tparam I index, for circle/sphere always zero, for ellipse major/minor axis,
        for ellipsoid one of the 3 equatorial radii
    \param geometry the geometry to change
    \param radius the radius to set
*/
template <std::size_t I, typename G>
inline void set_radius(G& geometry, typename radius_type<G>::type const& radius)
{
    typedef typename boost::remove_const<G>::type rconst;

    core_dispatch::radius_access<typename tag<G>::type, G,
        typename radius_type<G>::type, I>::set(geometry, radius);
}

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_RADIUS_HPP


/*
 * @Description: tf监听模块
 * @Author: Ren Qian
 * @Date: 2020-02-06 16:01:21
 */
#ifndef LIDAR_LOCALIZATION_TF_LISTENER_HPP_
#define LIDAR_LOCALIZATION_TF_LISTENER_HPP_

#include <string>

#include <Eigen/Dense>
#include <ros/ros.h>
#include <tf/transform_listener.h>

namespace lidar_localization {
class TFListener {
  public:
    TFListener(ros::NodeHandle& nh, std::string base_frame_id, std::string child_frame_id);
    TFListener() = default;

    bool LookupData(Eigen::Matrix4f& transform_matrix);

  private:
    bool TransformToMatrix(const tf::StampedTransform& transform, Eigen::Matrix4f& transform_matrix);

  private:
    ros::NodeHandle nh_;
    tf::TransformListener listener_;
    std::string base_frame_id_;
    std::string child_frame_id_;
};
}

#endif


/*  LICENSE

 _This file is Copyright 2018 by the Image Processing and Analysis Group (BioImage Suite Team). Dept. of Radiology & Biomedical Imaging, Yale School of Medicine._

 BioImage Suite Web is licensed under the Apache License, Version 2.0 (the "License");

 - you may not use this software except in compliance with the License.
 - You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](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.__

 ENDLICENSE */

#include "bisEigenUtil.h"
#include <iostream>
#include <Eigen/Dense>
#include <string.h>

namespace bisEigenUtil {

  Eigen::MatrixXf mapToEigenMatrix(bisSimpleMatrix<float>* m)
  {
    int rows=m->getNumRows();
    int cols=m->getNumCols();
    return Eigen::Map<Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> >(m->getData(),rows,cols);
  }

  Eigen::VectorXf mapToEigenVector(bisSimpleVector<float>* m)
  {
    int rows=m->getLength();
    return Eigen::VectorXf::Map(m->getData(),rows);
  }

  Eigen::MatrixXf mapImageToEigenMatrix(bisSimpleImage<float>* img)
  {
    int dim[5]; img->getDimensions(dim);
    int rows=dim[3]*dim[4];
    int cols=dim[0]*dim[1]*dim[2];
    return Eigen::Map<Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> >(img->getData(),rows,cols);
  }

  // -----------------------------------------------------------------------------------------------------
  // deserialize And Map
  // -----------------------------------------------------------------------------------------------------

  int deserializeAndMapToEigenVector(bisSimpleVector<float>* s_vector,unsigned char* ptr,Eigen::VectorXf& output,int defaultsize,float defaultvalue,int debug)
  {
    if (ptr!=0)
     {
       if (s_vector->linkIntoPointer(ptr))
	 {
	   if (debug)
	     std::cout << "Using external vector " << std::endl;

	   output=bisEigenUtil::mapToEigenVector(s_vector);
	   return 1;
	 }

       std::unique_ptr<bisSimpleMatrix<float> > s_matrix(new bisSimpleMatrix<float>("vectormatrix"));
       if (!s_matrix->linkIntoPointer(ptr))
	 {
	   std::cerr << "Failed to deserialize vector" << std::endl;
	   return 0;
	 }

       int rows=s_matrix->getNumRows();
       int cols=s_matrix->getNumCols();
       if (cols!=1)
	 {
	   std::cerr << "Failed to deserialize vector multi-col matrix provided." << std::endl;
	   return 0;
	 }

       std::cout << "wasm- Deserializing vector from single-column matrix." << std::endl;
       output=Eigen::VectorXf::Map(s_matrix->getData(),rows);
       return 1;
     }

    if (defaultsize>0)
      {
	output=Eigen::VectorXf::Zero(defaultsize);
	for (int ia=0;ia<defaultsize;ia++)
	  output(ia)=defaultvalue;
      }
    return 2;
  }

  int deserializeAndMapToEigenMatrix(bisSimpleMatrix<float>* s_matrix,unsigned char* ptr,Eigen::MatrixXf& output,int debug)
  {
    if (ptr==0) {
      std::cerr << "Failed to deserialize matrix" << std::endl;
      return 0;
    }

    if (s_matrix->linkIntoPointer(ptr))
      {
	if (debug)
	  std::cout << "Using external matrix " << std::endl;

	output=bisEigenUtil::mapToEigenMatrix(s_matrix);
	return 1;
      }

    std::unique_ptr<bisSimpleVector<float> > s_vector(new bisSimpleVector<float>("matrixvector"));
    if (!s_vector->linkIntoPointer(ptr))
      {
	std::cerr << "Failed to deserialize matrix as vector" << std::endl;
	return 0;
      }

    int rows=s_vector->getLength();
    std::cout << "wasm- Deserializing matrix from vector." << std::endl;
    output=Eigen::Map<Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> >(s_vector->getData(),rows,1);
    return 1;
  }

  unsigned char* serializeAndReturn(Eigen::MatrixXf& mat,std::string name)
  {
    std::unique_ptr<bisSimpleMatrix<float> > out(bisEigenUtil::createSimpleMatrix(mat,name));
    out->releaseOwnership();
    return out->getRawArray();
  }

  // -----------------------------------------------------------------------------------------------------
  std::unique_ptr<bisSimpleMatrix< float> > createSimpleMatrix(Eigen::MatrixXf inp,std::string name)
  {
    std::unique_ptr<bisSimpleMatrix<float> > out (new bisSimpleMatrix<float>(name));
    out->allocate(inp.rows(),inp.cols());
    float* odata=out->getData();
    int index=0;

    for (int row=0;row<inp.rows();row++)
      {
	for (int col=0;col<inp.cols();col++)
	  {
	    odata[index]=inp(row,col);
	    ++index;
	  }
      }

    return std::move(out);
  }

  std::unique_ptr<bisSimpleVector< float> > createSimpleVector(Eigen::VectorXf inp,std::string name)
  {

    std::unique_ptr<bisSimpleVector<float> > out (new bisSimpleVector<float>(name));

    out->allocate(inp.rows());
    float* odata=out->getData();

    for (int row=0;row<inp.rows();row++)
      odata[row]=inp(row);

    return std::move(out);
  }

  // ---------------------------------------------------------
  // Converted from BioImageSuite::vtkpxMatrix
  Eigen::MatrixXf importFromMatlabV6(const unsigned char* bytepointer,int bytearraylength,std::string matrixname,int debug,int& out_ok)
  {
    out_ok=0;
    static unsigned char* indataptr=0;
    static int remaining=0;

    long pt=(long)bytepointer;
    indataptr=(unsigned char*)pt;
    remaining=bytearraylength;
    Eigen::MatrixXf outputMatrix=Eigen::MatrixXf::Zero(1,1);

    if (debug>1)
      std::cout << "pointer=" << (long)indataptr << " numbytes=" << bytearraylength << "\t " << remaining << std::endl;

    struct internal
    {
      static int readdata(void* outbuf,int sizeofelement,int numelements)
      {
	int sz=numelements*sizeofelement;
	if (sz<=remaining)
	  {
	    memcpy(outbuf,indataptr,sz);
	    remaining=remaining-sz;
	    indataptr+=sz;
	    //	    std::cout << "read " << sz << " elements pointer=" << (int)indataptr << "\t remaining=" << remaining << std::endl;
	    return sz;
	  }
	return 0;
      }

      static int skipahead(int sz)
      {
	if (sz<remaining)
	  {
	    indataptr+=sz;
	    remaining=remaining-sz;
	    //	    std::cout << "skipping ahead " << sz << " elements pointer=" << (int)indataptr << "\t remaining=" << remaining << std::endl;
	    return sz;
	  }
	return 0;
      }

      static int swapint(int input) {
	int a=input;
	unsigned char* bytes=(unsigned char*)&a;
	unsigned char tmp;

	tmp=*bytes;
	*bytes=*(bytes+3);
	*(bytes+3)=tmp;

	tmp=*(bytes+1);
	*(bytes+1)=*(bytes+2);
	*(bytes+2)=tmp;

	return a;
      }

      static float swapfloat(float input) {
	float a=input;
	unsigned char* bytes=(unsigned char*)&a;
	unsigned char tmp;

	tmp=*bytes;
	*bytes=*(bytes+3);
	*(bytes+3)=tmp;

	tmp=*(bytes+1);
	*(bytes+1)=*(bytes+2);
	*(bytes+2)=tmp;

	return a;
      }

      static short swapshort(short input) {
	short a=input;
	unsigned char *bytes=(unsigned char*)&a;
	unsigned char tmp;
	tmp=*bytes;
	*bytes=*(bytes+1);
	*(bytes+1)=tmp;
	return a;
      }

      static double swapdouble(double input) {
	double a=input;
	double b=input;
	unsigned char* ap=(unsigned char*)&a;
	unsigned char* bp=(unsigned char*)&b;

	ap[0]=bp[7];
	ap[1]=bp[6];
	ap[2]=bp[5];
	ap[3]=bp[4];
	ap[4]=bp[3];
	ap[5]=bp[2];
	ap[6]=bp[1];
	ap[7]=bp[0];

	return a;
      }

    };

    char buffer[2000];
    char name[2000];

    internal::readdata(buffer,1,116);
    if (debug)
      std::cout << "Description = " << buffer << std::endl;

    internal::readdata(buffer,1,8);
    int ok=1;
    for (int ia=0;ia<=7;ia++)
      {
	int v=int(buffer[ia]);
	if (!(v==0 || v==32))
	  {
	    std::cerr << "We have a problem with ia=" << ia << std::endl;
	    ok=0;
	    ia=9;
	  }
      }

    if (ok==0)
      {
	return outputMatrix;
      }
    internal::readdata(buffer,1,4);
    if (debug>1)
      std::cout << "All Offset bytes are either zero or space OK!" << std::endl;

    int done=0;
    int totalread=128;
    int count=0;

    while (done==0)
      {
	int dtype[2];
	int n=internal::readdata(dtype,sizeof(int),2);
	totalread+=8;
	if (debug>1)
	  std::cout << "n = " << n << " totalread= " << totalread << std::endl << "-----------------------------------------------------" << std::endl;
	if (n<1)
	  {
	    done=1;
	  }
	else
	  {
	    int swap=0;
	    ++count;
	    if (dtype[0]<0 || dtype[0]>1024)
	      {
		dtype[0]=internal::swapint(dtype[0]);
		dtype[1]=internal::swapint(dtype[1]);
		swap=1;
	      }
	    if (debug>1)
	      std::cout << std::endl << "dtype = " << dtype[0] << " , numbytes = " << dtype[1] << std::endl;
	    if (dtype[0]!=14)
	      {
		if (debug>1)
		  {
		    std::cout << "Not a matrix skipping ahead " << dtype[1] << " bytes" << std::endl;
		    std::cout << "Seaking ahead  " << dtype[1] << " bytes" << std::endl;
		  }
		int toread=dtype[1];

		// Add padding
		int tmp=8*int(toread/8);
		if (tmp<toread)
		  {
		    toread=8+tmp;
		    //		  std::cout  << "Adding padding from " << dtype[1] << " to " << toread << std::endl;
		  }

		while (toread>0)
		  {
		    int n=toread;
		    if (toread>256) n=256;
		    totalread+=internal::readdata(buffer,1,n);
		    toread-=n;
		  }
		if (debug>1)
		  std::cout << "Total read = " << totalread << std::endl;
	      }
	    else
	      {
		if (debug)
		  std::cout << std::endl << "Beginning to read matrix: " << std::endl;
		int bytes_read=internal::readdata(buffer,1,16);
		int cl=(int)buffer[8];
		//	      if (swap)
		//		cl=internal::swapint(cl);

		int flags[6],length[1];
		bytes_read+=internal::readdata(flags,sizeof(int),5);
		if (swap)
		  {
		    //		    length[0]=internal::swapint(length[0]);
		    for (int ic=0;ic<5;ic++)
		      flags[ic]=internal::swapint(flags[ic]);
		  }

		// Check for use of small element format
		//
		int test=int(flags[4] / 65536 );
		if (debug>1)
		  std::cout << "***************** Is Small Element " << test << std::endl;
		if (test==0)
		  {
		    length[0]=0;
		    bytes_read+=internal::readdata(length,sizeof(int),1);
		    if (swap)
		      length[0]=internal::swapint(length[0]);
		    flags[5]=length[0];
		    if (swap)
		      flags[5]=internal::swapint(flags[5]);
		    bytes_read+=internal::readdata(name,1,flags[5]);
		    name[flags[5]]=(char)0;
		    int rem=8-(flags[5]-int(flags[5]/8)*8);
		    if (debug>1)
		      std::cout << "Remainder " << rem << std::endl;
		    bytes_read+=internal::readdata(buffer,1,rem);
		  }
		else
		  {
		    const int tmp_mask=65535;
		    int nb=(flags[4] & tmp_mask);
		    if (debug>1)
		      std::cout << "Small Element nb=" << nb << " test= " << int(test/65536) << std::endl;
		    bytes_read+=internal::readdata(name,1,4);
		    name[nb]=(char)0;
		    flags[5]=0;
		  }

		int nfl[2];
		bytes_read+=internal::readdata(nfl,sizeof(int),2);
		if (swap)
		  {
		    nfl[0]=internal::swapint(nfl[0]);
		    nfl[1]=internal::swapint(nfl[1]);
		  }
		if (debug>1)
		  std::cout << "Final Flags = " << nfl[0] << "," << nfl[1] << std::endl;

		int numrows=flags[2];
		int numcols=flags[3];
		if (debug)
		  {
		    std::cout << "Dimensions =" << numrows << "x" << numcols << ", class = " << cl << ", length = " << flags[5] << std::endl;
		    std::cout << "Name = " << name << ", (bytes read= " << bytes_read << ")" << std::endl;
		  }
		int toread=dtype[1]-bytes_read;
		if (debug>1)
		  std::cout << "To read (1) = " << toread << std::endl;

		if (strcmp(name, matrixname.c_str())==0 || strlen(matrixname.c_str()) == 0)
		  {
		    if ( (cl==7 || cl==6))
		      {
			int numbytesneeded=4*numrows*numcols;
			if (cl==6)
			  numbytesneeded*=2;

			if (debug)
			  std::cout << "Numbytes needed = " << numbytesneeded << std::endl;

			if (debug>1)
			  std::cout << "Beginning to read matrix " << numbytesneeded << " < " <<  toread << std::endl;

			if (numbytesneeded<=toread)
			  {
			    outputMatrix=Eigen::MatrixXf::Zero(numrows,numcols);
			    if (cl==6)
			      {
				std::unique_ptr<double> rd(new double[numrows]);
				for (int ib=0;ib<numcols;ib++)
				  {
				    bytes_read+=internal::readdata(rd.get(),sizeof(double),numrows);
				    for (int ia=0;ia<numrows;ia++)
				      if (swap)
					outputMatrix(ia,ib)=float(internal::swapdouble(rd.get()[ia]));
				      else
					outputMatrix(ia,ib)=float(rd.get()[ia]);
				  }
			      }
			    else
			      {
				std::unique_ptr<float> rf(new float[numrows]);
				for (int ib=0;ib<numcols;ib++)
				  {
				    bytes_read+=internal::readdata(rf.get(),sizeof(float),numrows);
				    for (int ia=0;ia<numrows;ia++)
				      if (swap)
					outputMatrix(ia,ib)=(internal::swapfloat(rf.get()[ia]));
				      else
					outputMatrix(ia,ib)=(rf.get()[ia]);
				  }
			      }

			    out_ok=1;
			    return outputMatrix;
			  }
			else
			  {
			    std::cerr << "\t\t\t can't read data not enough bytes" << std::endl;
			  }
		      }
		    std::cout << "Final To read (2) = " << toread << std::endl;
		  }
		else
		  {
		    if (debug>1)
		      std::cout << "Not the matrix we are looking for" << std::endl;
		  }

		while (toread>0)
		  {
		    int n=toread;
		    if (toread>256) n=256;
		    bytes_read+=internal::readdata(buffer,1,n);
		    toread-=n;
		  }

		totalread+=bytes_read;
	      }
	  }
      }

    return outputMatrix;

  }

  // ---------------------------------------------------------------------------------------------
  // Eigen Utilities
  // ---------------------------------------------------------------------------------------------
  void getMatrixDimensions(Eigen::MatrixXf& mat,int sz[2]) {
    sz[0]=mat.rows();
    sz[1]=mat.cols();
  }

  void resizeZeroVector(Eigen::VectorXf& vct,int numrows) {

    if (numrows!=vct.rows())
      {
	vct=Eigen::VectorXf::Zero(numrows);
	return;
      }

    for (int i=0;i<numrows;i++)
      vct(i)=0.0;
  }

  void resizeZeroMatrix(Eigen::MatrixXf& mat,int sz[2]) {

    int dim[2]; getMatrixDimensions(mat,dim);

    if (dim[0]!=sz[0] || dim[1]!=sz[1])
      {
	mat=Eigen::MatrixXf::Zero(sz[0],sz[1]);
	return;
      }

    for (int i=0;i<sz[0];i++)
      for (int j=0;j<sz[1];j++)
	mat(i,j)=0.0;
  }

  Eigen::MatrixXf createLSQMatrix(Eigen::MatrixXf& A) {
    Eigen::MatrixXf At=A.transpose();
    return ((At*A).inverse())*At;
  }

  int inPlaceMultiplyMV(Eigen::MatrixXf& A, Eigen::VectorXf& x, Eigen::VectorXf& b)
  {
    int dim[2]; getMatrixDimensions(A,dim);
    // R * C  * C * 1 = R *1

    //    std::cout << "Dim=" << dim[0] << "," << dim[1] << " x=" << x.rows() << " b=" <<  b.rows() << " " << std::endl;

    if (dim[1]!=x.rows() || dim[0]!=b.rows())
      return 0;

    for (int i=0;i<dim[0];i++)
      {
	float sum=0.0;
	for (int j=0;j<dim[1];j++)
	  sum+=A(i,j)*x[j];
	b(i)=sum;
      }

    //    std::cout << "b=" << b << std::endl;

    return 1;
  }

  // -----------------------------------------------------------------------------------
  int inPlaceMultiply(Eigen::MatrixXf& A, Eigen::MatrixXf& B, Eigen::MatrixXf& C)
  {
    int s1[2],s2[2],s3[2];
    getMatrixDimensions(A,s1);
    getMatrixDimensions(B,s2);

    if (s1[1]!=s2[0])
      {
	std::cerr << "Cannot multiply matrices bad size! a=" << s1[0] << "x" << s1[1] <<", b=" << s2[0] << "x" << s2[1] << std::endl;
	return 0;
      }

    s3[0]=s1[0];
    s3[1]=s2[1];

    resizeZeroMatrix(C,s3);

    for(int col = 0; col < s3[1]; col++)
      {
	for(int row = 0; row < s3[0]; row++)
	  {
	    float sum=0.0;
	    for(int i = 0; i < s1[1]; i++)
	      sum+=A(row,i)*B(i,col);
	    C(row,col)=sum;
	  }
      }
    return 1;
  }

  int inPlaceMultiply3(Eigen::MatrixXf& a,Eigen::MatrixXf& b,Eigen::MatrixXf& c,Eigen::MatrixXf& result)
  {
    int s1[2],s2[2],s3[2];
    getMatrixDimensions(a,s1);
    getMatrixDimensions(b,s2);
    getMatrixDimensions(c,s3);

    if (s1[1]!=s2[0] || s2[1]!=s3[0])
      {
	std::cerr << "Cannot multiply3 matrices bad sizes " << s1[0]<<"*" << s1[1] <<", " << s2[0] << "*" << s2[1] << ", " << s3[0] << "*" << s3[1] << std::endl;
	return 0;
      }

    int s4[2] = { s1[0],s3[1] };
    resizeZeroMatrix(result,s4);

    for(int col = 0; col < s4[1]; col++)
      {
	for(int row = 0; row < s4[0]; row++)
	  {
	    float sum=0.0;
	    for(int k = 0; k < s1[1] ; k++)
	      for (int l=0; l <  s2[1] ; l++ )
		sum+=a(row,k)*b(k,l)*c(l,col);

	    result(row,col)=sum;
	  }
      }
    return 1;
  }

}


//==================================================================================================
/*!
  @file

    @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_CONJ_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_CONJ_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

  /*!

    @ingroup group-arithmetic
    function object computes the complex conjugate of its parameter

    @par Header <boost/simd/function/conj.hpp>

    @par Notes

    - for real entries it resumes to the identity

  **/
  Value conj(Value const& x);
} }
#endif

#include <boost/simd/function/scalar/conj.hpp>
#include <boost/simd/function/simd/conj.hpp>

#endif


/*
 *  connectivity.hpp
 *
 *
 *  Created by Andrea Bedini on 10/Jul/2009.
 *  Copyright (c) 2009-2014, Andrea Bedini <andrea.bedini@gmail.com>.
 *
 *  Distributed under the terms of the Modified BSD License.
 *  The full license is in the file COPYING, distributed as part of
 *  this software.
 *
 */

#ifndef CONNECTIVITY_HPP
#define CONNECTIVITY_HPP

#include "connectivity_functions.hpp"

#include <boost/cstdint.hpp>
#include <boost/functional/hash.hpp>

#include <algorithm>
#include <iosfwd>

class connectivity
{
  typedef boost::uint8_t uint8_t;

  unsigned int size_;
  uint8_t * impl_;

public:
  connectivity(unsigned int n)
    : size_(n)
    , impl_(new uint8_t[size_])
  {
    for (unsigned int i = 0; i < size_; ++i)
      impl_[i] = i + 1;
  }

  connectivity(const connectivity& rhs)
    : size_(rhs.size_)
    , impl_(new uint8_t[size_])
  {
    std::copy(rhs.impl_, rhs.impl_ + rhs.size_, impl_);
  }

  ~connectivity()
  {
    if (impl_)
      delete [] impl_;
  }

  connectivity& operator=(const connectivity& rhs)
  {
    if (this != &rhs) {
      uint8_t* new_impl_ = new uint8_t[rhs.size_];
      std::copy(rhs.impl_, rhs.impl_ + rhs.size_, new_impl_);
      delete [] impl_;
      impl_ = new_impl_;
      size_ = rhs.size_;
    }
    return *this;
  }

  unsigned int size() const
  {
    return size_;
  }

  void swap(connectivity& rhs) throw ()
  {
    using std::swap;
    swap(size_, rhs.size_);
    swap(impl_, rhs.impl_);
  }

  bool operator==(const connectivity& rhs) const
  {
    return (size_ == rhs.size_) and std::equal(impl_, impl_ + size_, rhs.impl_);
  }

  connectivity& canonicalize()
  {
    connectivity_functions::canonicalize(size_, impl_);
    return *this;
  }

  //////////////////////////////////////////////////////////////////////
  // const
  //////////////////////////////////////////////////////////////////////

  bool connected(unsigned int i, unsigned int j) const
  {
    return connectivity_functions::connected(impl_, i, j);
  }

  bool singleton(unsigned int i) const
  {
    return connectivity_functions::is_singleton(size_, impl_, i);
  }

  connectivity& delete_node(unsigned int i)
  {
    connectivity new_(size_ - 1);
    std::copy(impl_, impl_ + i, new_.impl_);
    std::copy(impl_ + i + 1, impl_ + size_, new_.impl_ + i);
    swap(new_);
    return *this;
  }

  connectivity& connect(unsigned int i, unsigned int j)
  {
    connectivity_functions::connect(size_, impl_, i, j);
    return *this;
  }

  connectivity& detach(unsigned int i)
  {
    connectivity_functions::detach(size_, impl_, i);
    return *this;
  }

  template<typename F>
  void decompose(F f) const
  {
    connectivity_functions::decompose(size_, impl_, f);
  }

  friend std::size_t hash_value(const connectivity&);
  friend std::ostream& operator<<(std::ostream&, const connectivity&);
};

std::size_t hash_value(const connectivity& a)
{
  return boost::hash_range(a.impl_, a.impl_ + a.size_);
}

std::ostream& operator<<(std::ostream& o, const connectivity& c)
{
  o << "{ ";
  for (unsigned int i = 0; i < c.size_; ++i) {
    o << (int) c.impl_[i] << " ";
  }
  return o << "}";
}

#endif


//
// Copyright © 2019 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "QuantizedLstmEndToEndTestImpl.hpp"

#include "CommonTestUtils.hpp"
#include "EndToEndTestImpl.hpp"

#include <ResolveType.hpp>

#include <armnn/INetwork.hpp>

#include <test/TensorHelpers.hpp>

#include <boost/test/unit_test.hpp>

#include <type_traits>

namespace
{

using MultiArray = const boost::multi_array<uint8_t, 2>&;

armnn::INetworkPtr CreateQuantizedLstmNetwork(MultiArray input,
                                              MultiArray expectedOutput)
{
    auto batchSize = boost::numeric_cast<unsigned int>(input.shape()[0]);
    auto inputSize = boost::numeric_cast<unsigned int>(input.shape()[1]);
    auto outputSize = boost::numeric_cast<unsigned int>(expectedOutput.shape()[1]);

    float inputOutputScale = 0.0078125f;
    int32_t inputOutputOffset = 128;

    float weightsScale = 0.00408021f;
    int32_t weightsOffset = 100;

    float biasScale = 3.1876640625e-05f;
    int32_t biasOffset = 0;

    float cellStateScale = 0.00048828125f;
    int32_t cellStateOffset = 0;

    armnn::TensorInfo inputWeightsInfo({outputSize, inputSize},
                                       armnn::DataType::QuantisedAsymm8,
                                       weightsScale,
                                       weightsOffset);

    armnn::TensorInfo recurrentWeightsInfo({outputSize, outputSize},
                                           armnn::DataType::QuantisedAsymm8,
                                           weightsScale,
                                           weightsOffset);

    armnn::TensorInfo biasInfo({outputSize}, armnn::DataType::Signed32, biasScale, biasOffset);

    armnn::QuantizedLstmInputParams data;

    const std::vector<uint8_t> inputToInputWeightsVector = {146, 250, 235, 171, 10, 218, 171, 108};
    armnn::ConstTensor inputToInputWeightsTensor(inputWeightsInfo, inputToInputWeightsVector.data());

    const std::vector<uint8_t> inputToForgetWeightsVector = {24, 50, 132, 179, 158, 110, 3, 169};
    armnn::ConstTensor inputToForgetWeightsTensor(inputWeightsInfo, inputToForgetWeightsVector.data());

    const std::vector<uint8_t> inputToCellWeightsTensorVector = {133, 34, 29, 49, 206, 109, 54, 183};
    armnn::ConstTensor inputToCellWeightsTensor(inputWeightsInfo, inputToCellWeightsTensorVector.data());

    const std::vector<uint8_t> inputToOutputWeightsTensorVector = {195, 187, 11, 99, 109, 10, 218, 48};
    armnn::ConstTensor inputToOutputWeightsTensor(inputWeightsInfo, inputToOutputWeightsTensorVector.data());

    const std::vector<uint8_t> recurrentToInputWeightsTensorVector =
            {254, 206, 77, 168, 71, 20, 215, 6, 223, 7, 118, 225, 59, 130, 174, 26};
    armnn::ConstTensor recurrentToInputWeightsTensor(recurrentWeightsInfo, recurrentToInputWeightsTensorVector.data());

    const std::vector<uint8_t> recurrentToForgetWeightsTensorVector =
            {137, 240, 103, 52, 68, 51, 237, 112, 0, 220, 89, 23, 69, 4, 207, 253};
    armnn::ConstTensor recurrentToForgetWeightsTensor(recurrentWeightsInfo,
                                                      recurrentToForgetWeightsTensorVector.data());

    const std::vector<uint8_t> recurrentToCellWeightsTensorVector =
            {172, 60, 205, 65, 14, 0, 140, 168, 240, 223, 133, 56, 142, 64, 246, 216};
    armnn::ConstTensor recurrentToCellWeightsTensor(recurrentWeightsInfo, recurrentToCellWeightsTensorVector.data());

    const std::vector<uint8_t> recurrentToOutputWeightsTensorVector =
            {106, 214, 67, 23, 59, 158, 45, 3, 119, 132, 49, 205, 129, 218, 11, 98};
    armnn::ConstTensor recurrentToOutputWeightsTensor(recurrentWeightsInfo,
                                                      recurrentToOutputWeightsTensorVector.data());

    const std::vector<int32_t> inputGateBiasTensorVector = {-7876, 13488, -726, 32839};
    armnn::ConstTensor inputGateBiasTensor(biasInfo, inputGateBiasTensorVector.data());

    const std::vector<int32_t> forgetGateBiasTensorVector = {9206, -46884, -11693, -38724};
    armnn::ConstTensor forgetGateBiasTensor(biasInfo, forgetGateBiasTensorVector.data());

    const std::vector<int32_t> cellBiasTensorVector = {39481, 48624, 48976, -21419};
    armnn::ConstTensor cellBiasTensor(biasInfo, cellBiasTensorVector.data());

    const std::vector<int32_t> outputGateBiasTensorVector = {-58999, -17050, -41852, -40538};
    armnn::ConstTensor outputGateBiasTensor(biasInfo, outputGateBiasTensorVector.data());

    data.m_InputToInputWeights = &inputToInputWeightsTensor;
    data.m_InputToForgetWeights = &inputToForgetWeightsTensor;
    data.m_InputToCellWeights = &inputToCellWeightsTensor;
    data.m_InputToOutputWeights = &inputToOutputWeightsTensor;
    data.m_RecurrentToInputWeights = &recurrentToInputWeightsTensor;
    data.m_RecurrentToForgetWeights = &recurrentToForgetWeightsTensor;
    data.m_RecurrentToCellWeights = &recurrentToCellWeightsTensor;
    data.m_RecurrentToOutputWeights = &recurrentToOutputWeightsTensor;
    data.m_InputGateBias = &inputGateBiasTensor;
    data.m_ForgetGateBias = &forgetGateBiasTensor;
    data.m_CellBias = &cellBiasTensor;
    data.m_OutputGateBias = &outputGateBiasTensor;

    armnn::INetworkPtr net(armnn::INetwork::Create());

    armnn::IConnectableLayer* const inputLayer   = net->AddInputLayer(0);
    armnn::IConnectableLayer* const cellStateIn = net->AddInputLayer(1);
    armnn::IConnectableLayer* const outputStateIn = net->AddInputLayer(2);
    armnn::IConnectableLayer* const quantizedLstmLayer = net->AddQuantizedLstmLayer(data, "quantizedLstm");
    armnn::IConnectableLayer* const cellStateOut  = net->AddOutputLayer(0);
    armnn::IConnectableLayer* const outputStateOut  = net->AddOutputLayer(1);

    armnn::TensorInfo inputTensorInfo({batchSize , inputSize},
                                      armnn::DataType::QuantisedAsymm8,
                                      inputOutputScale,
                                      inputOutputOffset);

    armnn::TensorInfo cellStateInTensorInfo({batchSize , outputSize},
                                            armnn::DataType::QuantisedSymm16,
                                            cellStateScale,
                                            cellStateOffset);

    armnn::TensorInfo outputStateInTensorInfo({batchSize , outputSize},
                                              armnn::DataType::QuantisedAsymm8,
                                              inputOutputScale,
                                              inputOutputOffset);

    armnn::TensorInfo cellStateOutTensorInfo({batchSize, outputSize},
                                             armnn::DataType::QuantisedSymm16,
                                             cellStateScale,
                                             cellStateOffset);

    armnn::TensorInfo outputTensorInfo({batchSize, outputSize},
                                       armnn::DataType::QuantisedAsymm8,
                                       inputOutputScale,
                                       inputOutputOffset);

    // connect up
    // inputs
    Connect(inputLayer, quantizedLstmLayer, inputTensorInfo, 0, 0);
    Connect(cellStateIn, quantizedLstmLayer, cellStateInTensorInfo, 0, 1);
    Connect(outputStateIn, quantizedLstmLayer, outputStateInTensorInfo, 0, 2);

    // outputs
    Connect(quantizedLstmLayer, cellStateOut, cellStateOutTensorInfo, 0, 0);
    Connect(quantizedLstmLayer, outputStateOut, outputTensorInfo, 1, 0);

    return net;
}

// Checks if two values of an arithmetic type are close enough to each other
// with regard to a given tolerance value.
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type
IsCloseEnough(T value1, T value2, T tolerance)
{
    if (tolerance < 0)
    {
        throw armnn::InvalidArgumentException("Tolerance cannot be < 0");
    }

    T diff = value1 >= value2 ? static_cast<T>(value1 - value2) : static_cast<T>(value2 - value1);
    return diff <= tolerance;
}

} // anonymous namespace

void QuantizedLstmEndToEnd(const std::vector<armnn::BackendId>& backends)
{
    std::vector<uint8_t> inputVector = {166, 179, 50, 150};
    armnn::TensorInfo inputDesc({2, 2}, armnn::DataType::QuantisedAsymm8);
    boost::multi_array<uint8_t, 2> input = MakeTensor<uint8_t, 2>(inputDesc, inputVector);

    std::vector<int16_t> cellStateInVector = {876, 1034, 955, -909, 761, 1029, 796, -1036};
    armnn::TensorInfo cellStateInDesc({2, 4}, armnn::DataType::QuantisedSymm16);
    boost::multi_array<int16_t, 2> cellStateIn = MakeTensor<int16_t, 2>(cellStateInDesc, cellStateInVector);

    std::vector<uint8_t> outputStateInVector = {136, 150, 140, 115, 135, 152, 138, 112};
    armnn::TensorInfo outputStateInDesc({2, 4}, armnn::DataType::QuantisedAsymm8);
    boost::multi_array<uint8_t, 2> outputStateIn = MakeTensor<uint8_t, 2>(outputStateInDesc, outputStateInVector);

    std::vector<int16_t> cellStateOutVector = {1485, 1177, 1373, -1023, 1019, 1355, 1097, -1235};
    armnn::TensorInfo cellStateOutVectorDesc({2, 4}, armnn::DataType::QuantisedSymm16);
    boost::multi_array<int16_t, 2> cellStateOut = MakeTensor<int16_t, 2>(cellStateOutVectorDesc, cellStateOutVector);

    std::vector<uint8_t> outputStateOutVector = {140, 151, 146, 112, 136, 156, 142, 112};
    armnn::TensorInfo outputDesc({2, 4}, armnn::DataType::QuantisedAsymm8);
    boost::multi_array<uint8_t, 2> outputStateOut = MakeTensor<uint8_t, 2>(outputDesc, outputStateOutVector);

    // Builds up the structure of the network
    armnn::INetworkPtr net = CreateQuantizedLstmNetwork(input, outputStateOut);

    BOOST_TEST_CHECKPOINT("create a network");

    IRuntime::CreationOptions options;
    IRuntimePtr runtime(IRuntime::Create(options));

    // optimize the network
    IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());

    // Loads it into the runtime.
    NetworkId netId;
    runtime->LoadNetwork(netId, std::move(optNet));

    InputTensors inputTensors;
    inputTensors.reserve(3);

    // input
    inputTensors.push_back({0, ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputVector.data())});
    inputTensors.push_back({1, ConstTensor(runtime->GetInputTensorInfo(netId, 1), cellStateInVector.data())});
    inputTensors.push_back({2, ConstTensor(runtime->GetInputTensorInfo(netId, 2), outputStateInVector.data())});

    OutputTensors outputTensors;
    outputTensors.reserve(2);

    //output
    std::vector<int16_t > cellStateOutResult(cellStateOutVector.size());
    std::vector<uint8_t > outputStateOutResult(outputStateOutVector.size());
    outputTensors.push_back({0, Tensor(runtime->GetOutputTensorInfo(netId, 0), cellStateOutResult.data())});
    outputTensors.push_back({1, Tensor(runtime->GetOutputTensorInfo(netId, 1), outputStateOutResult.data())});

    // Does the inference.
    runtime->EnqueueWorkload(netId, inputTensors, outputTensors);

    // Checks the results
    constexpr int16_t toleranceInt16 = 2;
    for (unsigned int i = 0u; i < cellStateOutResult.size(); ++i)
    {
        BOOST_CHECK(IsCloseEnough(cellStateOutVector[i], cellStateOutResult[i], toleranceInt16));
    }

    constexpr uint8_t toleranceUint8 = 1;
    for (unsigned int i = 0u; i < outputStateOutResult.size(); ++i)
    {
        BOOST_TEST(IsCloseEnough(outputStateOutVector[i], outputStateOutResult[i], toleranceUint8));
    }
}


#pragma once

#include <rj_geometry/point.hpp>
#include <rj_geometry/pose.hpp>
#include <boost/circular_buffer.hpp>
#include <rj_common/utils.hpp>
#include <rj_vision_filter/filter/kalman_filter3_d.hpp>
#include <rj_vision_filter/robot/camera_robot.hpp>

namespace vision_filter {
class WorldRobot;

/**
 * Filtered robot estimation for a single camera
 */
class KalmanRobot {
public:
    /**
     * Checks previous_world_robot to see if it's valid
     *
     * @param camera_id ID of the camera this filter is applied to
     * @param creation_time Time this filter was created
     * @param init_measurement Initial robot measurement
     * @param previous_world_robot World robot from last frame (or invalid world
     * robot)
     */
    KalmanRobot(unsigned int camera_id, RJ::Time creation_time,
                CameraRobot init_measurement,
                const WorldRobot& previous_world_robot);

    /**
     * Predicts one time step forward
     *
     * @param current_time Current time of the prediction step
     */
    void predict(RJ::Time current_time);

    /**
     * Predicts one time step forward then triangulates toward the measurement
     *
     * @param current_time Current time of the prediction/update step
     * @param update_robot Robot measurement that we are using as feedback
     */
    void predict_and_update(RJ::Time current_time, CameraRobot update_robot);

    /**
     * Returns true when the filter hasn't been updated in a while and should be
     * deleted
     */
    bool is_unhealthy() const;

    /**
     * @return The camera id this belongs to
     */
    unsigned int get_camera_id() const;

    /**
     * @return This robot's id
     */
    int get_robot_id() const;

    /**
     * @return How healthy this filter is. AKA How often it's been updated
     */
    int get_health() const;

    /**
     * @return Best estimate of the linear position of the robot
     */
    rj_geometry::Point get_pos() const;

    /**
     * @return Best estimate of the heading. Not bounded
     */
    double get_theta() const;

    /**
     * @return Best estimate of the linear velocity of the robot
     */
    rj_geometry::Point get_vel() const;

    /**
     * @return Best estimate of the angular velocity
     */
    double get_omega() const;

    /**
     * @return Covariance in X and Y linear direction of the position of the
     * robot
     */
    rj_geometry::Point get_pos_cov() const;

    /**
     * @return Covariance of theta of the robot
     */
    double get_theta_cov() const;

    /**
     * @return Covariance in X and Y linear direction of the velocity of the
     * robot
     */
    rj_geometry::Point get_vel_cov() const;

    /**
     * @return Covariance of omega of the robot
     */
    double get_omega_cov() const;

    /**
     * @return List of previous camera robot measurements for kick detection
     */
    const boost::circular_buffer<CameraRobot>& get_prev_measurements() const;

private:
    RJ::Time last_update_time_;
    RJ::Time last_predict_time_;

    boost::circular_buffer<CameraRobot> previous_measurements_;

    KalmanFilter3D filter_;

    double previous_theta_;
    int unwrap_theta_ctr_;
    int health_;

    int robot_id_;

    unsigned int camera_id_;
};
}  // namespace vision_filter


#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <cctbx/miller.h>
#include <scitbx/array_family/flex_types.h>
#include <scitbx/array_family/shared.h>
#include <cctbx/miller/match_indices.h>
#include <scitbx/math/linear_correlation.h>

namespace af = scitbx::af;

using namespace boost::python;

namespace cctbx { namespace merging {

  void update_wij_rij(int const& i, int const& j,
       af::shared<cctbx::miller::index<int> > millers_i, af::shared<cctbx::miller::index<int> > millers_j,
       af::shared<double> data_i, af::shared<double> data_j,
       int const& i_start, int const& j_start,
       af::versa< double, af::flex_grid<> > wij_, af::versa< double, af::flex_grid<> > rij_,
       double const& sign, bool const& use_weights
                      ){
    cctbx::miller::match_indices matches(millers_i, millers_j);
    af::shared<double> intensities_i, intensities_j;
    for (int ipair = 0; ipair < matches.pairs().size(); ++ipair){
      intensities_i.push_back(data_i[i_start + matches.pairs()[ipair][0]]);
      intensities_j.push_back(data_j[j_start + matches.pairs()[ipair][1]]);
    }
    scitbx::math::linear_correlation<> corr(intensities_i.const_ref(), intensities_j.const_ref());
    //printf("%5d <--> %5d, matches=%4d, corr=%7.4f,%4d\n",i,j,matches.pairs().size(),corr.coefficient(),
      //wij_.accessor().focus()[0]);
    if (corr.is_well_defined()){
      int size_1d = wij_.accessor().focus()[0];
      double* wij_begin = wij_.begin();
      double* rij_begin = rij_.begin();
      if (use_weights) {
        wij_begin[i*size_1d + j] += corr.n();
        wij_begin[j*size_1d + i] += corr.n();
      } else {
        wij_begin[i*size_1d + j] += 1.;
        wij_begin[j*size_1d + i] += 1.;
      }
      rij_begin[i*size_1d + j] += sign * corr.coefficient();
      rij_begin[j*size_1d + i] += sign * corr.coefficient();
    }
  };

}}

BOOST_PYTHON_MODULE(cctbx_merging_ext)
{
  def ("update_wij_rij",&cctbx::merging::update_wij_rij);
}


/* Main memory port of MADlib Linear Regression
 */

//#include <regress/linear.cpp>

// Note: If errors occur in the following include files, it could indicate that
// new macros have been added to mainmemQL header files.

#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET

#include <cstdio>

#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <dbconnector/dbconnector.hpp>

#include "modules/regress/logistic.cpp"

using namespace madlib;
using namespace madlib::modules::regress;

typedef MutableArrayHandle<double> Handle_t;
int main( ) {
  printf("Generating Example array...\n");
  ArrayType arr;
  arr.len = 5;
  double arr_back[5] = {0, 0, 0, 0, 0};
  arr.ptr = (void*) arr_back;
  arr.ndims = 1;
  arr.dims[0] = 100;

  arr_back[0] = static_cast<double>(2);

  // step size
  arr_back[1] = 0.1;
  // coef
  arr_back[2] = 0.1;
  arr_back[3] = 0.1;

  *reinterpret_cast<uint64_t*>(&arr_back[4]) = 2;

  Handle_t  arrh (&arr);
  Allocator alloc;

  LogRegrIGDTransitionState<Handle_t> logr(arrh);
  LogRegrIGDTransitionState<Handle_t> prev_logr(arrh);
  logr.initialize(alloc, 2);
  printf("Num rows %%uh = %hu\n", (short)logr.numRows);

  LogRegrIGDTransitionState<Handle_t> logr_next(arrh);
  logr_next.initialize(alloc, 2);

  double ex1[2] = {1.0, 0.0};
  TransparentHandle<double> th(ex1);
  MappedColumnVector v1(th, 2);
  double ex2[2] = {0.0, 1.0};
  TransparentHandle<double> th2(ex2);
  MappedColumnVector v2(th2, 2);
  logregr_igd_step_transition step;

  for (int i = 0; i < 500; i++) {
  printf("(pre-step)  model = %f %f\n", arr_back[2], arr_back[3]);
  printf("(pre-step)  logr.nrows = %hd\n", (short)logr.numRows);
  AnyType t1;
  t1 << logr;
  t1 << true;
  t1 << v1;
  t1 << prev_logr;

  // mutates logr
  logr_next = step.run(t1);

  printf("*** coef: %f %f\n", (double)logr_next.coef[0], (double)logr_next.coef[1]);
  AnyType t2;
  t2 << logr_next;
  t2 << false;
  t2 << v2;
  t2 << prev_logr;
  logr = step.run(t2);
  printf("*** coef: %f %f\n", (double)logr.coef[0], (double)logr.coef[1]);
  }
}


#ifndef GUNEROMEMBERSHIPCIRCUIT_H_
#define GUNEROMEMBERSHIPCIRCUIT_H_

#include <deque>
#include <mutex>
#include <boost/optional.hpp>
#include <boost/static_assert.hpp>
#include <libff/common/utils.hpp>
#include <libsnark/common/default_types/r1cs_gg_ppzksnark_pp.hpp>
#include <libsnark/common/default_types/r1cs_gg_ppzksnark_pp.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp>
#include <libff/algebra/fields/field_utils.hpp>
#include <libff/algebra/scalar_multiplication/multiexp.hpp>
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libff/algebra/curves/edwards/edwards_pp.hpp>
#include <libff/algebra/curves/mnt/mnt4/mnt4_pp.hpp>
#include <libff/algebra/curves/mnt/mnt6/mnt6_pp.hpp>
#include <libff/common/utils.hpp>
#include <libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp>

#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp>

#include "gunero_merkle_tree.hpp"
#include "guneromembership_gadget.hpp"
#include "GuneroProof.hpp"

using namespace libsnark;

namespace gunero {

class GuneroMembershipWitness{
public:
    uint256 W;
    uint8_t N_account;
    uint256 V_account;

    GuneroMembershipWitness() {}
    GuneroMembershipWitness(
        const uint256& pW,
        const uint8_t& pN_account,
        const uint256& pV_account
    ) : W(pW),
        N_account(pN_account),
        V_account(pV_account)
    {
    }
    ~GuneroMembershipWitness() {}

    ADD_SERIALIZE_METHODS;

    template <typename Stream, typename Operation>
    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
        READWRITE(W);
        READWRITE(N_account);
        READWRITE(V_account);
    }

    friend std::ostream& operator<<(std::ostream &out, const GuneroMembershipWitness &witness)
    {
        ::Serialize(out, witness, 1, 1);

        return out;
    }

    friend std::istream& operator>>(std::istream &in, GuneroMembershipWitness &witness)
    {
        ::Unserialize(in, witness, 1, 1);

        return in;
    }
};

///// MEMBERSHIP PROOF /////
// Public Parameters:
// Authorization Root Hash (W)
// Account Status (N_account)
// Account View Hash (V_account)

// Private Parameters:
// Account Secret Key (s_account)
// alt: Account (A_account)
// Authorization Merkle Path (M_account[160])
// Account View Randomizer (r_account)

//1) Obtain A_account from s_account through EDCSA (secp256k1) operations
//1 alt) Obtain P_proof from s_account through PRF operations
//2) Validate W == calc_root(A_account, N_account, M_account[160]) (User is authorized)
//2 alt) Validate W == calc_root(A_account, keccak256(P_proof,N_account), M_account[160]) (User is authorized)
//3) Validate V_account == keccak256(A_account, keccak256(W,r_account) (View Hash is consistent)
//3) alt) Validate V_account == keccak256(P_proof, keccak256(W,r_account) (View Hash is consistent)
template<typename FieldT, typename BaseT, typename HashT, size_t tree_depth>
class GuneroMembershipCircuit
{
public:
    GuneroMembershipCircuit()
    {}
    ~GuneroMembershipCircuit() {}

    void generate(
        const std::string& r1csPath,
        const std::string& pkPath,
        const std::string& vkPath
    ) {
        protoboard<FieldT> pb;
        guneromembership_gadget<FieldT, BaseT, HashT, tree_depth> gunero(pb);

        gunero.generate_r1cs_constraints(r1csPath, pkPath, vkPath);
    }

    static void makeTestVariables(
        const uint252& s_account,
        const uint8_t& N_account,
        const uint256& r_account,
        libff::bit_vector& P_proof,
        libff::bit_vector& leaf,
        std::vector<gunero_merkle_authentication_node>& M_account,
        libff::bit_vector& A_account_padded,
        libff::bit_vector& W,
        libff::bit_vector& view_hash_1,
        libff::bit_vector& V_account
    )
    {
        /* prepare test variables */
#ifdef DEBUG
        libff::print_header("Gunero prepare test variables");
#endif
        M_account = std::vector<gunero_merkle_authentication_node>(tree_depth);

        libff::bit_vector s_account_256(uint252_to_bool_vector_256(s_account));
        assert(s_account_256.size() == HashT::get_digest_len());

        libff::bit_vector N_account_lsb(uint256_to_bool_vector(uint8_to_uint256(N_account)));
        assert(N_account_lsb.size() == HashT::get_digest_len());

        {//P_proof = Hash(0000b | (s_account&252b), 0)
            libff::bit_vector block(HashT::get_digest_len());
            block.insert(block.begin(), s_account_256.begin(), s_account_256.end());
            assert(block.at(0) == false);
            assert(block.at(1) == false);
            assert(block.at(2) == false);
            assert(block.at(3) == false);

            P_proof = HashT::get_hash(block);

            block = P_proof;
            block.insert(block.end(), N_account_lsb.begin(), N_account_lsb.end());
            leaf = HashT::get_hash(block);//hash(P_proof,N_account)
        }

        // libff::bit_vector prev_hash(HashT::get_digest_len());
        // std::generate(prev_hash.begin(), prev_hash.end(), [&]() { return std::rand() % 2; });
        // leaf = prev_hash;
        assert(leaf.size() == HashT::get_digest_len());
        libff::bit_vector prev_hash = leaf;

        // libff::bit_vector address_bits;
        libff::bit_vector A_account(tree_depth);

        size_t address = 0;
        for (long level = tree_depth-1; level >= 0; --level)
        {
            //Generate random uncle position
            const bool computed_is_right = (std::rand() % 2);
            address |= (computed_is_right ? 1ul << (tree_depth-1-level) : 0);
            // address_bits.push_back(computed_is_right);
            A_account.at(level) = computed_is_right;

            //Generate random uncle
            libff::bit_vector uncle(HashT::get_digest_len());
            std::generate(uncle.begin(), uncle.end(), [&]() { return std::rand() % 2; });

            //Create block of prev_hash + uncle
            libff::bit_vector block = prev_hash;
            block.insert(computed_is_right ? block.begin() : block.end(), uncle.begin(), uncle.end());
            //Compress block to new hash
            libff::bit_vector h = HashT::get_hash(block);

            //Add uncle to path
            M_account[level] = uncle;

            prev_hash = h;
        }

        W = prev_hash;

        A_account_padded = libff::bit_vector(HashT::get_digest_len() - A_account.size());
        A_account_padded.insert(A_account_padded.begin(), A_account.begin(), A_account.end());

        assert(A_account_padded.size() == HashT::get_digest_len());

        libff::bit_vector r_account_lsb(uint256_to_bool_vector(r_account));
        assert(r_account_lsb.size() == HashT::get_digest_len());

        {//view_hash_1 = hash(W, r_account_lsb)
            libff::bit_vector block = W;
            block.insert(block.end(), r_account_lsb.begin(), r_account_lsb.end());
            view_hash_1 = HashT::get_hash(block);//hash(W, r_account_lsb)

            //V_account = hash(P_proof, hash(W, r_account_lsb))
            block = P_proof;
            block.insert(block.end(), view_hash_1.begin(), view_hash_1.end());
            V_account = HashT::get_hash(block);//hash(P_proof, view_hash_1)
        }

#ifdef DEBUG
        printf("\n"); libff::print_indent(); libff::print_mem("after prepare test variables"); libff::print_time("after prepare test variables");
#endif
    }

    static void calculateMerkleRoot(
        const libff::bit_vector& A_account,
        const libff::bit_vector& leaf,
        const std::vector<gunero_merkle_authentication_node>& M_account,
        libff::bit_vector& W
    )
    {
        const bool UseNewFormat = false;

#ifdef DEBUG
        libff::print_header("Gunero calculateMerkleRoot()");
#endif
        assert(M_account.size() == tree_depth);

        // libff::bit_vector prev_hash(HashT::get_digest_len());
        // std::generate(prev_hash.begin(), prev_hash.end(), [&]() { return std::rand() % 2; });
        // leaf = prev_hash;
        assert(leaf.size() == HashT::get_digest_len());
        libff::bit_vector prev_hash = leaf;

        // libff::bit_vector address_bits;
        assert(A_account.size() == tree_depth);

        // size_t address = 0;
        for (long level = tree_depth-1; level >= 0; --level)
        {
            //A_account is accessed LSB but is processed as MSB (root) to LSB (leaf)
            bool parameter_is_left;
            if (UseNewFormat)
            {
                parameter_is_left = A_account.at(tree_depth-1-level);
            }
            else
            {
                parameter_is_left = !A_account.at(level);
            }

            // //Generate random uncle
            // libff::bit_vector uncle(HashT::get_digest_len());
            // std::generate(uncle.begin(), uncle.end(), [&]() { return std::rand() % 2; });
            libff::bit_vector uncle = M_account[level];

            //Create block of prev_hash + uncle
            libff::bit_vector block = prev_hash;
            block.insert((!parameter_is_left) ? block.begin() : block.end(), uncle.begin(), uncle.end());
            //Compress block to new hash
            libff::bit_vector h = HashT::get_hash(block);

            // //Add uncle to path
            // M_account[level] = uncle;

            prev_hash = h;
        }

        W = prev_hash;

#ifdef DEBUG
        printf("\n"); libff::print_indent(); libff::print_mem("after calculateMerkleRoot()"); libff::print_time("after calculateMerkleRoot()");
#endif
    }

    bool prove(
        const uint256& pW,
        const uint8_t& pN_account,
        const uint256& pV_account,
        const uint252& ps_account,
        const std::vector<gunero_merkle_authentication_node>& pM_account,
        const uint160& pA_account,
        const uint256& pr_account,
        const r1cs_ppzksnark_proving_key<BaseT>& pk,
        const r1cs_ppzksnark_verification_key<BaseT>& vk,
        GuneroProof& proof
    )
    {
#ifdef DEBUG
        libff::print_header("Gunero witness (proof)");
#endif

        {
            r1cs_primary_input<FieldT> primary_input;
            r1cs_auxiliary_input<FieldT> aux_input;
            {
                protoboard<FieldT> pb;
                {
#ifdef DEBUG
                    libff::print_header("Gunero guneromembership_gadget.load_r1cs_constraints()");
#endif

                    guneromembership_gadget<FieldT, BaseT, HashT, tree_depth> gunero(pb);

                    gunero.generate_r1cs_witness(
                        pW,
                        pN_account,
                        pV_account,
                        ps_account,
                        pM_account,
                        pA_account,
                        pr_account
                    );

#ifdef DEBUG
                    printf("\n"); libff::print_indent(); libff::print_mem("after guneromembership_gadget.load_r1cs_constraints()"); libff::print_time("after guneromembership_gadget.load_r1cs_constraints()");
#endif
                }

                // The constraint system must be satisfied or there is an unimplemented
                // or incorrect sanity check above. Or the constraint system is broken!
                assert(pb.is_satisfied());

                // TODO: These are copies, which is not strictly necessary.
                primary_input = pb.primary_input();
                aux_input = pb.auxiliary_input();

                // Swap A and B if it's beneficial (less arithmetic in G2)
                // In our circuit, we already know that it's beneficial
                // to swap, but it takes so little time to perform this
                // estimate that it doesn't matter if we check every time.
                // pb.constraint_system.swap_AB_if_beneficial();

                //Test witness_map()
                {
                    r1cs_primary_input<FieldT> primary_input_test = guneromembership_gadget<FieldT, BaseT, HashT, tree_depth>::witness_map(
                        pW,
                        pN_account,
                        pV_account
                    );
                    assert(primary_input == primary_input_test);
                }
            }

            r1cs_ppzksnark_proof<BaseT> r1cs_proof = r1cs_ppzksnark_prover<BaseT>(
                pk,
                primary_input,
                aux_input
            );

            proof = GuneroProof(r1cs_proof);

#ifdef DEBUG
            printf("\n"); libff::print_indent(); libff::print_mem("after witness (proof)"); libff::print_time("after witness (proof)");
#endif
        }

        //Verify
        {
            r1cs_primary_input<FieldT> primary_input = guneromembership_gadget<FieldT, BaseT, HashT, tree_depth>::witness_map(
                pW,
                pN_account,
                pV_account
            );

            return r1cs_ppzksnark_verifier_strong_IC<BaseT>(vk, primary_input, proof.to_libsnark_proof<r1cs_ppzksnark_proof<BaseT>>());
        }
    }

    bool verify(
        const uint256& W,
        const uint8_t& N_account,
        const uint256& V_account,
        const GuneroProof& proof,
        const r1cs_ppzksnark_verification_key<BaseT>& vk,
        const r1cs_ppzksnark_processed_verification_key<BaseT>& vk_precomp
        )
    {
        try
        {
            r1cs_primary_input<FieldT> primary_input = guneromembership_gadget<FieldT, BaseT, HashT, tree_depth>::witness_map(
                W,
                N_account,
                V_account
            );

            r1cs_ppzksnark_proof<BaseT> r1cs_proof = proof.to_libsnark_proof<r1cs_ppzksnark_proof<BaseT>>();

            ProofVerifier<BaseT> verifierEnabled = ProofVerifier<BaseT>::Strict();

            bool verified = verifierEnabled.check(
                vk,
                vk_precomp,
                primary_input,
                r1cs_proof
            );

#ifdef DEBUG
            printf("\n"); libff::print_indent(); libff::print_mem("after verify"); libff::print_time("after verify");
#endif

            if (verified)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (...)
        {
            return false;
        }
    }
};

} // end namespace `gunero`

#endif /* GUNEROMEMBERSHIPCIRCUIT_H_ */


#pragma once
#include "../simd.h"
#include <boost/integer.hpp>
#include <type_traits>

namespace coreutil {
namespace simd_detail {

template <class V, bool F = std::is_floating_point<simd_element_type<V>>()>
struct simd_abs_impl;

template <class V> inline V simd_abs_f(V x);
template <class V> inline V simd_abs_i(V x);

template <class V> struct simd_abs_impl<V, true> {
  inline V operator()(V x) { return simd_abs_f(x); }
};
template <class V> struct simd_abs_impl<V, false> {
  inline V operator()(V x) { return simd_abs_i(x); }
};

template <class V>
inline V simd_abs_f(V x) {
  typedef simd_element_type<V> real_type;
  constexpr unsigned bits = 8 * sizeof(real_type);

  typedef typename boost::uint_t<bits>::exact uint_type;
  typedef simd_t<uint_type, simd_size<V>> uint_vector;

  uint_vector mask = simd_pack<uint_vector>(uint_type(-1) >> 1);
  return V(uint_vector(x) & mask);
}

#if (defined(__i386__) || defined(__x86_64__)) && defined(__SSSE3__)
template <>
inline v4si simd_abs_i(v4si x) {
  return v4si(_mm_abs_epi32(__m128i(x)));
}
template <>
inline v8ss simd_abs_i(v8ss x) {
  return v8ss(_mm_abs_epi16(__m128i(x)));
}
template <>
inline v16sb simd_abs_i(v16sb x) {
  return v16sb(_mm_abs_epi8(__m128i(x)));
}
#endif

#if (defined(__i386__) || defined(__x86_64__)) && defined(__AVX__)
template <>
inline v8si simd_abs_i(v8si x) {
  return v8si(_mm256_abs_epi32(__m256i(x)));
}
template <>
inline v16ss simd_abs_i(v16ss x) {
  return v16ss(_mm256_abs_epi16(__m256i(x)));
}
template <>
inline v32sb simd_abs_i(v32sb x) {
  return v32sb(_mm256_abs_epi8(__m256i(x)));
}
#endif

template <class V>
inline V simd_abs_i(V x) {
  V neg = x < 0;
  return (neg & -x) | (~neg & x);
}

}  // namespace simd_detail

template <class V>
inline V simd_abs(V x) {
  return simd_detail::simd_abs_impl<V>()(x);
}

}  // namespace coreutil


#ifndef PRESSIODEMOAPPS_PREDICATES_NATIVE_EIGEN_VECTOR_HPP_
#define PRESSIODEMOAPPS_PREDICATES_NATIVE_EIGEN_VECTOR_HPP_

#include <Eigen/Dense>

namespace pressiodemoapps{

template <typename T, typename enable = void>
struct is_dynamic_row_vector_eigen : std::false_type {};

template <typename T>
struct is_dynamic_row_vector_eigen<
  T,
  std::enable_if_t<
    std::is_same<
      typename std::remove_cv<T>::type,
		  Eigen::Matrix<typename T::Scalar,1, Eigen::Dynamic>
		 >::value
    >
  > : std::true_type{};
//----------------------------------------------

template <typename T, typename enable = void>
struct is_static_row_vector_eigen : std::false_type {};

template <typename T>
struct is_static_row_vector_eigen<
  T,
  std::enable_if_t<
    std::is_same<
     typename std::remove_cv<T>::type,
		 Eigen::Matrix<typename T::Scalar, 1, T::ColsAtCompileTime>
		 >::value and
    !is_dynamic_row_vector_eigen<T>::value
    >
  > : std::true_type{};
//----------------------------------------------

template <typename T, typename enable = void>
struct is_dynamic_column_vector_eigen : std::false_type {};

template <typename T>
struct is_dynamic_column_vector_eigen<
  T,
  std::enable_if_t<
    std::is_same<
     typename std::remove_cv<T>::type,
		 Eigen::Matrix<typename T::Scalar, Eigen::Dynamic, 1>
		 >::value
    >
  > : std::true_type{};
//----------------------------------------------

template <typename T, typename enable = void>
struct is_static_column_vector_eigen : std::false_type {};

template <typename T>
struct is_static_column_vector_eigen<
  T,
  std::enable_if_t<
    std::is_same<
     typename std::remove_cv<T>::type,
		 Eigen::Matrix<typename T::Scalar, T::RowsAtCompileTime,1>
		 >::value and
    !is_dynamic_column_vector_eigen<T>::value
    >
  > : std::true_type{};
//----------------------------------------------

template <typename T, typename enable = void>
struct is_static_vector_eigen : std::false_type {};

template <typename T>
struct is_static_vector_eigen<
  T,
  std::enable_if_t<
    is_static_row_vector_eigen<T>::value ||
    is_static_column_vector_eigen<T>::value
    >
  > : std::true_type{};
//----------------------------------------------

template <typename T, typename enable = void>
struct is_dynamic_vector_eigen : std::false_type {};

template <typename T>
struct is_dynamic_vector_eigen<
  T,
  std::enable_if_t<
    is_dynamic_row_vector_eigen<T>::value or
    is_dynamic_column_vector_eigen<T>::value
    >
  > : std::true_type{};
//----------------------------------------------

template <typename T, typename enable = void>
struct is_vector_eigen : std::false_type {};

template <typename T>
struct is_vector_eigen<
  T,
  std::enable_if_t<
    is_dynamic_vector_eigen<T>::value or
    is_static_vector_eigen<T>::value
    >
  > : std::true_type{};

}//end namespace
#endif


//==================================================================================================
/*!

  Copyright 2016 NumScale SAS

  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/simd/function/scalar/quadrant.hpp>
#include <boost/simd/detail/dispatch/meta/as_integer.hpp>

#include <scalar_test.hpp>

STF_CASE_TPL (" quadrant real",  STF_IEEE_TYPES)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;

   using bs::quadrant;
   using r_t = decltype(quadrant(T()));
   using iT =  bd::as_integer_t<T>;
   STF_TYPE_IS(r_t, T);

  for(iT i=0; i < 128; i++)
  {
    STF_EQUAL(quadrant(T(i)), i&iT(3));
  }
} // end of test for floating_


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

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

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

//[interior_type
//`Shows how to use the interior_type metafunction

#include <iostream>
#include <typeinfo>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/geometries/adapted/boost_array.hpp>

BOOST_GEOMETRY_REGISTER_BOOST_ARRAY_CS(cs::cartesian)

int main()
{
    // Define a polygon storing points in a deque and storing interior rings
    // in a list (note that std::list is not supported by most algorithms
    // because not supporting a random access iterator)
    typedef boost::geometry::model::polygon
        <
            boost::array<short, 3>,
            true, true,
            std::deque, std::list
        > polygon;

    std::cout << typeid(boost::geometry::interior_type<polygon>::type).name() << std::endl;

    return 0;
}

//]

//[interior_type_output
/*`
Output (using MSVC) is a long story (part manually replaced with ellipsis):
[pre
class std::list<class boost::geometry::model::ring<class boost::array<short,3>,1,1,class std::deque,class std::allocator>,class std::allocator<...> > >
]
*/
//]