/*
   Copyright (C) 2016-2021 by Synge Todo <wistaria@phys.s.u-tokyo.ac.jp>
                              Chihiro Kondo <chihiro.kondo@phys.s.u-tokyo.ac.jp>

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

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

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

// Density of state of square lattice Ising model

#pragma once

#include <cmath>
#include <limits>
#include <vector>
#include <boost/math/constants/constants.hpp>
#include <boost/math/differentiation/autodiff.hpp>
#include <boost/math/special_functions/binomial.hpp>
#include <boost/math/special_functions/factorials.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <lattice/graph.hpp>

namespace ising {
namespace dos {
namespace square {

typedef unsigned long uint_t;

std::vector<uint_t> count(uint_t Lx, uint_t Ly) {
  auto basis = lattice::basis::simple(2);
  auto unitcell = lattice::unitcell(2);
  unitcell.add_site(lattice::coordinate(0, 0), 0);
  unitcell.add_bond(0, 0, lattice::offset(1, 0), 0);
  unitcell.add_bond(0, 0, lattice::offset(0, 1), 0);
  auto graph = lattice::graph(basis, unitcell, lattice::extent(Lx, Ly));
  if (graph.num_bonds() >= std::numeric_limits<uint_t>::digits)
    throw std::range_error("Error: system size is too large\n");

  std::vector<uint_t> dos(graph.num_bonds() + 1, 0);
  uint_t num_states = 1 << graph.num_sites();
  for (uint_t c = 0; c < num_states; ++c) {
    uint_t energy = 0;
    for (uint_t b = 0; b < graph.num_bonds(); ++b) {
      uint_t ci = (c >> graph.source(b)) & 1;
      uint_t cj = (c >> graph.target(b)) & 1;
      energy += (ci ^ cj);
    }
    ++dos[energy];
  }
  return dos;
}

// Density of state of square lattice Ising model

// Ref: P. Beale, Phys. Rev. Lett. 76, 78-81 (1996)

namespace {

template<typename T>
T zero(const T& x) { return 0 * x; }

template<typename T>
T one(const T& x) { return 1 + zero(x); }

template<typename T>
T power_n(const T& x, unsigned n) {
  auto res = one(x);
  for (unsigned i = 0; i < n; ++i) res *= x;
  return res;
}

template<typename T>
T alpha(const T& x, const T& beta, unsigned n, unsigned k) {
  using std::cos;
  auto pi = boost::math::constants::pi<typename T::root_type>();
  return power_n(1 + x * x, 2) - beta * cos(pi * k / n);
}

}

using namespace boost::math;
using namespace boost::math::differentiation;
namespace mp = boost::multiprecision;
typedef mp::cpp_int int_type;

template<unsigned Order, unsigned Digits10, class ExponentType = boost::int32_t>
std::vector<mp::cpp_int> finite(uint_t m, uint_t n) {
  typedef mp::number<mp::cpp_dec_float<Digits10, ExponentType>> real_type;
  std::cout << std::setprecision(std::numeric_limits<real_type>::max_digits10);

  auto const x = make_fvar<real_type, Order>(0);
  auto const xpo = make_fvar<real_type, Order>(-1);
  auto const xmo = make_fvar<real_type, Order>(+1);

  auto beta = 2 * x * xpo * xmo;
  auto beta_m = power_n(beta, m);
  auto c0 = power_n(xmo, m) + power_n(x * xpo, m);
  auto s0 = power_n(xmo, m) - power_n(x * xpo, m);
  auto cn = power_n(xpo, m) + power_n(x * xmo, m);
  auto sn = power_n(xpo, m) - power_n(x * xmo, m);

  auto z1 = zero(x);
  auto z2 = zero(x);
  auto z3 = zero(x);
  auto z4 = zero(x);
  if ((n & 1) == 0) {
    z1 = one(x) / 2;
    z2 = one(x) / 2;
    z3 = c0 * cn / 2;
    z4 = s0 * sn / 2;
  } else {
    z1 = cn / 2;
    z2 = sn / 2;
    z3 = c0 / 2;
    z4 = s0 / 2;
  }
  for (unsigned k = 1; k < n; ++k) {
    auto ak = alpha(x, beta, n, k);
    auto v = zero(x);
    for (unsigned j = 0; j <= m; j += 2)
      v += binomial_coefficient<real_type>(m, j)
        * power_n(ak * ak - beta * beta, j/2) * power_n(ak, m-j);
    if ((k & 1) == 1) {
      z1 *= (v + beta_m) / power_n(real_type(2), m - 1);
      z2 *= (v - beta_m) / power_n(real_type(2), m - 1);
    } else {
      z3 *= (v + beta_m) / power_n(real_type(2), m - 1);
      z4 *= (v - beta_m) / power_n(real_type(2), m - 1);
    }
  }
  auto zmn = z1 + z2 + z3 + z4;

  std::vector<int_type> dos;
  for (unsigned i = 0; i <= 2 * m * n; ++i) dos.push_back(int_type(zmn.at(i) + 0.01));
  auto sum = std::accumulate(dos.begin(), dos.end(), int_type(0));
  if (sum != power_n(int_type(2), m * n)) {
    std::cerr << "Error: result check failed\n";
    throw(0);
  }
  return dos;
}

}
}
}


// test_minimum.cpp
// (c) Tivole

#include <boost/test/unit_test.hpp>
#include "../src/numerary.hpp"

namespace numerary
{

    BOOST_AUTO_TEST_SUITE(TestMinimum)

    BOOST_AUTO_TEST_CASE(test_minimum_bisection)
    {
        const double eps = 1.e-9;
        double answer;
        double expected_answer;
        short int result;
        short int expected_result;

        // Testing sin function
        expected_result = 1;
        expected_answer = -1.0 * M_PI_2;
        result = Numerary::minimum(sin, -3, 3, &answer, "bisection", eps);
        BOOST_CHECK_EQUAL(result, expected_result);
        BOOST_CHECK(fabs(answer - expected_answer) < 1.e-7);

	    // Testing log function
        expected_result = 1;
        expected_answer = 0.5;
        result = Numerary::minimum(log, 0.5, 4, &answer, "bisection", eps);
        BOOST_CHECK_EQUAL(result, expected_result);
        BOOST_CHECK(fabs(answer - expected_answer) < 1.e-7);
    }

    BOOST_AUTO_TEST_CASE(test_minimum_golden_ratio)
    {
        const double eps = 1.e-9;
        double answer;
        double expected_answer;
        short int result;
        short int expected_result;

        // Testing sin function
        expected_result = 1;
        expected_answer = -1.0 * M_PI_2;
        result = Numerary::minimum(sin, -3, 3, &answer, "golden_ratio", eps);
        BOOST_CHECK_EQUAL(result, expected_result);
        BOOST_CHECK(fabs(answer - expected_answer) < 1.e-7);

	    // Testing cos function
        expected_result = 1;
        expected_answer = 0.5;
        result = Numerary::minimum(log, 0.5, 4, &answer, "golden_ratio", eps);
        BOOST_CHECK_EQUAL(result, expected_result);
        BOOST_CHECK(fabs(answer - expected_answer) < 1.e-7);
    }

    BOOST_AUTO_TEST_SUITE_END()
}


// HelloWorld.cpp : main project file.
//#define _CRTDBG_MAP_ALLOC
//#include <stdlib.h>
//#include <crtdbg.h>
#include "stdafx.h"
#include <NTL/ZZ_pXFactoring.h>
#include "Shamir.h"
#include "string.h"
#include "ShamirShare.h"
#include "BenalohLeichter.h"
//#include "AccessStructure.h"
//#include "Trustee.h"
#include "ISecretShare.h"
#include "NonInteractiveChaumPedersen.h"
#include "NTLHelper.h"
#include "PrimeGenerator.h"
#include <vector>
#include "Schoenmakers.h"
#include "PublicKeyEncryption.h"
#include <tuple>
//#include "vld.h"
using namespace System;
using namespace std;
using namespace NTL;
using namespace System::Collections::Generic;
using namespace SecretSharingCore::Algorithms;
using namespace SecretSharingCore::Algorithms::PVSS;
using namespace SecretSharingCore::Algorithms::PKE;
using namespace SecretSharingCore::Common;
using namespace SecretSharingCore::Algorithms::GeneralizedAccessStructure;
using namespace SecretSharing::OptimalThreshold::Models;
using namespace SecretSharing::OptimalThreshold;
using namespace SecretSharingCore::ZKProtocols;
using namespace SecretSharingCore;

void MarshalString(String ^ s, string& os)
{
	using namespace Runtime::InteropServices;
	const char* chars =
		(const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
	os = chars;
	Marshal::FreeHGlobal(IntPtr((void*)chars));
}

void runByteChunkShare(){
	int k = 3;
	int n = 10;
	Byte chunkSize = 16;
	String^ secret = "1234567812345678";
	array<Byte>^ bytes = Encoding::UTF8->GetBytes(secret->ToCharArray());
	Shamir^ secretshare = gcnew Shamir();
#ifdef calcPrimeTime
	double a = 0;
	List<IShareCollection^>^ shares = secretshare->DivideSecret(k, n, bytes,chunkSize,a);
#else
	List<IShareCollection^>^ shares = secretshare->DivideSecret(k, n, bytes, chunkSize);
#endif
	//List<IShareCollection^>^ sharesStr = secretshare->DivideSecret(k, n,secret);
	delete bytes;
	for (int i = 0; i < k; i++)
	{
		IShareCollection^ col = shares[i];
		//IShareCollection^ colstr = sharesStr[i];

		Console::WriteLine(col->ToString());
		//Console::WriteLine(colstr->ToString());

	/*	for (int j = 0; j < col->GetCount(); j++)
		{
			IShare^ share = col->GetShare(j);
			IShare^ shareStr = colstr->GetShare(j);
			Console::WriteLine(share->ToString());
			Console::WriteLine(shareStr->ToString());
		}*/
	}

	List<IShareCollection^>^ recshares = shares->GetRange(0, k);
	array<Byte>^ recoveredSecret = secretshare->ReconstructSecret(recshares, chunkSize);
	//List<IShareCollection^>^ recsharesstr = sharesStr->GetRange(0, k);
	//String^ recoveredSecretstr = secretshare->ReconstructSecret(recsharesstr);

	Console::WriteLine("Secret:"+Encoding::UTF8->GetString(recoveredSecret));
	for (int i = 0; i < recshares->Count; i++)
	{
		delete recshares[i];
	}
	//Console::WriteLine("SecretStr:" + recoveredSecretstr);
}

void PrintIShares(List<IShare^>^ shares){
	for (int j = 0; j < shares-> Count; j++)
	{
		Console::WriteLine(shares[j]->ToString());
	}
}

int main(array<System::String ^> ^args)
{
	//PrimeGenerator^ pg = gcnew PrimeGenerator();
	//ZZ p = ZZ(263);
	//ZZ_p::init(p);
	//cout<< pg->IsGeneratorOfP(p, ZZ_p(5));
	//Console::Read();

	Schoenmakers^ sch = gcnew Schoenmakers();
	sch->SelectPrimeAndGenerators(1);
	ZZ_p g = sch->Getg();
	ZZ_p G = sch->GetG();
	ZZ q = sch->Getq();
	cout <<"g:"<<g <<'\n';
	cout << "G:" << G << '\n';
	cout << "q:" << q << '\n';

	int n = 5;
	// generate n keypairs
	vector<ZZ_p> publickeys;
	vector<tuple<ZZ_p, ZZ_p>> keypairs;
	PublicKeyEncryption^ pke = gcnew PublicKeyEncryption();
	for (int i = 0; i < n; i++)
	{
		tuple<ZZ_p,ZZ_p> pair= pke->GenerateKeyPair(q, G);
		keypairs.push_back(pair);
		//cout <<"x:"<< get<0>(pair)<<" y:"<<get<1>(pair)<<'\n';
		publickeys.push_back(get<1>(pair));
	}

	int t = 3;

	vector<ZZ_p> encryptedShares;
	vector<ZZ_p> commitments;
	vector<ZZ_p> c,r;
	ZZ_p secret;
	//provide public keys to schoenmakers
	sch->SetPublicKeys(publickeys);

	List<array<Byte>^>^ commitsList = gcnew List<array<Byte>^>();
	array<Byte>^ secretB;
	array<Byte>^ U;
	array<Byte>^ sigma = Encoding::UTF8->GetBytes("4");
	List<SchoenmakersShare^>^ shares =  sch->Distribute(t, n,sigma, commitsList, secretB,U);
	List<SchoenmakersShare^>^ poolesshares = gcnew List<SchoenmakersShare^> ();
	int i = 0;
	for each (SchoenmakersShare^ share in shares)
	{
		SchoenmakersShare^ pooledshare = share;
		sch->PoolShare(gcnew Tuple<array<Byte>^, array<Byte>^>(NTLHelper::ZZpToByte(get<0>(keypairs.at(i))), NTLHelper::ZZpToByte(get<1>(keypairs.at(i)))), pooledshare);
		poolesshares->Add(pooledshare);
		i++;
	}
	array<Byte>^ reconed = sch->Reconstruct(t, poolesshares, U);
	//Console::Read();

	sch->Distribute(t, n, encryptedShares, commitments, r, c,secret);

	for (int i = 0; i < n; i++)
	{
		bool verified = sch->VerifyDistributedShare(i+1, r.at(i), c.at(i), encryptedShares.at(i), commitments, publickeys.at(i));
		cout << "share i:" << i+1 << " verified status:" << verified<<'\n';
		//if (!verified) throw gcnew Exception("Failed to verify the share!");
	}
	vector<ZZ_p> rshares;
	vector<ZZ_p> cshares;
	vector<ZZ_p> S;
	for (int i = 0; i < encryptedShares.size(); i++)
	{
		ZZ_p rshare, cshare;
		//each party pool his share and compute zero knowledge r and c
		ZZ_p Si = sch->PoolShare(get<0>(keypairs.at(i)), get<1>(keypairs.at(i)), encryptedShares.at(i), rshare, cshare);
		rshares.push_back(rshare);
		cshares.push_back(cshare);
		S.push_back(Si);
	}
	//dealer, at this point can verify decrypted shares
	bool verifyConstruction = sch->VerifyPooledShares(t, S, encryptedShares, rshares, cshares);
	cout << "Construction verified:" << verifyConstruction<<'\n';

	if (verifyConstruction){
		ZZ_p secret = sch->Reconstruct(t,S);
		cout <<"secret:" <<secret<<'\n';
	}
	Console::Read();
	return 0;

	again:
	array<Byte>^ Prime =   NTLHelper::NumberToZZByte(17);
	NTLHelper::InitZZ_p(Prime);

	array<Byte>^ Base1 = NTLHelper::NumberToZZpByte(3);
	array<Byte>^ Base2 = NTLHelper::NumberToZZpByte(5);
    array<Byte>^ Result1 = NTLHelper::NumberToZZpByte((long)pow(3,7));
	array<Byte>^ Result2 = NTLHelper::NumberToZZpByte((long)pow(5,7));
	array<Byte>^ Secret = NTLHelper::NumberToZZpByte(7);
	array<Byte>^ R;
	array<Byte>^ C;

	NonInteractiveChaumPedersen^ NICP = gcnew NonInteractiveChaumPedersen(Prime);
	NICP->ComputeProofs(Base1,Base2,Result1,Result2,Secret,R,C);
	bool Proved = NICP ->VerifyProofs(Base1,Base2,Result1,Result2,R,C);
	cout << "Proved:" << Proved<<'\n';
	Console::Read();
	goto again;

	/*ZZ prime = ZZ(17);
	ZZ_p::init(prime);
	NonInteractiveChaumPedersen^ nicp = gcnew NonInteractiveChaumPedersen(prime);
	ZZ_p base1 = ZZ_p(3);
	ZZ_p base2 = ZZ_p(5);
	ZZ secret = ZZ(7);
	ZZ_p result1 = power(base1, secret);
	ZZ_p result2 = power(base2, secret);
	ZZ_p c;
	ZZ_p r;
	nicp->ComputeProofs(base1, base2, result1, result2, to_ZZ_p(secret), r, c);

	cout <<"r: "<< r<<'\n';
	cout << "c: " << c << '\n';

	bool proved = nicp->VerifyProofs(base1, base2, result1, result2, r, c);
	cout << "proved:" << proved<<'\n';
	Console::Read();

	goto again;*/

	/*BenalohLeichter^ benaloh = gcnew BenalohLeichter();
	AccessStructure^ access = gcnew AccessStructure("p1^p2^p3,p2^p3^p4,p1^p3^p4,p1^p2^p4");
	access = ThresholdHelper::OptimiseAccessStructure(access, true);
	array<Byte>^ secretBytes = Encoding::UTF8->GetBytes("12345678");
	List<IShareCollection^>^ shares =  benaloh->DivideSecret(secretBytes, access);
	array<Byte>^ reconSecretBytes = benaloh->ReconstructSecret(shares[0]);
	Console::WriteLine(Encoding::UTF8->GetString(reconSecretBytes));
*/
	//_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);

	/*Vec<ZZ_p> y = vec_ZZ_p();
	Vec<ZZ_p> x = vec_ZZ_p();

	ZZ_p::init(ZZ(199));
	ZZ_p y1 = ZZ_p(68);
	ZZ_p y2 = ZZ_p(2);
	ZZ_p y3 = ZZ_p(92);

		x.append(ZZ_p(1));
		x.append(ZZ_p(2));
		x.append(ZZ_p(3));

		y.append(y1);
		y.append(y2);
		y.append(y3);

	ZZ_pX interpolatedf = interpolate(x, y);
	cout << "interpol g(x):" << interpolatedf;*/

	//runByteChunkShare();

	//IShare^ sharezz = gcnew ShamirShare(1, &ZZ_p(2));

	/*
	int k = 4;
	int n = 10;
	String^ secret = "1234";

	Shamir^ secretshare = gcnew Shamir();
	List<IShareCollection^>^ shares = secretshare->DivideSecret(k, n, secret);

	for (int i = 0; i < shares->Count; i++)
	{
		IShareCollection^ col = shares[i];
		Console::WriteLine(col->ToString());
		for (int j = 0; j < col->GetCount(); j++)
		{
			IShare^ share = col->GetShare(j);
			Console::WriteLine(share->ToString());
		}
	}

	List<IShareCollection^>^ frecshares = shares->GetRange(0, k - 1);
	String^ frecoveredSecret = secretshare ->ReconstructSecret(frecshares);
	Console::WriteLine("recovered secret with k-1 shares:{0} secret:{1}", frecshares->Count, frecoveredSecret);

	List<IShareCollection^>^ recshares = shares->GetRange(0, k);
	String^ recoveredSecret = secretshare->ReconstructSecret(recshares);
	Console::WriteLine("recovered secret with k shares:{0} secret:{1}", recshares->Count, recoveredSecret);*/

	/*
	int a1 = 166;
	int a2 = 94;

	int p = 1613;

	ZZ_p::init(ZZ(p));

	ZZ_pX f;
	f.SetLength( k-1);
	SetCoeff(f, 0, ZZ_p(secret));
	SetCoeff(f, 1, ZZ_p(a1));
	SetCoeff(f, 2, ZZ_p(a2));

	cout << f;

	ZZ_p d1 = eval(f, ZZ_p(1));
	ZZ_p d2 = eval(f, ZZ_p(2));
	ZZ_p d3 = eval(f, ZZ_p(3));
	ZZ_p d4 = eval(f, ZZ_p(4));
	ZZ_p d5 = eval(f, ZZ_p(5));
	ZZ_p d6 = eval(f, ZZ_p(6));

	cout << '\n' << d1 << '\n' << d2 << '\n' << d3 << '\n' << d4 << '\n' << d5 << '\n' << d6;

	Vec<ZZ_p> x = vec_ZZ_p();
	for (int i = 1; i < 4; i++)
	{
		x.append(ZZ_p(i));
	}

	Vec<ZZ_p> y = vec_ZZ_p();
	y.append(d1);
	y.append(d2);
	y.append(d3);
	ZZ_pX interpolatedf = interpolate(x, y);
	cout << "secret is:" << eval(interpolatedf, ZZ_p(0));

	/*ZZ p;
	GenPrime(p, 10);
	long val = RandomPrime_long(8);
	cout << p << "/n";
	cout << val;
	cin >> p;
	ZZ_p::init(p);

	ZZ_pX f;
	cin >> f;

	Vec< Pair< ZZ_pX, long > > factors;

	CanZass(factors, f);  // calls "Cantor/Zassenhaus" algorithm

	cout << factors << "\n";
	*/	//_CrtDumpMemoryLeaks();
}


// solving A * X = B
// using driver function gesv()

#include <cstddef>
#include <iostream>
#include <vector>
#include <boost/numeric/bindings/lapack/gesv.hpp>
#include <boost/numeric/bindings/traits/ublas_matrix.hpp>
#include <boost/numeric/bindings/traits/std_vector.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
#include "utils.h"

namespace ublas = boost::numeric::ublas;
namespace lapack = boost::numeric::bindings::lapack;

using std::size_t;
using std::cout;
using std::endl;

typedef ublas::matrix<double, ublas::column_major> m_t;

int main() {

  cout << endl;

  size_t n = 5;
  m_t a (n, n);   // system matrix

  size_t nrhs = 2;
  m_t x (n, nrhs), b (n, nrhs);  // b -- right-hand side matrix

  init_symm (a);
  //     [n   n-1 n-2  ... 1]
  //     [n-1 n   n-1  ... 2]
  // a = [n-2 n-1 n    ... 3]
  //     [        ...       ]
  //     [1   2   ...  n-1 n]

  m_t aa (a); // copy of a, because a is `lost' after gesv()

  ublas::matrix_column<m_t> xc0 (x, 0), xc1 (x, 1);
  for (int i = 0; i < xc0.size(); ++i) {
    xc0 (i) = 1.;
    xc1 (i) = 2.;
  }
  b = prod (a, x);

  print_m (a, "A");
  cout << endl;
  print_m (b, "B");
  cout << endl;

  lapack::gesv (a, b);  // solving the system, b contains x

  print_m (b, "X");
  cout << endl;

  x = prod (aa, b);
  print_m (x, "B = A X");

  cout << endl;

}


/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2020 Klaus Spanderen

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file momentbasedgaussianpolynomial.hpp
    \brief Gaussian quadrature defined by the moments of the distribution
*/

#ifndef quantlib_moment_based_gaussian_polynomial_hpp
#define quantlib_moment_based_gaussian_polynomial_hpp

#include <ql/math/comparison.hpp>
#include <ql/math/integrals/gaussianorthogonalpolynomial.hpp>
#include <ql/errors.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <vector>

namespace QuantLib {
    /*! References:
        Gauss quadratures and orthogonal polynomials

        G.H. Gloub and J.H. Welsch: Calculation of Gauss quadrature rule.
        Math. Comput. 23 (1986), 221-230,
        http://web.stanford.edu/class/cme335/spr11/S0025-5718-69-99647-1.pdf

        M. Morandi Cecchi and M. Redivo Zaglia, Computing the coefficients
        of a recurrence formula for numerical integration by moments and
        modified moments.
        http://ac.els-cdn.com/0377042793901522/1-s2.0-0377042793901522-main.pdf?_tid=643d5dca-a05d-11e6-9a56-00000aab0f27&acdnat=1478023545_cf7c87cba4cc9e37a136e68a2564d411
    */

    template <class mp_real>
    class MomentBasedGaussianPolynomial
            : public GaussianOrthogonalPolynomial {
      public:
        MomentBasedGaussianPolynomial();

        Real mu_0() const;
        Real alpha(Size i) const;
        Real beta(Size i) const;

        virtual mp_real moment(Size i) const = 0;

      private:
        mp_real alpha_(Size i) const;
        mp_real beta_(Size i) const;

        mp_real z(Integer k, Integer i) const;

        mutable std::vector<mp_real> b_, c_;
        mutable std::vector<std::vector<mp_real> > z_;
    };

    template <class mp_real> inline
    MomentBasedGaussianPolynomial<mp_real>::MomentBasedGaussianPolynomial()
    : z_(1, std::vector<mp_real>()) {}

    template <class mp_real> inline
    mp_real MomentBasedGaussianPolynomial<mp_real>::z(Integer k, Integer i) const {
        if (k == -1) return mp_real(0.0);

        const Integer rows = z_.size();
        const Integer cols = z_[0].size();

        if (cols <= i) {
            for (Integer l=0; l<rows; ++l)
                z_[l].resize(i+1, std::numeric_limits<mp_real>::quiet_NaN());
        }
        if (rows <= k) {
            z_.resize(k+1, std::vector<mp_real>(
                z_[0].size(), std::numeric_limits<mp_real>::quiet_NaN()));
        }

        if (boost::math::isnan(z_[k][i])) {
            if (k == 0)
                z_[k][i] = moment(i);
            else {
                const mp_real tmp = z(k-1, i+1)
                    - alpha_(k-1)*z(k-1, i) - beta_(k-1)*z(k-2, i);
                z_[k][i] = tmp;
            }
        }

        return z_[k][i];
    };

    template <class mp_real> inline
    mp_real MomentBasedGaussianPolynomial<mp_real>::alpha_(Size u) const {

        if (b_.size() <= u)
            b_.resize(u+1, std::numeric_limits<mp_real>::quiet_NaN());

        if (boost::math::isnan(b_[u])) {
            if (u == 0)
                b_[u] = moment(1);
            else {
                const Integer iu(u);
                const mp_real tmp =
                    -z(iu-1, iu)/z(iu-1, iu-1) + z(iu, iu+1)/z(iu, iu);
                b_[u] = tmp;
            }
        }
        return b_[u];
    }

    template <class mp_real> inline
    mp_real MomentBasedGaussianPolynomial<mp_real>::beta_(Size u) const {
        if (u == 0)
            return mp_real(1.0);

        if (c_.size() <= u)
            c_.resize(u+1, std::numeric_limits<mp_real>::quiet_NaN());

        if (boost::math::isnan(c_[u])) {
            const Integer iu(u);
            const mp_real tmp = z(iu, iu) / z(iu-1, iu-1);
            c_[u] = tmp;
        }
        return c_[u];
    }

    template <> inline
    Real MomentBasedGaussianPolynomial<Real>::alpha(Size u) const {
        return alpha_(u);
    }

    template <class mp_real> inline
    Real MomentBasedGaussianPolynomial<mp_real>::alpha(Size u) const {
        return alpha_(u).template convert_to<Real>();
    }

    template <> inline
    Real MomentBasedGaussianPolynomial<Real>::beta(Size u) const {
        return beta_(u);
    }

    template <class mp_real> inline
    Real MomentBasedGaussianPolynomial<mp_real>::beta(Size u) const {
        mp_real b = beta_(u);
        return b.template convert_to<Real>();
    }

    template <> inline
    Real MomentBasedGaussianPolynomial<Real>::mu_0() const {
        const Real m0 = moment(0);
        QL_REQUIRE(close_enough(m0, 1.0), "zero moment must by one.");

        return moment(0);
    }

    template <class mp_real> inline
    Real MomentBasedGaussianPolynomial<mp_real>::mu_0() const {
        return moment(0).template convert_to<Real>();
    }
}

#endif


#include <SOperations.h>
#include <assert.h>                  // for assert
#include <algorithm>                 // for min
#include <boost/core/enable_if.hpp>  // for enable_if_c<>::type
#include <stdexcept>                 // for out_of_range

using namespace boost ;

//https://stackoverflow.com/questions/35971827/c-boost-rational-class-floor-function
namespace boost {
    template <typename IntType>
    constexpr IntType floor(rational<IntType> const &num) {
        return static_cast<IntType>(num.numerator() / num.denominator());
    }
    template <typename IntType>
    constexpr IntType ceil(rational<IntType> const &num) {
        auto inum = static_cast<IntType>(num.numerator() / num.denominator());
        return (num == inum) ? inum : ((num.numerator() > 0) ? ++ inum : --inum) ;
    }
}

/*
for i in range(0,10):
     if floor(i*delta)==floor((i+1)*delta):
         print B[i-int(floor((i+1)*delta))],
     else:
         print A[int(floor(i*delta))],

deltaC = (deltaA*deltaB)/(deltaA+deltaB)
*/

rational<int> deltaHash(const rational<int> &arg1, const rational<int> &arg2) {
    assert(arg1 + arg2 != 0);
    return (arg1 * arg2) / (arg1 + arg2);
}

bool Hash(const rational<int> &deltaA, const rational<int> &deltaB, const int i, int &retPos) {
    assert(deltaA > 0);
    assert(deltaB > 0);
    const rational<int> delta = deltaB / (deltaA + deltaB) ;
    bool ret = floor(delta * i) == floor(delta * (i + 1));

    if (ret) {
        retPos = i - (floor((i + 1) * delta));        //B
    } else {
        retPos = floor(i * delta);    //A
    }

    return ret ;
}

/*
#hash - begin
delta=deltaB/(deltaA+deltaB)

for i in range(0,24):
    if int(i*delta)==int((i+1)*delta):
        C.append( B[i-int((i+1)*delta)] )
    else:
        C.append( A[int(i*delta)] )
#hash - end

#div - begin
deltaC=(deltaA*deltaB)/(deltaA+deltaB)

deltaA_ = deltaB*deltaC/(deltaB-deltaC)
assert(deltaA_ == deltaA)
from math import ceil
for i in range(0,5) :
    print C[i+int(ceil((i+1)*deltaA/deltaB))],    <--- tu jest to div
#Output: 1 2 3 4 5

#div- end
*/

int Div(const boost::rational<int> &deltaA, const boost::rational<int> &deltaB, const int i) {
    return i + ceil((i + 1) * deltaA / deltaB);
}

/*
#hash - begin
delta=deltaB/(deltaA+deltaB)

for i in range(0,24):
    if int(i*delta)==int((i+1)*delta):
        C.append( B[i-int((i+1)*delta)] )
    else:
        C.append( A[int(i*delta)] )

#hash - end

#mod - begin
deltaC=(deltaA*deltaB)/(deltaA+deltaB)

deltaB_ = deltaA*deltaC/(deltaA-deltaC)
assert(deltaB_ == deltaB)
for i in range(0,10) :
    print C[i+int(i*deltaB/deltaA)],                <--- tu jest mod
#Output: a b c d e f g h i j#

#mod - end
*/

int Mod(const boost::rational<int> &deltaA, const boost::rational<int> &deltaB, const int i) {
    return i + floor(i * deltaB / deltaA);
}

/* Ta funkcja jest taka sama dla obu operacji */

rational<int> deltaDivMod(const rational<int> &arg1, const rational<int> &arg2) {
    assert(arg1 != arg2);

    if (arg1 == arg2) {
        throw std::out_of_range("Delta are equal in DehashDiv - undefinied.");
    }

    return (arg1 * arg2) / abs(arg1 - arg2);
}

/*
from math import ceil
for i in range(0,10):
    if deltaA > deltaB :
        print C[int(ceil(i*deltaA/deltaB))][0],
    else:
        print C[i][0],
*/

rational<int> deltaSubstract(const rational<int> &arg1) {
    return arg1 ;
}
//todo
int Substract(const rational<int> &deltaA, const rational<int> &deltaB, const int i) {
    return ceil(i * deltaA / deltaB);
}

rational<int> deltaAdd(const rational<int> &arg1, const rational<int> &arg2) {
    return std::min(arg1, arg2) ;
}

/*
deltaC = min( deltaA,deltaB )
for i in range(0,10):
     if deltaC == deltaA:
         print str(A[i])+B[int(i*deltaA/deltaB)],
     else:
         print str(A[int(i*deltaB/deltaA)])+B[i],
*/

rational<int> deltaTimemove(const rational<int> &arg1, const rational<int> &arg2) {
    return arg1 ;
}

int agse(int offset, int step) {
    return floor(boost::rational<int> (offset) / boost::rational<int> (step));
}

void SOperations_regtest() {
    boost::rational<int> a(1, 2) ;
    boost::rational<int> b(1, 3) ;
    boost::rational<int> c(2, 3) ;
    boost::rational<int> d(5, 4) ;
    boost::rational<int> e(1) ;
    boost::rational<int> f(0) ;
    boost::rational<int> g(-2, 3);
    boost::rational<int> h(-1);
    boost::rational<int> j(-5, 4);
    assert(floor(a) == 0);
    assert(floor(b) == 0);
    assert(floor(c) == 0);
    assert(floor(d) == 1);
    assert(floor(e) == 1);
    assert(floor(f) == 0);
    assert(floor(g) == 0);
    assert(floor(h) == -1);
    assert(floor(j) == -1);
    assert(ceil(a) == 1);
    assert(ceil(b) == 1);
    assert(ceil(c) == 1);
    assert(ceil(d) == 2);
    assert(ceil(e) == 1);
    assert(ceil(f) == 0);
    assert(ceil(g) == -1);
    assert(ceil(h) == -1);
    assert(ceil(j) == -2);
}


/**
 * @file getBoundingBox.cpp
 */
#include <pcl/common/centroid.h>
#include <pcl/point_types.h>
#include <pcl/common/common.h>
#include <pcl/common/transforms.h>
#include <Eigen/Eigenvalues>
#include <pcl/visualization/pcl_visualizer.h>

#include "getBoundingBox.h"

/**
 * @function getBoundingBox
 * @brief Shows a visualizer with the bounding box and prints out its dimensions
 */
template<typename PointType>
void getBoundingBox( const boost::shared_ptr< pcl::PointCloud<PointType> > &_input  ) {

  // Compute principal direction
  Eigen::Vector4f centroid;
  pcl::compute3DCentroid( *_input, centroid );

  Eigen::Matrix3f covariance;
  pcl::computeCovarianceMatrixNormalized( *_input,
					  centroid,
					  covariance);
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigenSolver( covariance,
							      Eigen::ComputeEigenvectors);
  Eigen::Matrix3f eigDx = eigenSolver.eigenvectors();
  eigDx.col(2) = eigDx.col(0).cross( eigDx.col(1));

  // Move the points to that reference frame
  Eigen::Matrix4f p2w( Eigen::Matrix4f::Identity() );

  // [Rt, -Rt*T]
  p2w.block<3,3>(0,0) = eigDx.transpose();
  p2w.block<3,1>(0,3) = -1.0*( p2w.block<3,3>(0,0) )*(centroid.head<3>());
  pcl::PointCloud<pcl::PointXYZ> input_p;
  pcl::transformPointCloud( *_input, input_p, p2w );

  //-- Get max and min
  pcl::PointXYZ minP, maxP;
  pcl::getMinMax3D( input_p, minP, maxP );
  const Eigen::Vector3f meanDiag( 0.5*(minP.x + maxP.x),
				  0.5*(minP.y + maxP.y),
				  0.5*(minP.z + maxP.z));

  //-- Final transform
  const Eigen::Quaternionf qfinal( eigDx );
  const Eigen::Vector3f tfFinal = eigDx*meanDiag + centroid.head<3>();

  //-- Box Dimensions
  double bx = maxP.x - minP.x;
  double by = maxP.y - minP.y;
  double bz = maxP.z - minP.z;

  //-- Center of 6 box's faces
  Eigen::VectorXf bc[6];
  bc[0] = tfFinal + eigDx.col(0)*bx / 2.0;
  bc[1] = tfFinal - eigDx.col(0)*bx / 2.0;
  bc[2] = tfFinal + eigDx.col(1)*by / 2.0;
  bc[3] = tfFinal - eigDx.col(1)*by / 2.0;
  bc[4] = tfFinal + eigDx.col(2)*bz / 2.0;
  bc[5] = tfFinal - eigDx.col(2)*bz / 2.0;

  //-- Print info
  std::cout << " * Centroid: "<< centroid.head(3).transpose() << std::endl;
  std::cout << " * Dimensions: "<<bx<< ", "<<by<<", "<<bz<< std::endl;

  //-- Show visualizer

  pcl::visualization::PCLVisualizer viewer;
  viewer.addPointCloud( _input );
  viewer.addCube( tfFinal, qfinal, bx, by, bz );

  // Add center of box faces
  for( int i = 0; i < 6; ++i ) {
      pcl::PointXYZ p;
      p.x = bc[i](0); p.y = bc[i](1); p.z = bc[i](2);
      char name[30];
      sprintf( name, "sphere%d", i );
      viewer.addSphere( p, 0.02, 1.0, 0.0, 0.0, name );
  }

  //viewer.addCoordinateSystem(1.0);
  viewer.spin();

  return;
}


#ifndef USE_CUDA

#include <kernel_vectormath.hpp>
#include <Eigen/Dense>

// C++ Version
namespace Kernel
{
    // sets vf := v
    // vf is a vectorfield
    // v is a vector
    void fill(vectorfield & vf, const Vector3 & v)
    {
        for (unsigned int i=0; i<vf.size(); ++i)
        {
            vf[i] = v;
        }
    }

    void scale(vectorfield & vf, const scalar & sc)
    {
        for (unsigned int i=0; i<vf.size(); ++i)
        {
            vf[i] *= sc;
        }
    }

	// computes the inner product of two vectorfields v1 and v2
	scalar dot(const vectorfield & v1, const vectorfield & v2)
	{
		scalar x = 0;
		for (unsigned int i = 0; i<v1.size(); ++i)
		{
			x += v1[i].dot(v2[i]);
		}
		return x;
	}

    // computes the inner products of vectors in v1 and v2
    // v1 and v2 are vectorfields
    void dot(const vectorfield & v1, const vectorfield & v2, scalarfield & out)
    {
        for (unsigned int i=0; i<v1.size(); ++i)
        {
			out[i] = v1[i].dot(v2[i]);
        }
    }

    // computes the vector (cross) products of vectors in v1 and v2
    // v1 and v2 are vector fields
    void cross(const vectorfield & v1, const vectorfield & v2, vectorfield & out)
    {
        for (unsigned int i=0; i<v1.size(); ++i)
        {
            out[i] = v1[i].cross(v2[i]);
        }
    }

    // out[i] += c*a
    void add_c_a(const scalar & c, const Vector3 & a, vectorfield & out)
    {
        for(unsigned int idx = 0; idx < out.size(); ++idx)
        {
            out[idx] += c*a;
        }
    }

    // out[i] += c*a[i]
    void add_c_a(const scalar & c, const vectorfield & a, vectorfield & out)
    {
        for(unsigned int idx = 0; idx < out.size(); ++idx)
        {
            out[idx] += c*a[idx];
        }
    }

    // out[i] += c * a*b[i]
    void add_c_dot(const scalar & c, const Vector3 & a, const vectorfield & b, scalarfield & out)
    {
        for(unsigned int idx = 0; idx < out.size(); ++idx)
        {
            out[idx] += c*a.dot(b[idx]);
        }
    }

    // out[i] += c * a[i]*b[i]
    void add_c_dot(const scalar & c, const vectorfield & a, const vectorfield & b, scalarfield & out)
    {
        for(unsigned int idx = 0; idx < out.size(); ++idx)
        {
            out[idx] += c*a[idx].dot(b[idx]);
        }
    }

    // out[i] += c * a x b[i]
    void add_c_cross(const scalar & c, const Vector3 & a, const vectorfield & b, vectorfield & out)
    {
        for(unsigned int idx = 0; idx < out.size(); ++idx)
        {
            out[idx] += c*a.cross(b[idx]);
        }
    }

    // out[i] += c * a[i] x b[i]
    void add_c_cross(const scalar & c, const vectorfield & a, const vectorfield & b, vectorfield & out)
    {
        for(unsigned int idx = 0; idx < out.size(); ++idx)
        {
            out[idx] += c*a[idx].cross(b[idx]);
        }
    }

}

#endif


#include <iostream>
#include <Eigen/Dense>
#include "matplotlibcpp.h"
#include <boost/numeric/odeint.hpp>

using namespace boost::numeric::odeint;

// Define a abbreviation for state type
typedef std::vector< double > state_type;

namespace plt = matplotlibcpp;

const double sigma = 10.0;
const double R = 28.0;
const double b = 8.0 / 3.0;

// the system function can be a classical functions
void lorenz( state_type &x , state_type &dxdt , double t )
{
    dxdt[0] = sigma * ( x[1] - x[0] );
    dxdt[1] = R * x[0] - x[1] - x[0] * x[2];
    dxdt[2] = x[0]*x[1] - b * x[2];
}

int main(int argc, char const *argv[])
{
    state_type x( 3 );
    x[0] = x[1] = x[2] = 10.0;
    const double dt = 0.01;
    integrate_const( runge_kutta4< state_type >() , lorenz , x , 0.0 , 10.0 , dt );

    return 0;
}


#include <iostream>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

int main()
{
	Matrix3f A;
	A << 1, 2, 1,
	    2, 1, 0,
	    -1, 1, 2;
	cout << A << endl;
	cout << A * A * A * A * A * A * A << endl;
	cout << A.inverse() << endl;
	cout << A.determinant() << endl;

	MatrixXf B = MatrixXf::Random(5, 3);
	cout << B << endl;

	return 0;
}


#include <iostream>
#include <boost/numeric/mtl/mtl.hpp>

int main(int, char**)
{
    typedef mtl::dense2D<double>       Matrix;
    typedef mtl::dense_vector<double>  Vector;

    Matrix                             A(4, 4), L(4, 4), U(4, 4), AA(4, 4);
    Vector	       		       v(4);
    double 			       c=1.0;

    for (unsigned i= 0; i < 4; i++)
	for(unsigned j= 0; j < 4; j++) {
	    U[i][j]= i <= j ? c * (i+j+2) : (0);
	    L[i][j]= i > j ? c * (i+j+1) : (i == j ? (1) : (0));
	}

    std::cout << "L is:\n" << L << "U is:\n" << U;
    A= L * U;
    std::cout << "A is:\n" << A;
    AA= adjoint(A);

    for (unsigned i= 0; i < 4; i++)
	v[i]= double(i);

    Vector b( A*v ), b2( adjoint(A)*v );

    Matrix LU(A);
    lu(LU);
    std::cout << "LU decomposition of A is:\n" << LU;

    Matrix B( lu_f(A) );
    std::cout << "LU decomposition of A (as function result) is:\n" << B;

    Vector v1( lu_solve_straight(A, b) );
    std::cout << "v1 is " << v1 << "\n";

    Vector v2( lu_solve(A, b) );
    std::cout << "v2 is " << v2 << "\n";

    mtl::dense_vector<unsigned> P;
    lu(A, P);
    std::cout << "LU with pivoting is \n" << with_format(A, 5, 2) << "Permutation is " << P << "\n";
    Vector v3( lu_apply(A, P, b) );
    std::cout << "v3 is " << v3 << "\n";

    Vector v4(lu_adjoint_apply(A, P, b2));
    std::cout << "v4 is " << v4 << "\n";

    Vector v5(lu_adjoint_solve(AA, b));
    std::cout << "v5 is " << v5 << "\n";

    return 0;
}


//
// Created by senbaikang on 21.05.21.
//

#include <cmath>
#include <config.h>

#include <boost/math/special_functions/digamma.hpp>

#include "probabilities.h"

double logBetaBinCountsTerm(
    double sup,
    double cov
    )
{
  return std::lgamma(cov + 1.0) -  std::lgamma(sup + 1.0) - std::lgamma(cov - sup + 1.0);
}

double logBetaBinMixedTerm(
    double sup,
    double cov,
    double mean,
    double overDis
    )
{
  return std::lgamma(sup + mean * overDis) + std::lgamma(cov - sup + overDis * (1.0 - mean)) - std::lgamma(cov + overDis);
}

double logBetaBinParamsTerm(
    double mean,
    double overDis
    )
{
  return std::lgamma(overDis) - std::lgamma(mean * overDis) - std::lgamma(overDis * (1.0 - mean));
}

double logBetaBinPDF(
    double sup,
    double cov,
    double mean,
    double overDis
)
{
  if (cov == 0)
    return 0;

  return logBetaBinCountsTerm(sup, cov) +
         logBetaBinMixedTerm(sup, cov, mean, overDis) +
         logBetaBinParamsTerm(mean, overDis);
}

double computeRawWildLogScore(
    Config const &config,
    double altCount,
    double coverage
    )
{
  return logBetaBinPDF(
      altCount,
      coverage,
      config.getEffectiveSeqErrRate() / 3.0,
      config.getWildOverdispersion()
      );
//  return logBetaBinPDF(
//      altCount,
//      coverage,
//      config.getEffectiveSeqErrRate(),
//      config.getWildOverdispersion()
//  );
}

double computeRawHeteroMutLogScore(
    Config const &config,
    double altCount,
    double coverage
    )
{
  return logBetaBinPDF(
      altCount,
      coverage,
      0.5 - config.getEffectiveSeqErrRate() / 3.0,
      config.getMuOverdispersion()
      );
//  return logBetaBinPDF(
//      altCount,
//      coverage,
//      0.5 - (2.0 / 3.0 * config.getEffectiveSeqErrRate()),
//      config.getMuOverdispersion()
//  );
}

double computeRawHomoMutLogScore(
    Config const &config,
    double covMinusSup,
    double coverage
    )
{
  return logBetaBinPDF(
      covMinusSup,
      coverage,
      config.getEffectiveSeqErrRate(),
      config.getWildOverdispersion()
      );
}

// Add two values in real space by first exponentiating
double addLogProb(double x, double y)
{
  double maxScore;
  double minScore;

  if (x > y)
  {
    maxScore = x;
    minScore = y;
  }
  else
  {
    maxScore = y;
    minScore = x;
  }

  return std::log(1.0 + std::exp(minScore - maxScore)) + maxScore;
}

double logNChoose2(u_int32_t numMut)
{
  return log(static_cast<double>(numMut)) + log((static_cast<double>(numMut) - 1.0) / 2.0);
}

double logNChooseK(u_int32_t n, u_int32_t k, double logNChoosekMinusOne)
{
  if (k == 0)
    return 0;

  return logNChoosekMinusOne + log(static_cast<double>(n + 1 - k) / static_cast<double>(k));
}

double logNChooseK(u_int32_t n, u_int32_t k)
{
  if (k == 0)
    return 0;

  return std::lgamma(n + 1) - std::lgamma(k + 1) - std::lgamma(n - k + 1);
}

OptimizeBetaBinMeanOverDis::OptimizeBetaBinMeanOverDis(
    const std::vector<std::pair<u_int32_t, u_int32_t>> &counts
    ):
        counts(counts)
{}

double OptimizeBetaBinMeanOverDis::operator()(const dlib::matrix<double,0,1> &x) const
{
  double result = 0;
  for (const auto & count : this->counts)
    result += logBetaBinPDF(count.first, count.second, x(0), x(1));

  return result;
}

OptimizeBetaBinMeanOverDisDerivates::OptimizeBetaBinMeanOverDisDerivates(
    const std::vector<std::pair<u_int32_t , u_int32_t>> &counts
    ):
    counts(counts)
{}

dlib::matrix<double> OptimizeBetaBinMeanOverDisDerivates::operator()(const dlib::matrix<double,0,1> &x) const
{
  double mean = x(0);
  double overDis = x(1);
  dlib::matrix<double,0,1> res = {0,0};

  double temp = 0;
  unsigned counter = 0;
  for (const auto & count : this->counts)
  {
    unsigned k = count.first;
    unsigned n = count.second;
    temp += overDis *  boost::math::digamma(k + mean * overDis)
            - overDis *  boost::math::digamma(n - k + overDis - overDis * mean);
    ++counter;
  }
  res(0) = counter * (-overDis *  boost::math::digamma(mean * overDis) + overDis *  boost::math::digamma(overDis - overDis * mean)) + temp;

  temp = 0;
  for (const auto & count : this->counts)
  {
    unsigned k = count.first;
    unsigned n = count.second;
    temp += mean * boost::math::digamma(k + mean * overDis) +
            (1.0 - mean) * boost::math::digamma(n - k + overDis - overDis * mean) -
            boost::math::digamma(n + overDis);
  }
  res(1) = counter * (boost::math::digamma(overDis) - mean * boost::math::digamma(mean * overDis) - (1.0 - mean) * boost::math::digamma(overDis - overDis * mean)) + temp;

  return res;
}

OptimizeBetaBinOverDis::OptimizeBetaBinOverDis(
    const std::vector<std::pair<u_int32_t, u_int32_t>> &counts,
    double meanFilter
):
    counts(counts),
    meanFilter(meanFilter)
{}

double OptimizeBetaBinOverDis::operator()(const dlib::matrix<double,0,1> &x) const
{
  double result = 0;
  for (const auto & count : this->counts)
    result += logBetaBinPDF(count.first, count.second, meanFilter, x(0));

  return result;
}

OptimizeBetaBinOverDisDerivates::OptimizeBetaBinOverDisDerivates(
    const std::vector<std::pair<u_int32_t, u_int32_t>> &counts,
    double meanFilter
    ):
    counts(counts),
    meanFilter(meanFilter)
{}

dlib::matrix<double> OptimizeBetaBinOverDisDerivates::operator()(const dlib::matrix<double,0,1> &x) const
{
  double mean = this->meanFilter;
  double overDis = x(0);
  dlib::matrix<double,0,1> res = {0};

  double temp = 0;
  u_int32_t counter = 0;
  for (const auto & count : this->counts)
  {
    unsigned k = count.first;
    unsigned n = count.second;
    temp += mean * boost::math::digamma(k + mean * overDis) +
            (1.0 - mean) * boost::math::digamma(n - k + overDis - overDis * mean) -
            boost::math::digamma(n + overDis);
    ++counter;
  }
  res(0) = counter * (boost::math::digamma(overDis) - mean * boost::math::digamma(mean * overDis) - (1.0 - mean) * boost::math::digamma(overDis - overDis * mean)) + temp;

  return res;
}


#include <vector>

#include "caffe/util/math_functions.hpp"
#include "caffe/util/calculate_SVD.hpp"
#include <Eigen/SVD>
using namespace Eigen;

namespace caffe {

template <typename Dtype>
void CalculateSVD(const Dtype* weight,
    Dtype* weight_mut, int num_neurons, int dim_features, int k_value) {

  //FM: SVD
  //const Dtype* weight = this->blobs_[0]->cpu_data();
  //Dtype* weight_mut = this->blobs_[0]->mutable_cpu_data();

  //Instantiate the weight matrix
  MatrixXf m = MatrixXf::Random(num_neurons, dim_features);
  int counter = 0;
  for (int i = 0; i < num_neurons; ++i) {
	  for (int j = 0; j < dim_features; ++j) {
		  m(i, j) = weight[counter];
		  counter++;
	  }

  }

  //Perform SVD
  // cout << "Here is the matrix m:" << endl << m << endl;
  JacobiSVD<MatrixXf> svd(m, ComputeThinU | ComputeThinV);

  // Set with the new values
  counter = 0;
  //MatrixXf m_inner = svd.matrixU() * (svd.singularValues().asDiagonal() * svd.matrixV().transpose()); //original
  int u_rows = svd.matrixU().rows();
  int v_rows = svd.matrixV().rows();
  int s_cols = svd.singularValues().cols();
  //MatrixXf m_inner = svd.matrixU().block<u_rows, k>(0, 0) * (svd.singularValues().asDiagonal() * svd.matrixV().transpose()); //low-rank decomposition
  MatrixXf m_inner = svd.matrixU().block(0, 0, u_rows, k_value) * (svd.singularValues().block(0, 0, k_value, s_cols).asDiagonal() * svd.matrixV().block(0, 0, v_rows, k_value).transpose()); //low-rank decomposition

  #ifdef _DEBUG
	  MatrixXf diff = m_inner - m;
	  cout << "diff:\n" << diff.array().abs().sum() << "\n";
  #endif

  for (int i = 0; i < num_neurons; ++i) {
	  for (int j = 0; j < dim_features; ++j) {
		  weight_mut[counter] = m_inner(i, j);
		  counter++;
	  }

  }
  // FM: End of SVD
}

template void CalculateSVD<float>(const float* weight, float* weight_mut, int num_neurons, int dim_features, int k_value);
template void CalculateSVD<double>(const double* weight, double* weight_mut, int num_neurons, int dim_features, int k_value);

}  // namespace caffe


/*
 * Copyright (C) 2016-2019 Istituto Italiano di Tecnologia (IIT)
 *
 * This software may be modified and distributed under the terms of the
 * BSD 3-Clause license. See the accompanying LICENSE file for details.
 */

#include <BayesFilters/LTIStateModel.h>

#include <Eigen/Dense>

using namespace bfl;
using namespace Eigen;

LTIStateModel::LTIStateModel(const Ref<const MatrixXd>& transition_matrix, const Ref<const MatrixXd>& noise_covariance_matrix) :
    F_(transition_matrix), Q_(noise_covariance_matrix)
{
    if ((F_.rows() == 0) || (F_.cols() == 0))
        throw std::runtime_error("ERROR::LTISTATEMODEL::CTOR\nERROR:\n\tState transition matrix dimensions cannot be 0.");
    else if ((Q_.rows() == 0) || (Q_.cols() == 0))
        throw std::runtime_error("ERROR::LTISTATEMODEL::CTOR\nERROR:\n\tNoise covariance matrix dimensions cannot be 0.");
    else if (F_.rows() != F_.cols())
        throw std::runtime_error("ERROR::LTISTATEMODEL::CTOR\nERROR:\n\tState transition matrix must be a square matrix.");
    else if (Q_.rows() != Q_.cols())
        throw std::runtime_error("ERROR::LTISTATEMODEL::CTOR\nERROR:\n\tNoise covariance matrix must be a square matrix.");
    else if (F_.rows() != Q_.rows())
        throw std::runtime_error("ERROR::LTISTATEMODEL::CTOR\nERROR:\n\tNumber of rows of the state transition matrix must be the same as the size of the noise covariance matrix.");
}

void LTIStateModel::propagate(const Eigen::Ref<const Eigen::MatrixXd>& cur_states, Eigen::Ref<Eigen::MatrixXd> prop_states)
{
    prop_states = F_ * cur_states;
}

Eigen::MatrixXd LTIStateModel::getNoiseCovarianceMatrix()
{
    return Q_;
}

Eigen::MatrixXd LTIStateModel::getStateTransitionMatrix()
{
    return F_;
}

bool LTIStateModel::setProperty(const std::string& property)
{
    return false;
}

Eigen::MatrixXd LTIStateModel::getJacobian()
{
    return F_;
}


/*
 * Refs:
 * https://eigen.tuxfamily.org/dox/index.html
 * https://dritchie.github.io/csci2240/assignments/eigen_tutorial.pdf
 * */

#include <iostream>
#include <Eigen/Dense>

#define PRINT(x) std::cout << #x << ": " << std::endl << (x) << std::endl << std::endl
#define PRINT_SIZE(x) std::cout << #x << " is of size " << x.rows() << "x" << x.cols() << std::endl << std::endl
#define SECTION(x) std::cout << "======================== " << x << " =======================" << std::endl << std::endl

int main() {

  using namespace Eigen;

  SECTION("Initialisations");
  // Different ways to initialise matrix
  Matrix<double , Dynamic, Dynamic, 0, 6, 8> m0 = Matrix4d::Ones();
  // the last three are optional, so we don't have to worry about it most of the time.
  // isRowMajor=0: default is column major, MaxRowsAtCompileTime, MaxColsAtCompileTime
  PRINT(m0);
  MatrixXd m1(4, 4); // typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
  m1 = Matrix4d::Zero();
  PRINT(m1);
  // fix size matrix
  Matrix4d m2 = Matrix4d::Random(); // [-1, 1]
  PRINT(m2);
  Vector4d m3(1.0, 2.0, 3.0, 4.0); // typedef Matrix<double, 4, 1> Vector3d;
  PRINT(m3);
  MatrixXd v = Vector4d::Ones(); // vectors just one dimensional matrices
  PRINT(v);
  VectorXd m4 = Vector4d::Constant(108.5); // column vector
  PRINT(m4);
  RowVectorXd m4r = Vector4d::Constant(108.5); // row vector
  PRINT(m4r);

  SECTION("Store orders");
  // store orders
  // https://eigen.tuxfamily.org/dox/group__TopicStorageOrders.html
  Matrix<double, 4, 4, RowMajor> m5;
  m5 << 1, 2, 3, 4,  5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16; // comma-initializer syntax
  PRINT(m5);
  std::cout << "In memory (row-major):" << std::endl;
  for (int i = 0; i < m5.size(); i++)
    std::cout << *(m5.data() + i) << "  ";
  std::cout << std::endl << std::endl;

  Matrix<double, 4, 4, ColMajor> m6;
  m6 << 1, 2, 3, 4,  5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16;
  PRINT(m6);
  std::cout << "In memory (column-major):" << std::endl;
  for (int i = 0; i < m6.size(); i++)
    std::cout << *(m6.data() + i) << "  ";
  std::cout << std::endl << std::endl;

  Matrix<double, 4, 4> m7; // default is Column major
  m7 << 1, 2, 3, 4,  5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16;
  PRINT(m7);
  std::cout << "In memory (column-major) is default:" << std::endl;
  for (int i = 0; i < m7.size(); i++)
    std::cout << *(m7.data() + i) << "  ";
  std::cout << std::endl << std::endl;

  // ref: https://eigen.tuxfamily.org/dox/group__TutorialAdvancedInitialization.html
  MatrixXd m8(4, 8);
  m8 << m6, m7;
  PRINT(m8);

  MatrixXd m9(8, 4);
  m9 << m6, m7;
  PRINT(m9);

  SECTION("Block Operation");
  // block operation https://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html
  MatrixXd m10(5, 9);
  m10.row(0) << RowVectorXd::Ones(9)*100;
  m10.block(1, 0, 4, 4) << m6;
  m10.block<4, 4>(1, 4) = m7*2;
  m10.col(8).tail(4) << VectorXd::Ones(4)*99; // col and row are special case of block
  PRINT(m10);
  // some other keywords:
  // topLeftCorner, bottomLeftCorner, topRightCorner, bottomRightCorner, topRows, bottomRows, leftCols, rightCols.
  PRINT(m5);
  PRINT(m5.leftCols(2));
  PRINT(m5.bottomRows<2>());
  m5.topLeftCorner(1,3) = m5.bottomRightCorner(3,1).transpose();
  PRINT(m5);
  VectorXd v0(6);
  v0 << 1, 2, 3, 4, 5, 6;
  PRINT(v0.head(3));
  PRINT(v0.tail<3>());
  v0.segment(1,4) *= 2;
  PRINT(v0);

  SECTION("Diagonal");
  // Coefficient accessors
  m0(2, 2) = 100;
  PRINT(m0);
  PRINT(m0.diagonal());
  MatrixXd m0d1 = m0.diagonal().asDiagonal();
  // https://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#a14235b62c90f93fe910070b4743782d0
  PRINT(m0d1);
  DiagonalMatrix<double, Dynamic> m0d2;
  // http://eigen.tuxfamily.org/dox/classEigen_1_1DiagonalMatrix.html
  m0d2.diagonal() = m0.diagonal();
  PRINT(MatrixXd(m0d2));

  m1 = Matrix4d::Identity(); // overwrite matrix values
  PRINT(m1);

  SECTION("Vector operations");
  // Vector operations
  Vector3f v1, v2;
  v1 = Vector3f::Random();
  v2 = Vector3f::Random();
  PRINT(v1);
  PRINT(v2);
  PRINT(v1 * v2.transpose());
  PRINT(v1.transpose() * v2);
  PRINT(v1.dot(v2));
  PRINT(v1.cross(Vector3f(3., 4., 6.).normalized()));
  PRINT(v1.cross(v2));

  Vector4f v3 = v1.homogeneous();
  PRINT(v3);
  PRINT(v3.hnormalized());
  // element-wise similar to matrix
  PRINT(v1.array().sin());

  SECTION("Matrix Operations");
  // Matrix Operations
  PRINT(m0 + m1);
  PRINT(m0 * m1);
  PRINT(m1 += m1);
  PRINT(m1 *= 2);
  PRINT(m0 - m1 * 2.2);
  // Check if two matrices are the same
  PRINT(m0 * m1 == m0 - m1 * 2.2);
  PRINT(m1 == Matrix4d::Identity()*4);

  PRINT(m6.transpose()); // this doesn't modify m6
  // NEVER DO "a = a.transpose()" aliasing issue: https://eigen.tuxfamily.org/dox/group__TutorialMatrixArithmetic.html
  // but matrix operation is fine, no problem! a = a*a;
  // https://eigen.tuxfamily.org/dox/group__TopicAliasing.html
  m6.transposeInPlace(); // we can do this instead
  PRINT(m6);
  PRINT(m6.inverse()); // if not invertible then shows NaN

  SECTION("Element-Wise");
  // element-wise
  PRINT(m6.array().square());
  PRINT(m6.array() * m6.transpose().array());
  PRINT(((m0 * m1).array() == (m0 - m1 * 2.2).array()));

  SECTION("Basic arithmetic reduction operations");
  // Basic arithmetic reduction operations
  // https://eigen.tuxfamily.org/dox/group__TutorialMatrixArithmetic.html
  // https://eigen.tuxfamily.org/dox/group__TutorialReductionsVisitorsBroadcasting.html
  PRINT(m1);
  PRINT(m1.sum());
  PRINT(m1.prod());
  PRINT(m1.mean());
  PRINT(m1.minCoeff());
  PRINT(m1.maxCoeff());
  PRINT(m1.trace());
  // visitors
  MatrixXd::Index maxRow, maxCol;
  double maxOfm1 = m1.maxCoeff(&maxRow, &maxCol);
  std::cout << maxOfm1 << " is at position: (" << maxRow << "," << maxCol << ")" << std::endl << std::endl;
  std::ptrdiff_t i, j;
  double minOfm1 = m1.minCoeff(&i, &j);
  std::cout << minOfm1 << " is at position: (" << i << "," << j << ")" << std::endl << std::endl;
  // partial reductions
  PRINT(m1.colwise().maxCoeff());
  PRINT(m1.rowwise().maxCoeff());
  PRINT(m1.cwiseSqrt());
  PRINT(m1.cwiseSqrt().colwise().maxCoeff());

  SECTION("Norm");
  PRINT(m1.squaredNorm());
  PRINT(m1.norm());
  // lp-norm
  PRINT(m1.lpNorm<2>());
  PRINT(m1.lpNorm<1>());
  PRINT(m1.lpNorm<Infinity>());
  // Operator norm: https://en.wikipedia.org/wiki/Operator_norm
  // 1-norm(m1)
  PRINT(m1.cwiseAbs().colwise().sum().maxCoeff());
  PRINT(m1.colwise().lpNorm<1>().maxCoeff());
  // Infinity-norm(m1)
  PRINT(m1.cwiseAbs().rowwise().sum().maxCoeff());
  PRINT(m1.rowwise().lpNorm<1>().maxCoeff());

  PRINT(m6);
  MatrixXd::Index maxIndex;
  double maxNorm = m6.colwise().sum().maxCoeff(&maxIndex);
  std::cout << "Maximum sum at position " << maxIndex << std::endl
            << "The corresponding vector is: " << std::endl
            << m6.col(maxIndex) << std::endl
            << "And its sum is is: " << maxNorm << std::endl << std::endl;

  SECTION("Broadcasting");
  // https://eigen.tuxfamily.org/dox/group__TutorialReductionsVisitorsBroadcasting.html
  MatrixXd mb = MatrixXd::Zero(2, 4);
  VectorXd vb = Vector2d(0, 1);
  PRINT(mb);
  PRINT(vb);
  mb.colwise() += vb;
  PRINT(mb);
  mb.setZero();
  vb = Vector4d(0, 1, 2, 3);
  mb.rowwise() += vb.transpose();
  PRINT(mb);
  PRINT(vb);
  // find nearest neighbour
  mb.setRandom();
  vb.setRandom(2);
  PRINT(mb);
  PRINT(vb);
  MatrixXf::Index index;
  (mb.colwise() - vb).colwise().squaredNorm().minCoeff(&index);
  std::cout << "Nearest neighbour is column " << index << ":" << std::endl;
  std::cout << mb.col(index) << std::endl;

  SECTION("Resizing");
  // resizing
  // https://eigen.tuxfamily.org/dox/group__TutorialMatrixClass.html
  VectorXd v4 = Vector4d::Ones()*100;
  PRINT(v4);
  v4.conservativeResize(6); // this leave the old value untouched
  PRINT(v4);
  v4.resize(8);
  PRINT(v4);

  PRINT_SIZE(m1);
  m1 = MatrixXd::Identity(6, 6); // copy and resize of matrix with dynamic size
  PRINT(m1);
  PRINT_SIZE(m1);

  // change type of matrix
  MatrixXf m11 = m1.cast<float>();
  PRINT(m11);

  SECTION("Temporary objects");
  // using comma-initializer as temporary objects
  // https://eigen.tuxfamily.org/dox/group__TutorialAdvancedInitialization.html
  MatrixXf mat = MatrixXf::Random(2, 3);
  PRINT(mat);
  mat = (MatrixXf(2,2) << 0, 1, 1, 0).finished() * mat;
  PRINT(mat);
  // https://eigen.tuxfamily.org/dox/structEigen_1_1CommaInitializer.html#a3cf9e2b8a227940f50103130b2d2859a

}


#include <map>
#include <string>
#include <iostream>
#include <Eigen/Dense>
#include "../simple_lib/include/two_layer_net.h"
#include "../datasets/include/mnist.h"

using namespace Eigen;

int main(){
    using std::map;
    using std::cout;
    using std::endl;
    using std::string;
    using namespace MyDL;

    int batch_size = 5;
    int input_size = 28*28;
    int hidden_size = 100;
    int output_size = 10;

    MnistEigenDataset mnist(batch_size);

    MatrixXd train_X = MatrixXd::Zero(batch_size, input_size);
    MatrixXd train_y = MatrixXd::Zero(batch_size, output_size);
    bool one_hot_label = true;

    TwoLayerNet net(input_size, hidden_size, output_size, 0.01);
    // mnist.next_train(train_X, train_y, one_hot_label);
    mnist.next_train(train_X, train_y);

    MatrixXd pred_y;
    double loss, accuracy;
    map<string, MatrixXd> grads;

    pred_y = net.predict(train_X);
    loss = net.loss(train_X, train_y);
    accuracy = net.accuracy(train_X, train_y);
    grads = net.gradient(train_X, train_y);

    cout << "Prediction: " << pred_y << endl;
    cout << "Loss: " << loss << endl;
    cout << "Accuracy: " << accuracy << endl;
    cout << "Gradient W1: " << grads["dW1"] << endl;

    return 0;
}


// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.

#include <dlib/matrix.h>
#include <sstream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <vector>
#include "../stl_checked.h"
#include "../array.h"
#include "../rand.h"
#include <dlib/string.h>

#include "tester.h"

namespace
{

    using namespace test;
    using namespace dlib;
    using namespace std;

    logger dlog("test.matrix_qr");

    dlib::rand rnd;

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

    template <typename mat_type>
    const matrix<typename mat_type::type> symm(const mat_type& m) { return m*trans(m); }

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

    template <typename type>
    const matrix<type> randmat(long r, long c)
    {
        matrix<type> m(r,c);
        for (long row = 0; row < m.nr(); ++row)
        {
            for (long col = 0; col < m.nc(); ++col)
            {
                m(row,col) = static_cast<type>(rnd.get_random_double());
            }
        }

        return m;
    }

    template <typename type, long NR, long NC>
    const matrix<type,NR,NC> randmat()
    {
        matrix<type,NR,NC> m;
        for (long row = 0; row < m.nr(); ++row)
        {
            for (long col = 0; col < m.nc(); ++col)
            {
                m(row,col) = static_cast<type>(rnd.get_random_double());
            }
        }

        return m;
    }

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

    template <typename matrix_type>
    void test_qr ( const matrix_type& m)
    {
        typedef typename matrix_type::type type;
        const type eps = 10*max(abs(m))*sqrt(std::numeric_limits<type>::epsilon());
        dlog << LDEBUG << "test_qr():  " << m.nr() << " x " << m.nc() << "  eps: " << eps;
        print_spinner();

        qr_decomposition<matrix_type> test(m);

        DLIB_TEST(test.nr() == m.nr());
        DLIB_TEST(test.nc() == m.nc());

        type temp;
        DLIB_TEST_MSG( (temp= max(abs(test.get_q()*test.get_r() - m))) < eps,temp);

        // none of the matrices we should be passing in to test_qr() should be non-full rank.
        DLIB_TEST(test.is_full_rank() == true);

        if (m.nr() == m.nc())
        {
            matrix<type> m2;
            matrix<type,0,1> col;

            m2 = identity_matrix<type>(m.nr());
            DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
            m2 = randmat<type>(m.nr(),5);
            DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
            m2 = randmat<type>(m.nr(),1);
            DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2)));
            col = randmat<type>(m.nr(),1);
            DLIB_TEST_MSG(equal(m*test.solve(col), col,eps),max(abs(m*test.solve(m2)- m2)));
        }
        else
        {
            DLIB_TEST_MSG(dlib::equal(pinv(m), test.solve(identity_matrix<type>(m.nr())), eps),
                        max(abs(pinv(m) - test.solve(identity_matrix<type>(m.nr())))) );
        }

        // now make us a non-full rank matrix
        if (m.nc() > 1)
        {
            matrix<type> sm(m);
            set_colm(sm,0) = colm(sm,1);

            qr_decomposition<matrix_type> test2(sm);
            DLIB_TEST_MSG( (temp= max(abs(test.get_q()*test.get_r() - m))) < eps,temp);

            if (test2.nc() < 100)
            {
                DLIB_TEST_MSG(test2.is_full_rank() == false,"eps: " << eps);
            }

        }

    }

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

    void matrix_test_double()
    {

        test_qr(10*randmat<double>(1,1));
        test_qr(10*randmat<double>(2,2));
        test_qr(10*symm(randmat<double>(2,2)));
        test_qr(10*randmat<double>(4,4));
        test_qr(10*randmat<double>(9,4));
        test_qr(10*randmat<double>(15,15));
        test_qr(2*symm(randmat<double>(15,15)));
        test_qr(10*randmat<double>(100,100));
        test_qr(10*randmat<double>(237,200));
        test_qr(10*randmat<double>(200,101));

        test_qr(10*randmat<double,1,1>());
        test_qr(10*randmat<double,2,2>());
        test_qr(10*randmat<double,4,3>());
        test_qr(10*randmat<double,4,4>());
        test_qr(10*randmat<double,9,4>());
        test_qr(10*randmat<double,15,15>());
        test_qr(10*randmat<double,100,100>());

        typedef matrix<double,0,0,default_memory_manager, column_major_layout> mat;
        test_qr(mat(3*randmat<double>(9,4)));
        test_qr(mat(3*randmat<double>(9,9)));
    }

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

    void matrix_test_float()
    {

        test_qr(3*randmat<float>(1,1));
        test_qr(3*randmat<float>(2,2));
        test_qr(3*randmat<float>(4,4));
        test_qr(3*randmat<float>(9,4));
        test_qr(3*randmat<float>(237,200));

        test_qr(3*randmat<float,1,1>());
        test_qr(3*randmat<float,2,2>());
        test_qr(3*randmat<float,4,3>());
        test_qr(3*randmat<float,4,4>());
        test_qr(3*randmat<float,9,4>());

        typedef matrix<float,0,0,default_memory_manager, column_major_layout> mat;
        test_qr(mat(3*randmat<float>(9,4)));
        test_qr(mat(3*randmat<float>(9,9)));
    }

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

    class matrix_tester : public tester
    {
    public:
        matrix_tester (
        ) :
            tester ("test_matrix_qr",
                    "Runs tests on the matrix QR component.")
        {
            //rnd.set_seed(cast_to_string(time(0)));
        }

        void perform_test (
        )
        {
            dlog << LINFO << "seed string: " << rnd.get_seed();

            dlog << LINFO << "begin testing with double";
            matrix_test_double();
            dlog << LINFO << "begin testing with float";
            matrix_test_float();
        }
    } a;

}


//
/// \file lognormal_test.cpp
/// \package how_much_data
//
/// \author Created by Joseph Dunn on 1/25/19.
/// \copyright © 2019 Joseph Dunn. All rights reserved.
//

#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::setw;
using std::setprecision;
using std::fixed;
#include <vector>
using std::vector;
#include <fstream>
using std::ofstream;
#include <boost/timer/timer.hpp>
using boost::timer::auto_cpu_timer;
using boost::timer::cpu_timer;
#include "lognormal_distribution.h"

int main(int argc, const char * argv[]) {
  Kronrod<double> k_big(10);
  int noext = 0;
  double epsabs_double = std::numeric_limits<double>::epsilon()/128;
  double epsrel_double = boost::math::tools::root_epsilon<double>();
  int limit = 1000;
  int verbose_integration = 0;
  IntegrationController<double> cf_ctl(noext, k_big,
                                       epsabs_double, epsrel_double,
                                       limit, verbose_integration);

  string ofile_name{"../output/lognormal_test_fourier_integrand.out"};
  cout << "Writing to file " << ofile_name << endl;
  ofstream trace(ofile_name);
  lognormal_distribution<>::print_fourier_integrand(trace, 1000,
                                            complex<double>(128,0.), .1);

  vector<double> sigmas = {.01, .1, 1, 5, 10};
  vector<complex<double> > omegas;
  omegas.push_back(0.);
  complex<double> i{0,1};
  for (int j=-512; j<=512; j++)
    omegas.push_back(pow(2,j/8.));

  vector<complex<double> > cfs_std;
  vector<complex<double> > cfprimes_std;

  vector<string> names = {"fourier_lnx", "fourier", "lambert_w","fourier_mixed", "adj_series"};
  vector<int> types ={2, 5, 3,4,1};

  for (auto type : types)
  {
    string ofile_name{"../output/lognormal_test_"+names.at(type-1)+".out"};
    cout << "Writing to file " << ofile_name << endl;
    ofstream out(ofile_name);
    auto_cpu_timer timer;
    out << setw(11) << "sigma,"
    << setw(14) << "omega,"
    << setw(17) << "cf_Re,"
    << setw(17) << "cf_Im,"
    << setw(17) << "Abs(cf-cf_std),"
    << setw(17) << "Integ_err,"
    << setw(11) << "# eval,"
    << setw(17) << "Abs(cf) -1"
    << setw(17) << "cfprime_Re,"
    << setw(17) << "cfprime_Im,"
    << setw(17) << "Abs(cfp-cfp_std),"
    << setw(17) << "Integ_err,"
    << setw(11) << "# eval"
    << endl;

    int j = 0;
    for (auto sigma : sigmas) {
      lognormal_distribution<> lnd(0, sigma, cf_ctl, type);
      for (auto omega : omegas ) {
        double cf_integ_err;
        double cf_l1_norm;
        int cf_neval;
        bool adjusted = (type==5 || type==6);
        double mean = adjusted ? 0 : lnd.mean();
        complex<double> fac = exp(- i * mean * omega);
        complex<double> cf = fac* lnd.characteristic_function(omega,
                                                              &cf_integ_err,
                                                              &cf_l1_norm,
                                                              &cf_neval
                                                              );
        bool std = type == types.at(0);
        complex<double> cf_std = std ? cf : cfs_std.at(j);
        if (std) cfs_std.push_back(cf);
        double cfp_integ_err;
        double cfp_l1_norm;
        int cfp_neval;
        complex<double> cfprime = fac*lnd.characteristic_function_prime(omega,
                                                                        &cfp_integ_err,
                                                                        &cfp_l1_norm,
                                                                        &cfp_neval
                                                                        )-i*mean*cf;
        complex<double> cfprime_std = std ? cfprime : cfprimes_std.at(j++);
        if (std) cfprimes_std.push_back(cfprime);
        out << setw(10) << setprecision(2) << sigma << ","
        << setw(13) << setprecision(4) << omega << ","
        << setw(16) << setprecision(8) << real(cf) << ","
        << setw(16) << setprecision(8) << imag(cf) << ","
        << setw(16) << setprecision(8) << abs(cf-cf_std) << ","
        << setw(16) << setprecision(8) << cf_integ_err << ","
        << setw(10) << cf_neval << ","
        << setw(16) << setprecision(8) << abs(cf) - 1. << ","
        << setw(16) << setprecision(8) << real(cfprime) << ","
        << setw(16) << setprecision(8) << imag(cfprime) << ","
        << setw(16) << setprecision(8) << abs(cfprime-cfprime_std) << ","
        << setw(16) << setprecision(8) << cfp_integ_err << ","
        << setw(10) << cfp_neval
        << endl;
      }
    }
    out << endl;
  }

}


#include <iostream>
#include <vector>
#include <alglib/graph/directed_graph.h>

using namespace std;
using namespace alglib::graph;

int main() {

    directed_graph<string, int> G;

    string c1 = "Bikaner";
    string c2 = "Bangalore";
    string c3 = "Jaipur";
    string c4 = "Hanumangarh";
    string c5 = "Jodhpur";

    G.add_vertex(c2);
    G.add_vertex(c1);
    G.add_vertex(c3);
    G.add_vertex(c4);
    G.add_vertex(c5);

    G.add_edge(c1, c2, 100);
    G.add_edge(c5, c1, 250);
    G.add_edge(c2, c3, 110);
    G.add_edge(c1, c4, 40);

    cout << "\nAll the cities: ";
    for(auto it = G.vbegin(); it != G.vend(); it++)
        cout << *it << "\t";
    cout << endl;

    cout << "\nCities adjacent to Bikaner: ";
    for(auto it = G.avbegin(c1); it != G.avend(c1); it++)
        cout << *it << "\t";

    cout << endl;

    cout << "\n\nDirected graph with unweighted edges:\n";
    // unweighted (or graph with unattributed edges) graph
    directed_graph<int> G1;
    G1.add_vertex(3);
    G1.add_vertex(10);

    G1.add_edge(3, 10); // OK
    // G1.add_edge(3, 10, 10);  // Error

    cout << "\nAll the vertices: ";
    for(auto it = G1.vbegin(); it != G1.vend(); it++)
        cout << *it << "\t";
    cout << endl;
}