/*****************************************************************************
*
*     Program: EPTlib
*     Author: Alessandro Arduino <a.arduino@inrim.it>
*
*  MIT License
*
*  Copyright (c) 2020-2021  Alessandro Arduino
*  Istituto Nazionale di Ricerca Metrologica (INRiM)
*  Strada delle cacce 91, 10135 Torino
*  ITALY
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  The above copyright notice and this permission notice shall be included in all
*  copies or substantial portions of the Software.
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*  SOFTWARE.
*
*****************************************************************************/

#include "eptlib/ept_convreact.h"

#include <complex>
#include <limits>

#include <iostream>
#include <fstream>

#include <Eigen/Sparse>

using namespace eptlib;

namespace {
	static double nand = std::numeric_limits<double>::quiet_NaN();
	static std::complex<double> nancd = std::complex<double>(nand,nand);
}

// EPTConvReact constructor
EPTConvReact::
EPTConvReact(const double freq, const std::array<int,NDIM> &nn,
    const std::array<double,NDIM> &dd, const Shape &shape) :
    EPTInterface(freq,nn,dd, 1,1), dir_epsr_(1.0), dir_sigma_(0.0),
    plane_idx_(nn[2]/2), is_volume_(false), diff_coeff_(0.0),
    thereis_diff_(false), fd_filter_(shape),
    solver_iterations_(0), solver_residual_(0.0) {
    return;
}

// EPTConvReact destructor
EPTConvReact::
~EPTConvReact() {
    return;
}

// EPTConvReact run
EPTlibError EPTConvReact::
Run() {
    if (thereis_tx_sens_.all()) {
        thereis_epsr_ = true;
        if (is_volume_) {
            epsr_ = Image<double>(nn_[0],nn_[1],nn_[2]);
        } else {
            epsr_ = Image<double>(nn_[0],nn_[1]);
        }
    }
    if (thereis_trx_phase_.all()) {
        thereis_sigma_ = true;
        if (is_volume_) {
            sigma_ = Image<double>(nn_[0],nn_[1],nn_[2]);
        } else {
            sigma_ = Image<double>(nn_[0],nn_[1]);
        }
    } else {
        return EPTlibError::MissingData;
    }
    if (thereis_epsr_) {
        // ...complete convection-reaction EPT
        return CompleteEPTConvReact();
    } else {
        // ...phase-based convection-reaction EPT
        return PhaseEPTConvReact();
    }
    return EPTlibError::Success;
}

// EPTConvReact set volume tomography
bool EPTConvReact::
Toggle3D() {
    is_volume_ = !is_volume_;
    return is_volume_;
}

// EPTConvReact set the selected plane index
EPTlibError EPTConvReact::
SelectSlice(const int slice_idx) {
    int r2 = fd_filter_.GetShape().GetSize()[2]/2;
    if (slice_idx<r2||slice_idx>nn_[2]-1-r2) {
        return EPTlibError::OutOfRange;
    }
    plane_idx_ = slice_idx;
    return EPTlibError::Success;
}

// EPTConvReact set the dirichlet boundary condition
EPTlibError EPTConvReact::
SetDirichlet(const double dir_epsr, const double dir_sigma) {
    if (dir_epsr<1.0||dir_sigma<0.0) {
        return EPTlibError::WrongDataFormat;
    }
    dir_epsr_ = dir_epsr;
    dir_sigma_ = dir_sigma;
    return EPTlibError::Success;
}

// EPTConvReact set artificial diffusion
void EPTConvReact::
SetArtificialDiffusion(const double diff_coeff) {
    diff_coeff_ = diff_coeff;
    thereis_diff_ = true;
    return;
}
// EPTConvReact unset artificial diffusion
void EPTConvReact::
UnsetArtificialDiffusion() {
    thereis_diff_ = false;
    return;
}

// EPTConvReact get the number of iterations
int EPTConvReact::
GetSolverIterations() {
    return solver_iterations_;
}
// EPTConvReact get estimated error
double EPTConvReact::
GetSolverResidual() {
    return solver_residual_;
}

namespace { // details
    template <typename T>
    void FillDoF(std::vector<int> *dof, int *idx_dof, int *n_dof, int *n_dop,
        const int n_dim, const int i2, const std::array<int,NDIM> &step,
        const std::vector<T> &beta) {
        int idx = step[2]*i2;
        for (int idx_out = 0; idx_out<step[2]; ++idx_out) {
            if (beta[idx]==beta[idx]) {
                // if beta is not a NaN, it could be a DoF...
                (*dof)[(*idx_dof)++] = ++(*n_dof);
                for (int d = 0; d<n_dim; ++d) {
                    if (beta[idx+step[d]]!=beta[idx+step[d]] || beta[idx-step[d]]!=beta[idx-step[d]]) {
                        // ...unless it is near to a NaN
                        (*dof)[*idx_dof-1] = --(*n_dop);
                        --(*n_dof);
                        break;
                    }
                }
            } else {
                (*dof)[(*idx_dof)++] = --(*n_dop);
            }
            ++idx;
        }
        return;
    }
}  // namespace

// EPTConvReact complete EPT
EPTlibError EPTConvReact::
CompleteEPTConvReact() {
    const std::array<int,NDIM> step{1,nn_[0],nn_[0]*nn_[1]};
    int n_dim = is_volume_?NDIM:NDIM-1;
    int n_out = is_volume_?n_vox_:step[2];
    std::complex<double> dir_x = 1.0/std::complex<double>(dir_epsr_*EPS0,-dir_sigma_/omega_);
    // compute the gradient
    std::vector<std::complex<double> > tx_sens_c(n_vox_);
    std::array<std::vector<std::complex<double> >,NDIM> beta;
    for (int idx = 0; idx<n_vox_; ++idx) {
        tx_sens_c[idx] = (*tx_sens_[0])[idx]*std::exp(std::complex<double>(0.0,0.5*(*trx_phase_[0])[idx]));
    }
    for (int d = 0; d<n_dim; ++d) {
        beta[d].resize(n_vox_,std::numeric_limits<double>::quiet_NaN());
        DifferentialOperator diff_op = static_cast<DifferentialOperator>(d);
        EPTlibError error = fd_filter_.Apply(diff_op,beta[d].data(),tx_sens_c.data(),nn_,dd_);
        if (error!=EPTlibError::Success) {
            return error;
        }
    }
    for (int idx = 0; idx<n_vox_; ++idx) {
        beta[0][idx] = beta[0][idx] - std::complex<double>(0.0,1.0)*beta[1][idx];
        beta[1][idx] = std::complex<double>(0.0,1.0)*beta[0][idx];
    }
    if (!is_volume_) {
        beta[2].resize(n_vox_,std::numeric_limits<double>::quiet_NaN());
        DifferentialOperator diff_op = DifferentialOperator::GradientZZ;
        EPTlibError error = fd_filter_.Apply(diff_op,beta[2].data(),tx_sens_c.data(),nn_,dd_);
        if (error!=EPTlibError::Success) {
            return error;
        }
    }
    // select the degrees of freedom
    std::vector<int> dof(n_out);
    int idx_dof = 0;
    int n_dof = 0;
    int n_dop = 0;
    if (is_volume_) {
        for (int i2 = 0; i2<nn_[2]; ++i2) {
            ::FillDoF(&dof,&idx_dof,&n_dof,&n_dop, n_dim,i2,step,beta[0]);
        }
    } else {
        ::FillDoF(&dof,&idx_dof,&n_dof,&n_dop, n_dim,plane_idx_,step,beta[0]);
    }
    // build coefficient matrix and forcing term
    Eigen::SparseMatrix<std::complex<double> > A(n_dof,n_dof);
    std::vector<Eigen::Triplet<std::complex<double> > > A_trip(0);
    Eigen::VectorXcd b(n_dof);
    for (int idx_out = 0; idx_out<n_out; ++idx_out) {
        int idx = is_volume_?idx_out:idx_out+step[2]*plane_idx_;
        int idof = dof[idx_out];
        if (idof > 0) {
            b[idof-1] = 0.0;
            // coefficient matrix
            for (int d = 0; d<n_dim; ++d) {
                if (thereis_diff_) {
                    A_trip.push_back(Eigen::Triplet<std::complex<double> >(idof-1,idof-1,2.0*diff_coeff_/dd_[d]/dd_[d]));
                }
                int jdx_out = idx_out+step[d];
                int jdx = idx+step[d];
                int jdof = dof[jdx_out];
                if (jdof > 0) {
                    A_trip.push_back(Eigen::Triplet<std::complex<double> >(idof-1,jdof-1,beta[d][jdx]/2.0/dd_[d]));
                    if (thereis_diff_) {
                        A_trip.push_back(Eigen::Triplet<std::complex<double> >(idof-1,jdof-1,-diff_coeff_/dd_[d]/dd_[d]));
                    }
                } else {
                    b[idof-1] += -dir_x*beta[d][jdx]/2.0/dd_[d];
                    if (thereis_diff_) {
                        b[idof-1] += dir_x*diff_coeff_/dd_[d]/dd_[d];
                    }
                }
                jdx_out = idx_out-step[d];
                jdx = idx-step[d];
                jdof = dof[jdx_out];
                if (jdof > 0) {
                    A_trip.push_back(Eigen::Triplet<std::complex<double> >(idof-1,jdof-1,-beta[d][jdx]/2.0/dd_[d]));
                    if (thereis_diff_) {
                        A_trip.push_back(Eigen::Triplet<std::complex<double> >(idof-1,jdof-1,-diff_coeff_/dd_[d]/dd_[d]));
                    }
                } else {
                    b[idof-1] += dir_x*beta[d][jdx]/2.0/dd_[d];
                    if (thereis_diff_) {
                        b[idof-1] += dir_x*diff_coeff_/dd_[d]/dd_[d];
                    }
                }
            }
            if (!is_volume_) {
                A_trip.push_back(Eigen::Triplet<std::complex<double> >(idof-1,idof-1,beta[2][idx]));
            }
            // forcing term
            b[idof-1] += -omega_*omega_*MU0*tx_sens_c[idx];
        }
    }
    A.setFromTriplets(A_trip.begin(),A_trip.end());
    A.makeCompressed();
    // Solve the linear system
    Eigen::BiCGSTAB<Eigen::SparseMatrix<std::complex<double> > > solver;
    solver.compute(A);
    Eigen::VectorXcd x = solver.solve(b);
    solver_iterations_ = solver.iterations();
    solver_residual_ = solver.error();
    // Extract the electric properties from the result
    for (int idx = 0; idx<n_out; ++idx) {
        int idof = dof[idx];
        if (idof > 0) {
            std::complex<double> epsc = 1.0/x[idof-1];
            epsr_[idx] = epsc.real()/EPS0;
            sigma_[idx] = -epsc.imag()*omega_;
        } else {
            epsr_[idx] = ::nand;
            sigma_[idx] = ::nand;
        }
    }
    return EPTlibError::Success;
}

// EPTConvReact phase-based EPT
EPTlibError EPTConvReact::
PhaseEPTConvReact() {
    const std::array<int,NDIM> step{1,nn_[0],nn_[0]*nn_[1]};
    int n_dim = is_volume_?NDIM:NDIM-1;
    int n_out = is_volume_?n_vox_:step[2];
    double dir_x = 1.0/dir_sigma_;
    // compute the gradient
    std::array<std::vector<double>,NDIM> beta;
    for (int d = 0; d<n_dim; ++d) {
        beta[d].resize(n_vox_,std::numeric_limits<double>::quiet_NaN());
        DifferentialOperator diff_op = static_cast<DifferentialOperator>(d);
        EPTlibError error;
        if (PhaseIsWrapped()) {
            error = WrappedPhaseDerivative(diff_op,beta[d].data(),trx_phase_[0]->GetData().data(),nn_,dd_,fd_filter_);
        } else {
            error = fd_filter_.Apply(diff_op,beta[d].data(),trx_phase_[0]->GetData().data(),nn_,dd_);
        }
        if (error!=EPTlibError::Success) {
            return error;
        }
    }
    if (!is_volume_) {
        beta[2].resize(n_vox_,std::numeric_limits<double>::quiet_NaN());
        DifferentialOperator diff_op = DifferentialOperator::GradientZZ;
        EPTlibError error;
        if (PhaseIsWrapped()) {
            error = WrappedPhaseDerivative(diff_op,beta[2].data(),trx_phase_[0]->GetData().data(),nn_,dd_,fd_filter_);
        } else {
            error = fd_filter_.Apply(diff_op,beta[2].data(),trx_phase_[0]->GetData().data(),nn_,dd_);
        }
        if (error!=EPTlibError::Success) {
            return error;
        }
    }
    // select the degrees of freedom
    std::vector<int> dof(n_out);
    int idx_dof = 0;
    int n_dof = 0;
    int n_dop = 0;
    if (is_volume_) {
        for (int i2 = 0; i2<nn_[2]; ++i2) {
            ::FillDoF(&dof,&idx_dof,&n_dof,&n_dop, n_dim,i2,step,beta[0]);
        }
    } else {
        ::FillDoF(&dof,&idx_dof,&n_dof,&n_dop, n_dim,plane_idx_,step,beta[0]);
    }
    // build coefficient matrix and forcing term
    Eigen::SparseMatrix<double> A(n_dof,n_dof);
    std::vector<Eigen::Triplet<double> > A_trip(0);
    Eigen::VectorXd b(n_dof);
    for (int idx_out = 0; idx_out<n_out; ++idx_out) {
        int idx = is_volume_?idx_out:idx_out+step[2]*plane_idx_;
        int idof = dof[idx_out];
        if (idof > 0) {
            b[idof-1] = 0.0;
            // coefficient matrix
            for (int d = 0; d<n_dim; ++d) {
                // diffusion (central term)
                if (thereis_diff_) {
                    A_trip.push_back(Eigen::Triplet<double>(idof-1,idof-1,2.0*diff_coeff_/dd_[d]/dd_[d]));
                }
                std::array<int,2> sides{+1,-1};
                for (int s = 0; s<2; ++s) {
                    int jdx_out = idx_out+sides[s]*step[d];
                    int jdx = idx+sides[s]*step[d];
                    int jdof = dof[jdx_out];
                    // convection
                    if (beta[d][idx]*beta[d][jdx]>0) {
                        if (sides[s]*beta[d][idx]>0) {
                            double A_tmp = sides[s]*beta[d][idx]/dd_[d];
                            A_trip.push_back(Eigen::Triplet<double>(idof-1,idof-1,A_tmp));
                        } else {
                            double A_tmp = sides[s]*beta[d][jdx]/dd_[d];
                            if (jdof > 0) {
                                A_trip.push_back(Eigen::Triplet<double>(idof-1,jdof-1,A_tmp));
                            } else {
                                b[idof-1] += -dir_x*A_tmp;
                            }
                        }
                    } else {
                        double A_tmp = sides[s]*beta[d][idx]/dd_[d]/2.0;
                        A_trip.push_back(Eigen::Triplet<double>(idof-1,idof-1,A_tmp));
                        A_tmp = sides[s]*beta[d][jdx]/dd_[d]/2.0;
                        if (jdof > 0) {
                            A_trip.push_back(Eigen::Triplet<double>(idof-1,jdof-1,A_tmp));
                        } else {
                            b[idof-1] += -dir_x*A_tmp;
                        }
                    }
                    // diffusion
                    if (thereis_diff_) {
                        if (jdof > 0) {
                            A_trip.push_back(Eigen::Triplet<double>(idof-1,jdof-1,-diff_coeff_/dd_[d]/dd_[d]));
                        } else {
                            b[idof-1] += dir_x*diff_coeff_/dd_[d]/dd_[d];
                        }
                    }
                }
            }
            if (!is_volume_) {
                A_trip.push_back(Eigen::Triplet<double>(idof-1,idof-1,beta[2][idx]));
            }
            // forcing term
            b[idof-1] += 2*omega_*MU0;
        }
    }
    A.setFromTriplets(A_trip.begin(),A_trip.end());
    A.makeCompressed();
    // Solve the linear system
    Eigen::BiCGSTAB<Eigen::SparseMatrix<double> > solver;
    solver.compute(A);
    Eigen::VectorXd x = solver.solve(b);
    solver_iterations_ = solver.iterations();
    solver_residual_ = solver.error();
    // Extract the electric properties from the result
    for (int idx = 0; idx<n_out; ++idx) {
        int idof = dof[idx];
        if (idof > 0) {
            sigma_[idx] = 1.0/x[idof-1];
        } else {
            sigma_[idx] = ::nand;
        }
    }
    return EPTlibError::Success;
}


// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG (haftungsbeschränkt), www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also license.mtl.txt in the distribution.

#ifndef MTL_RVEC_MAT_TIMES_EXPR_INCLUDE
#define MTL_RVEC_MAT_TIMES_EXPR_INCLUDE

#include <boost/numeric/mtl/operation/bin_op_expr.hpp>
#include <boost/numeric/mtl/mtl_fwd.hpp>

namespace mtl { namespace vec {

template <typename E1, typename E2>
struct rvec_mat_times_expr
  : public bin_op_expr< E1, E2 >,
    public mtl::vec::vec_expr< rvec_mat_times_expr<E1, E2> >
{
    typedef bin_op_expr< E1, E2 >         base;
    typedef rvec_mat_times_expr<E1, E2>   self;

    typedef typename Multiplicable<typename Collection<E1>::value_type,
				   typename Collection<E2>::value_type>::result_type   value_type;
    typedef typename Collection<E2>::size_type    size_type;

    rvec_mat_times_expr( E1 const& v, E2 const& A ) : base(v, A) {}
};

template <typename E1, typename E2>
std::size_t inline size(const rvec_mat_times_expr<E1, E2>& x)
{ return num_cols(x.first); }

}} // namespace mtl::vector

#endif // MTL_RVEC_MAT_TIMES_EXPR_INCLUDE


/*
 Copyright (C) 2016 Quaternion Risk Management Ltd
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

 ORE is free software: you can redistribute it and/or modify it
 under the terms of the Modified BSD License.  You should have received a
 copy of the license along with this program.
 The license is also available online at <http://opensourcerisk.org>

 This program is distributed on the basis that it will form a useful
 contribution to risk analytics and model standardisation, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
*/

#include <qle/termstructures/optionletstripper2.hpp>
#include <qle/termstructures/spreadedoptionletvolatility.hpp>

#include <ql/instruments/makecapfloor.hpp>
#include <ql/math/solvers1d/brent.hpp>
#include <ql/pricingengines/capfloor/bacheliercapfloorengine.hpp>
#include <ql/pricingengines/capfloor/blackcapfloorengine.hpp>
#include <ql/termstructures/volatility/optionlet/strippedoptionletadapter.hpp>

#include <boost/make_shared.hpp>

namespace QuantExt {

OptionletStripper2::OptionletStripper2(const boost::shared_ptr<QuantExt::OptionletStripper>& optionletStripper,
                                       const Handle<QuantLib::CapFloorTermVolCurve>& atmCapFloorTermVolCurve,
                                       const Handle<YieldTermStructure>& discount, const VolatilityType type,
                                       const Real displacement)
    : OptionletStripper(optionletStripper->termVolSurface(), optionletStripper->iborIndex(), discount,
                        optionletStripper->volatilityType(), optionletStripper->displacement()),
      stripper_(optionletStripper), atmCapFloorTermVolCurve_(atmCapFloorTermVolCurve),
      dc_(stripper_->termVolSurface()->dayCounter()), nOptionExpiries_(atmCapFloorTermVolCurve->optionTenors().size()),
      atmCapFloorStrikes_(nOptionExpiries_), atmCapFloorPrices_(nOptionExpiries_), spreadsVolImplied_(nOptionExpiries_),
      caps_(nOptionExpiries_), maxEvaluations_(10000), accuracy_(1.e-6), inputVolatilityType_(type),
      inputDisplacement_(displacement) {

    registerWith(stripper_);
    registerWith(atmCapFloorTermVolCurve_);

    QL_REQUIRE(dc_ == atmCapFloorTermVolCurve->dayCounter(), "different day counters provided");
}

void OptionletStripper2::performCalculations() const {

    // optionletStripper data
    optionletDates_ = stripper_->optionletFixingDates();
    optionletPaymentDates_ = stripper_->optionletPaymentDates();
    optionletAccrualPeriods_ = stripper_->optionletAccrualPeriods();
    optionletTimes_ = stripper_->optionletFixingTimes();
    atmOptionletRate_ = stripper_->atmOptionletRates();
    for (Size i = 0; i < optionletTimes_.size(); ++i) {
        optionletStrikes_[i] = stripper_->optionletStrikes(i);
        optionletVolatilities_[i] = stripper_->optionletVolatilities(i);
    }

    // atmCapFloorTermVolCurve data
    const vector<Period>& optionExpiriesTenors = atmCapFloorTermVolCurve_->optionTenors();
    const vector<Time>& optionExpiriesTimes = atmCapFloorTermVolCurve_->optionTimes();

    // discount curve
    const Handle<YieldTermStructure>& discountCurve =
        discount_.empty() ? iborIndex_->forwardingTermStructure() : discount_;

    for (Size j = 0; j < nOptionExpiries_; ++j) {
        // Dummy strike, doesn't get used for ATM curve
        Volatility atmOptionVol = atmCapFloorTermVolCurve_->volatility(optionExpiriesTimes[j], 33.3333);

        // Create a cap for each pillar point on ATM curve and attach relevant pricing engine i.e. Black if
        // quotes are shifted lognormal and Bachelier if quotes are normal
        boost::shared_ptr<PricingEngine> engine;
        if (inputVolatilityType_ == ShiftedLognormal) {
            engine = boost::make_shared<BlackCapFloorEngine>(discountCurve, atmOptionVol, dc_, inputDisplacement_);
        } else if (inputVolatilityType_ == Normal) {
            engine = boost::make_shared<BachelierCapFloorEngine>(discountCurve, atmOptionVol, dc_);
        } else {
            QL_FAIL("unknown volatility type: " << volatilityType_);
        }

        // Using Null<Rate>() as strike => strike will be set to ATM rate. However, to calculate ATM rate, QL requires
        // a BlackCapFloorEngine to be set (not a BachelierCapFloorEngine)! So, need a temp BlackCapFloorEngine with a
        // dummy vol to calculate ATM rate. Needs to be fixed in QL.
        boost::shared_ptr<PricingEngine> tempEngine = boost::make_shared<BlackCapFloorEngine>(discountCurve, 0.01);
        caps_[j] = MakeCapFloor(CapFloor::Cap, optionExpiriesTenors[j], iborIndex_, Null<Rate>(), 0 * Days)
                       .withPricingEngine(tempEngine);

        // Now set correct engine and get the ATM rate and the price
        caps_[j]->setPricingEngine(engine);
        atmCapFloorStrikes_[j] = caps_[j]->atmRate(**discountCurve);
        atmCapFloorPrices_[j] = caps_[j]->NPV();
    }

    spreadsVolImplied_ = spreadsVolImplied(discountCurve);

    StrippedOptionletAdapter adapter(stripper_);
    adapter.enableExtrapolation();

    Volatility unadjustedVol, adjustedVol;
    for (Size j = 0; j < nOptionExpiries_; ++j) {
        for (Size i = 0; i < optionletVolatilities_.size(); ++i) {
            if (i <= caps_[j]->floatingLeg().size()) {
                unadjustedVol = adapter.volatility(optionletTimes_[i], atmCapFloorStrikes_[j]);
                adjustedVol = unadjustedVol + spreadsVolImplied_[j];

                // insert adjusted volatility
                vector<Rate>::const_iterator previous =
                    lower_bound(optionletStrikes_[i].begin(), optionletStrikes_[i].end(), atmCapFloorStrikes_[j]);
                Size insertIndex = previous - optionletStrikes_[i].begin();

                optionletStrikes_[i].insert(optionletStrikes_[i].begin() + insertIndex, atmCapFloorStrikes_[j]);
                optionletVolatilities_[i].insert(optionletVolatilities_[i].begin() + insertIndex, adjustedVol);
            }
        }
    }
}

vector<Volatility> OptionletStripper2::spreadsVolImplied(const Handle<YieldTermStructure>& discount) const {

    Brent solver;
    vector<Volatility> result(nOptionExpiries_);
    Volatility guess = 0.0001, minSpread = -0.1, maxSpread = 0.1;
    for (Size j = 0; j < nOptionExpiries_; ++j) {
        ObjectiveFunction f(stripper_, caps_[j], atmCapFloorPrices_[j], discount);
        solver.setMaxEvaluations(maxEvaluations_);
        Volatility root = solver.solve(f, accuracy_, guess, minSpread, maxSpread);
        result[j] = root;
    }
    return result;
}

vector<Volatility> OptionletStripper2::spreadsVol() const {
    calculate();
    return spreadsVolImplied_;
}

vector<Rate> OptionletStripper2::atmCapFloorStrikes() const {
    calculate();
    return atmCapFloorStrikes_;
}

vector<Real> OptionletStripper2::atmCapFloorPrices() const {
    calculate();
    return atmCapFloorPrices_;
}

// OptionletStripper2::ObjectiveFunction
OptionletStripper2::ObjectiveFunction::ObjectiveFunction(
    const boost::shared_ptr<QuantExt::OptionletStripper>& optionletStripper, const boost::shared_ptr<CapFloor>& cap,
    Real targetValue, const Handle<YieldTermStructure>& discount)
    : cap_(cap), targetValue_(targetValue), discount_(discount) {
    boost::shared_ptr<OptionletVolatilityStructure> adapter(new StrippedOptionletAdapter(optionletStripper));
    adapter->enableExtrapolation();

    // set an implausible value, so that calculation is forced
    // at first operator()(Volatility x) call
    spreadQuote_ = boost::shared_ptr<SimpleQuote>(new SimpleQuote(-1.0));

    boost::shared_ptr<OptionletVolatilityStructure> spreadedAdapter(
        new SpreadedOptionletVolatility(Handle<OptionletVolatilityStructure>(adapter), Handle<Quote>(spreadQuote_)));

    // Use the same volatility type as optionletStripper
    // Anything else would not make sense
    boost::shared_ptr<PricingEngine> engine;
    if (optionletStripper->volatilityType() == ShiftedLognormal) {
        engine = boost::make_shared<BlackCapFloorEngine>(
            discount_, Handle<OptionletVolatilityStructure>(spreadedAdapter), optionletStripper->displacement());
    } else if (optionletStripper->volatilityType() == Normal) {
        engine = boost::make_shared<BachelierCapFloorEngine>(discount_,
                                                             Handle<OptionletVolatilityStructure>(spreadedAdapter));
    } else {
        QL_FAIL("Unknown volatility type: " << optionletStripper->volatilityType());
    }

    cap_->setPricingEngine(engine);
}

Real OptionletStripper2::ObjectiveFunction::operator()(Volatility s) const {
    if (s != spreadQuote_->value())
        spreadQuote_->setValue(s);
    return cap_->NPV() - targetValue_;
}
} // namespace QuantExt


/****
   Copyright 2005-2007, Moshe Looks and Novamente LLC

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

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

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

#include "moses/moses.h"
#include "moses/optimization.h"
#include "moses/scoring_functions.h"
#include <boost/lexical_cast.hpp>
#include "reduct/reduct.h"
#include <iostream>

using namespace moses;
using namespace reduct;
using namespace boost;
using namespace std;

int main(int argc,char** argv) {
  int order,max_evals;
  int arity=1,nsamples=20;
  try {
    if (argc!=4)
      throw "foo";
    srand(lexical_cast<int>(argv[1]));
    order=lexical_cast<int>(argv[2]);
    max_evals=lexical_cast<int>(argv[3]);
  } catch (...) {
    cerr << "usage: " << argv[0] << " seed order maxevals" << endl;
    exit(1);
  }

  tree_type tt(id::application);
  tt.append_children(tt.begin(),id::contin,2);

  RndNumTable rands(nsamples,arity);

  cout << rands << endl;

  metapopulation<contin_score,contin_bscore,univariate_optimization>
    metapop(vtree(id::plus),
	    tt,contin_reduction(),
	    contin_score(simple_symbolic_regression(order),rands),
	    contin_bscore(simple_symbolic_regression(order),rands));

  //had to put namespace moses otherwise gcc-4.1 complains that it is ambiguous
  moses::moses(metapop,max_evals,0);
}


//| This file is a part of the sferes2 framework.
//| Copyright 2009, ISIR / Universite Pierre et Marie Curie (UPMC)
//| Main contributor(s): Jean-Baptiste Mouret, mouret@isir.fr
//|
//| This software is a computer program whose purpose is to facilitate
//| experiments in evolutionary computation and evolutionary robotics.
//|
//| This software is governed by the CeCILL license under French law
//| and abiding by the rules of distribution of free software.  You
//| can use, modify and/ or redistribute the software under the terms
//| of the CeCILL license as circulated by CEA, CNRS and INRIA at the
//| following URL "http://www.cecill.info".
//|
//| As a counterpart to the access to the source code and rights to
//| copy, modify and redistribute granted by the license, users are
//| provided only with a limited warranty and the software's author,
//| the holder of the economic rights, and the successive licensors
//| have only limited liability.
//|
//| In this respect, the user's attention is drawn to the risks
//| associated with loading, using, modifying and/or developing or
//| reproducing the software by the user in light of its specific
//| status of free software, that may mean that it is complicated to
//| manipulate, and that also therefore means that it is reserved for
//| developers and experienced professionals having in-depth computer
//| knowledge. Users are therefore encouraged to load and test the
//| software's suitability as regards their requirements in conditions
//| enabling the security of their systems and/or data to be ensured
//| and, more generally, to use and operate it in the same conditions
//| as regards security.
//|
//| The fact that you are presently reading this means that you have
//| had knowledge of the CeCILL license and that you accept its terms.

#ifndef MODIFIER_NOVELTY_HPP
#define MODIFIER_NOVELTY_HPP

#include <Eigen/Core>
#include "sferes/parallel.hpp"
#include <boost/uuid/uuid.hpp>            // uuid class

//#include <boost/accumulators/accumulators.hpp>
//#include <boost/accumulators/statistics/stats.hpp>
//
//// Headers specifics to the computations we need
//#include <boost/accumulators/statistics/max.hpp>
//#include <boost/accumulators/statistics/min.hpp>

namespace sferes {
  namespace modif {
    namespace novelty {

      // compute the matrix of distances
      template<typename Phen>
      struct _distance_f {
        typedef std::vector<boost::shared_ptr<Phen> > pop_t;
        const pop_t& _pop;
        const pop_t& _archive;
        Eigen::MatrixXf& distances;

        ~_distance_f() { }
        _distance_f(const pop_t& pop, const pop_t& archive, Eigen::MatrixXf& d) :
          _pop(pop), _archive(archive), distances(d) {}
        _distance_f(const _distance_f& ev) :
          _pop(ev._pop), _archive(ev._archive), distances(ev.distances) {}

        void operator() (const parallel::range_t& r) const {
          for (size_t i = r.begin(); i != r.end(); ++i) {
            for (size_t j = 0; j < _archive.size(); ++j)
            {
            	float d = 0;

            	// Check if they are not the same image
            	if ((_pop[i] != _archive[j]) && (_pop[i]->id() != _archive[j]->id()))
            	{
#ifdef EUCLIDEAN_DISTANCE
            		// Euclidean distance
            		d = _pop[i]->dist(*_archive[j]);

            		#else
            		// Regular distance
            		d = _pop[i]->fit().dist(*_archive[j]);
#endif
            	}

              distances(i, j) = d;
            }
          }
        }
      };
    }

    // The novelty score will be stored in the last objective 'slot'
    // If there is only one objective (this->objs().size() == 1), then
    // this modifiers is a standard Novelty search algorithm [1]
    // otherwise, it is a "novelty-based multi-objectivization" [2]
    // See [2] for more explanations of the differences between
    // novelty search, multi-objective novelty search, and behavioral diversity
    //
    // * References
    // [1] Lehman, Joel, and Kenneth O. Stanley. "Abandoning objectives:
    // Evolution through the search for novelty alone."
    // Evolutionary computation 19.2 (2011): 189-223.
    //
    // [2] Mouret, Jean-Baptiste. "Novelty-based multiobjectivization."
    // New Horizons in Evolutionary Robotics. Springer Berlin Heidelberg,
    // 2011. 139-154.
    template<typename Phen, typename Params, typename Exact = stc::Itself>
    class Novelty {
     public:
      typedef boost::shared_ptr<Phen> phen_t;
      typedef std::vector<phen_t> pop_t;
      Novelty() : _rho_min(Params::novelty::rho_min_init), _not_added(0) {}

      template<typename Ea>
      void apply(Ea& ea)
      {
//      	boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::max> > acc_max;
//      	boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::min> > acc_min;

        SFERES_CONST size_t k = Params::novelty::k;
        // merge the population and the archive in a single archive
        pop_t archive = _archive;
        archive.insert(archive.end(), ea.pop().begin(), ea.pop().end());

        // we compute all the distances from pop(i) to archive(j) and store them
        Eigen::MatrixXf distances(ea.pop().size(), archive.size());
        novelty::_distance_f<Phen> f(ea.pop(), archive, distances);
        parallel::init();
        parallel::p_for(parallel::range_t(0, ea.pop().size()), f);

        // compute the sparseness of each individual of the population
        // and potentially add to the archive
        int added = 0;

        for (size_t i = 0; i < ea.pop().size(); ++i) {
          size_t nb_objs = ea.pop()[i]->fit().objs().size();
          Eigen::VectorXf vd = distances.row(i);

          // Get the k-nearest neighbors
          double n = 0.0;
          std::partial_sort(vd.data(),
                            vd.data() + k,
                            vd.data() + vd.size());

          // Sum up the total of distances from k-nearest neighbors
          // This is the novelty score
          n = vd.head<k>().sum() / k;

          // Set the novelty score to the last objective in the array of objectives
          ea.pop()[i]->fit().set_obj(nb_objs - 1, n);

//          std::cout << "rho = " << _rho_min << "; n = " << n << "\n";
//          acc_max(n);
//          acc_min(n);

          // Check if this individual is already in the archive
          if (!in_archive_already(ea.pop()[i]->id()) &&
          		(n > _rho_min			// Check if the novelty score passes the threshold
              || misc::rand<float>() < Params::novelty::add_to_archive_prob))
          {
          	// Add this individual to the permanent archive
          	_archive.push_back(ea.pop()[i]);

          	// Print this indiv just added
//            std::cout << "----> n = " << n << "; label = " << ea.pop()[i]->fit().label() << "; score = " << ea.pop()[i]->fit().score() << "; id = " << ea.pop()[i]->id()  <<"\n";
//          	std::cout << "----> n = " << n << "; label = " << "; id = " << ea.pop()[i]->id()  <<"\n";

            _not_added = 0;
            ++added;
          } else {
          	// Do not add this individual to the archive
            ++_not_added;
          }
        } // end for all individuals

        // update rho_min
        if (_not_added > Params::novelty::stalled_tresh)//2500
        {
          _rho_min *= 0.95;	// Lower rho_min
          _not_added = 0;		// After lowering the stalled threshold, we need to reset the _not_added count
        }
        if (_archive.size() > Params::novelty::k && added > Params::novelty::adding_tresh)//4
        {
          _rho_min *= 1.05f;	// Increase rho_min
        }

        std::cout<<"a size:"<<_archive.size()<<std::endl;

        // DEBUG
//        std::cout << "a size:"<<_archive.size()
//        		<< "; max: " << boost::accumulators::max(acc_max)
//        		<< "; min: " << boost::accumulators::min(acc_min)
//        		<< std::endl;

      }

      /*
			 * Check if this individual is already in the archive.
			 */
			const bool in_archive_already ( const boost::uuids::uuid& id )
			{
				/* Comment out to save computation time
				for (int i = 0; i < _archive.size(); ++i)
				{
					// Check if this id is found in the archive.
					if (_archive[i]->id() == id)
					{
						return true;
					}

				}
				*/

				return false;
			}

      /*
       * Getter of archive.
       *
       * This function is created for statistics class to save the archive down to gen file.
       * 2015-01-21
       */
      const pop_t& archive() const
      {
      	return _archive;
      }

      /*
       * Setter of archive.
       *
       * This function is created for statistics class to save the archive down to gen file.
       * 2015-01-21
       */
      void set_archive(const pop_t& archive)
      {
      	_archive.clear();

      	// Assign items to archive
      	_archive.insert(_archive.end(), archive.begin(), archive.end());
      }

     protected:
      pop_t _archive;
      float _rho_min;
      size_t _not_added;
    };
  } // modif
} // sferes

#endif


//==============================================================================
//         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
//==============================================================================
/*!
 * \file
**/
#ifndef BOOST_SIMD_TOOLBOX_ARITHMETIC_FUNCTIONS_ISQRT_HPP_INCLUDED
#define BOOST_SIMD_TOOLBOX_ARITHMETIC_FUNCTIONS_ISQRT_HPP_INCLUDED
#include <boost/simd/include/functor.hpp>
#include <boost/dispatch/include/functor.hpp>

/*!
 * \ingroup boost_simd_arithmetic
 * \defgroup boost_simd_arithmetic_isqrt isqrt
 *
 * \par Description
 * return the integer truncation of the squre root of  the entry.
 * The value returned in the same type as the entry.
 * /par
 * Negative entry leads to zero for integer entry and nan for floating one.
 *
 * \par Header file
 *
 * \code
 * #include <nt2/include/functions/isqrt.hpp>
 * \endcode
 *
 *
 * \synopsis
 *
 * \code
 * namespace boost::simd
 * {
 *   template <class A0>
 *     meta::call<tag::isqrt_(A0)>::type
 *     isqrt(const A0 & a0);
 * }
 * \endcode
 *
 * \param a0 the unique parameter of isqrt
 *
 * \return an integer value
 *
 * \par Notes
 * In SIMD mode, this function acts elementwise on the inputs vectors elements
 * \par
 *
**/

namespace boost { namespace simd { namespace tag
  {
    /*!
     * \brief Define the tag isqrt_ of functor isqrt
     *        in namespace boost::simd::tag for toolbox boost.simd.arithmetic
    **/
    struct isqrt_ : ext::elementwise_<isqrt_> { typedef ext::elementwise_<isqrt_> parent; };
  }
  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION(tag::isqrt_, isqrt, 1)
} }

#endif

// modified by jt the 25/12/2010


// This file is part of MLDB. Copyright 2015 mldb.ai inc. All rights reserved.

/* separation_stats.cc
   Jeremy Barnes, 14 June 2011
   Copyright (c) 2011 mldb.ai inc.  All rights reserved.

*/

#include "separation_stats.h"
#include "mldb/arch/exception.h"
#include "mldb/base/exc_assert.h"
#include <boost/utility.hpp>
#include "mldb/vfs/filter_streams.h"

using namespace std;

namespace MLDB {

/*****************************************************************************/
/* BINARY STATS                                                              */
/*****************************************************************************/

double
BinaryStats::
rocAreaSince(const BinaryStats & other) const
{
    double tp1 = other.truePositiveRate(), fp1 = other.falsePositiveRate();
    double tp2 = truePositiveRate(), fp2 = falsePositiveRate();

    double result = (fp2 - fp1) * (tp1 + tp2) * 0.5;

    //cerr << "tp1 = " << tp1 << " tp2 = " << tp2 << " fp1 = " << fp1
    //     << " fp2 = " << fp2 << " area = " << result << endl;

    return result;
}

void
BinaryStats::
add(const BinaryStats & other, double weight)
{
    auto addCounts = [&] (      Array2D & local,
                          const Array2D & other,
                                       float w)

    {
        local[0][0] += w * other[0][0];
        local[0][1] += w * other[0][1];
        local[1][0] += w * other[1][0];
        local[1][1] += w * other[1][1];
    };

    addCounts(counts, other.counts, weight);
    addCounts(unweighted_counts, other.unweighted_counts, 1);

    threshold += weight * other.threshold;
}

Json::Value
BinaryStats::
toJson() const
{
    Json::Value result;
    result["population"]["included"] = includedPopulation();
    result["population"]["excluded"] = excludedPopulation();
    result["pr"]["accuracy"] = accuracy();
    result["pr"]["precision"] = precision();
    result["pr"]["recall"] = recall();
    result["pr"]["f1Score"] = f();
    result["mcc"] = mcc();
    result["gain"] = gain();
    result["counts"]["truePositives"] = truePositives();
    result["counts"]["falsePositives"] = falsePositives();
    result["counts"]["trueNegatives"] = trueNegatives();
    result["counts"]["falseNegatives"] = falseNegatives();
    result["threshold"] = threshold;
    return result;
}

/*****************************************************************************/
/* SCORED STATS                                                              */
/*****************************************************************************/

ScoredStats::
ScoredStats()
    : auc(1.0), isSorted(true)
{
}

BinaryStats
ScoredStats::
atThreshold(float threshold) const
{
    struct FindThreshold {
        bool operator () (const BinaryStats & e1, const BinaryStats & e2) const
        {
            return e1.threshold > e2.threshold;
        }

        bool operator () (const BinaryStats & e1, float e2) const
        {
            return e1.threshold > e2;
        }

        bool operator () (float e1, const BinaryStats & e2) const
        {
            return e1 > e2.threshold;
        }
    };

    if (!std::is_sorted(stats.begin(), stats.end(), FindThreshold()))
        throw Exception("stats not sorted on input");

    if (stats.empty())
        throw Exception("stats is empty");

    // Lower bound means strictly above
    auto lower
        = std::lower_bound(stats.begin(), stats.end(), threshold,
                           FindThreshold());

    if (lower == stats.end())
        return stats.back();

    return *lower;
}

BinaryStats
ScoredStats::
atPercentile(float percentile) const
{
    struct FindPercentile {
        bool operator () (const BinaryStats & e1, const BinaryStats & e2) const
        {
            return e1.proportionOfPopulation() < e2.proportionOfPopulation();
        }

        bool operator () (const BinaryStats & e1, float e2) const
        {
            return e1.proportionOfPopulation() < e2;
        }

        bool operator () (float e1, const BinaryStats & e2) const
        {
            return e1 < e2.proportionOfPopulation();
        }
    };

    for (unsigned i = 1;  i < stats.size();  ++i) {
        if (stats[i -1].proportionOfPopulation() > stats[i].proportionOfPopulation()) {
            cerr << "i = " << i << endl;
            cerr << "prev = " << stats[i - 1].toJson() << endl;
            cerr << "ours = " << stats[i].toJson() << endl;
            throw MLDB::Exception("really not sorted on input");
        }
    }

    if (!std::is_sorted(stats.begin(), stats.end(), FindPercentile()))
        throw Exception("stats not sorted on input");

    if (stats.empty())
        throw Exception("stats is empty");

    // Lower bound means strictly above
    auto it
        = std::lower_bound(stats.begin(), stats.end(), percentile,
                           FindPercentile());

    if (it == stats.begin())
        return *it;

    if (it == stats.end())
        return stats.back();

    BinaryStats upper = *it, lower = *std::prev(it);

    // Do an interpolation
    double atUpper = upper.proportionOfPopulation(),
           atLower = lower.proportionOfPopulation(),
           range = atUpper - atLower;

    ExcAssertLessEqual(percentile, atUpper);
    ExcAssertGreaterEqual(percentile, atLower);
    ExcAssertGreater(range, 0);

    double weight1 = (atUpper - percentile) / range;
    double weight2 = (percentile - atLower) / range;

    //cerr << "atUpper = " << atUpper << " atLower = " << atLower
    //     << " range = " << range << " weight1 = " << weight1
    //     << " weight2 = " << weight2 << endl;

    BinaryStats result;
    result.add(upper, weight2);
    result.add(lower, weight1);

    //cerr << "result prop = " << result.proportionOfPopulation() << endl;

    return result;
}

void
ScoredStats::
sort()
{
    // Go from highest to lowest score
    std::sort(entries.begin(), entries.end());
    isSorted = true;
}

void
ScoredStats::
calculate()
{
    BinaryStats current;

    for (unsigned i = 0;  i < entries.size();  ++i)
        current.counts[entries[i].label][false] += entries[i].weight;

    if (!isSorted)
        sort();

    bestF = current;
    bestMcc = current;

    double totalAuc = 0.0;

    stats.clear();

    // take the all point
    stats.push_back(BinaryStats(current, INFINITY));

    for (unsigned i = 0;  i < entries.size();  ++i) {
        const ScoredStats::ScoredEntry & entry = entries[i];

        if (i > 0 && entries[i - 1].score != entry.score) {
            totalAuc += current.rocAreaSince(stats.back());
            stats.push_back
                (BinaryStats(current, entries[i - 1].score, entry.key));

            if (current.f() > bestF.f())
                bestF = stats.back();
            if (current.mcc() > bestMcc.mcc())
                bestMcc = stats.back();
            if (current.specificity() > bestSpecificity.specificity())
                bestSpecificity = stats.back();

#if 0
            cerr << "entry " << i << ": score " << entries[i - 1].score
                 << " p " << current.precision() << " r " << current.recall()
                 << " f " << current.f() << " mcc " << current.mcc() << endl;
#endif
        }

        bool label = entry.label;

        // We transfer from a false positive to a true negative, or a
        // true positive to a false negative

        double weight = entry.weight;

        current.counts[label][false] -= weight;
        current.counts[label][true] += weight;

        current.unweighted_counts[label][false] -= 1;
        current.unweighted_counts[label][true] += 1;

    }

    totalAuc += current.rocAreaSince(stats.back());

    if (!entries.empty())
        stats.push_back(BinaryStats(current, entries.back().score));

    auc = totalAuc;
}

void
ScoredStats::
add(const ScoredStats & other)
{
    if (!isSorted)
        throw MLDB::Exception("attempt to add to non-sorted separation stats");
    if (!other.isSorted)
        throw MLDB::Exception("attempt to add non-sorted separation stats");

    size_t split = entries.size();
    entries.insert(entries.end(), other.entries.begin(), other.entries.end());
    std::inplace_merge(entries.begin(), entries.begin() + split,
                       entries.end());

    // If we had already calculated, we recalculate
    if (!stats.empty())
        calculate();
}

void
ScoredStats::
dumpRocCurveJs(std::ostream & stream) const
{
    if (stats.empty())
        throw MLDB::Exception("can't dump ROC curve without calling calculate()");

    stream << "this.data = {" << endl;
    stream << MLDB::format("  \"aroc\": %8.05f , ", auc) << endl;
    stream << "  \"model\":{";
    for(unsigned i = 0;  i < stats.size();  ++i) {
        const BinaryStats & x = stats[i];
        stream << MLDB::format("\n  \"%8.05f\": { ", x.threshold);
        stream << MLDB::format("\n  tpr : %8.05f,", x.recall());
        stream << MLDB::format("\n  accuracy : %8.05f,", x.accuracy());
        stream << MLDB::format("\n  precision : %8.05f,", x.precision());
        stream << MLDB::format("\n  fscore : %8.05f,", x.f());
        stream << MLDB::format("\n  fpr : %8.05f,", x.falsePositiveRate());
        stream << MLDB::format("\n  tp : %8.05f,", x.truePositives());
        stream << MLDB::format("\n  fp : %8.05f,", x.falsePositives());
        stream << MLDB::format("\n  fn : %8.05f,", x.falseNegatives());
        stream << MLDB::format("\n  tn : %8.05f,", x.trueNegatives());
        stream << MLDB::format("}");
        stream << ",";
    }
    stream << "\n}";
    stream << "};";
}

void
ScoredStats::
saveRocCurveJs(const std::string & filename) const
{
    filter_ostream stream(filename);
    dumpRocCurveJs(stream);
}

Json::Value
ScoredStats::
getRocCurveJson() const
{
    if (stats.empty())
        throw MLDB::Exception("can't dump ROC curve without calling calculate()");

    Json::Value modelJs;
    for(unsigned i = 0;  i < stats.size();  ++i) {
        const BinaryStats & x = stats[i];
        modelJs[MLDB::format("%8.05f", x.threshold)] = x.toJson();
    }

    Json::Value js;
    js["aroc"] = auc;
    js["model"] = modelJs;
    js["bestF1Score"] = bestF.toJson();
    js["bestMcc"] = bestMcc.toJson();

    return js;
}

void
ScoredStats::
saveRocCurveJson(const std::string & filename) const
{
    filter_ostream stream(filename);
    stream << getRocCurveJson().toStyledString() << endl;
}

Json::Value
ScoredStats::
toJson() const
{
    Json::Value result;
    result["auc"] = auc;
    result["bestF1Score"] = bestF.toJson();
    result["bestMcc"] = bestMcc.toJson();
    return result;
}

} // namespace MLDB


/* -*- c++ -*- */
/*
 * Copyright 2004,2006,2010-2012 Free Software Foundation, Inc.
 *
 * This file is part of GNU Radio
 *
 * GNU Radio is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * GNU Radio 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
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "correlate_access_code_tag_bb_impl.h"
#include <gnuradio/io_signature.h>
#include <boost/format.hpp>
#include <stdexcept>
#include <volk/volk.h>
#include <cstdio>
#include <iostream>

namespace gr {
  namespace digital {

    correlate_access_code_tag_bb::sptr
    correlate_access_code_tag_bb::make(const std::string &access_code,
				       int threshold,
				       const std::string &tag_name)
    {
      return gnuradio::get_initial_sptr
	(new correlate_access_code_tag_bb_impl(access_code,
					       threshold, tag_name));
    }

    correlate_access_code_tag_bb_impl::correlate_access_code_tag_bb_impl(
        const std::string &access_code, int threshold, const std::string &tag_name)
      : sync_block("correlate_access_code_tag_bb",
		      io_signature::make(1, 1, sizeof(char)),
		      io_signature::make(1, 1, sizeof(char))),
	d_data_reg(0), d_mask(0),
	d_threshold(threshold), d_len(0)
    {
      if(!set_access_code(access_code)) {
	GR_LOG_ERROR(d_logger, "access_code is > 64 bits");
	throw std::out_of_range ("access_code is > 64 bits");
      }

      std::stringstream str;
      str << name() << unique_id();
      d_me = pmt::string_to_symbol(str.str());
      d_key = pmt::string_to_symbol(tag_name);
    }

    correlate_access_code_tag_bb_impl::~correlate_access_code_tag_bb_impl()
    {
    }

    bool
    correlate_access_code_tag_bb_impl::set_access_code(
        const std::string &access_code)
    {
      gr::thread::scoped_lock l(d_mutex_access_code);

      d_len = access_code.length();	// # of bytes in string
      if(d_len > 64)
        return false;

      // set len bottom bits to 1.
      d_mask = ((~0ULL) >> (64 - d_len));

      d_access_code = 0;
      for(unsigned i=0; i < d_len; i++){
        d_access_code = (d_access_code << 1) | (access_code[i] & 1);
      }

      GR_LOG_DEBUG(d_logger, boost::format("Access code: %llx") % d_access_code);
      GR_LOG_DEBUG(d_logger, boost::format("Mask: %llx") % d_mask);

      return true;
    }

    int
    correlate_access_code_tag_bb_impl::work(int noutput_items,
					    gr_vector_const_void_star &input_items,
					    gr_vector_void_star &output_items)
    {
      gr::thread::scoped_lock l(d_mutex_access_code);

      const unsigned char *in = (const unsigned char*)input_items[0];
      unsigned char *out = (unsigned char*)output_items[0];

      uint64_t abs_out_sample_cnt = nitems_written(0);

      for(int i = 0; i < noutput_items; i++) {
	out[i] = in[i];

	// compute hamming distance between desired access code and current data
	uint64_t wrong_bits = 0;
	uint64_t nwrong = d_threshold+1;

	wrong_bits  = (d_data_reg ^ d_access_code) & d_mask;
	volk_64u_popcnt(&nwrong, wrong_bits);

	// shift in new data
	d_data_reg = (d_data_reg << 1) | (in[i] & 0x1);
	if(nwrong <= d_threshold) {
	  GR_LOG_DEBUG(d_logger, boost::format("writing tag at sample %llu") % (abs_out_sample_cnt + i));
	  add_item_tag(0, //stream ID
		       abs_out_sample_cnt + i, //sample
		       d_key,      //frame info
		       pmt::from_long(nwrong), //data (number wrong)
		       d_me        //block src id
		       );
	}
      }

      return noutput_items;
    }

  } /* namespace digital */
} /* namespace gr */


// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include "arrow/util/decimal.h"

#include <boost/regex.hpp>

namespace arrow {
namespace decimal {

static const boost::regex DECIMAL_PATTERN("(\\+?|-?)((0*)(\\d*))(\\.(\\d+))?");

template <typename T>
ARROW_EXPORT Status FromString(
    const std::string& s, Decimal<T>* out, int* precision, int* scale) {
  if (s.empty()) {
    return Status::Invalid("Empty string cannot be converted to decimal");
  }
  boost::smatch match;
  if (!boost::regex_match(s, match, DECIMAL_PATTERN)) {
    std::stringstream ss;
    ss << "String " << s << " is not a valid decimal string";
    return Status::Invalid(ss.str());
  }
  const int8_t sign = match[1].str() == "-" ? -1 : 1;
  std::string whole_part = match[4].str();
  std::string fractional_part = match[6].str();
  if (scale != nullptr) { *scale = static_cast<int>(fractional_part.size()); }
  if (precision != nullptr) {
    *precision =
        static_cast<int>(whole_part.size()) + static_cast<int>(fractional_part.size());
  }
  if (out != nullptr) { StringToInteger(whole_part, fractional_part, sign, &out->value); }
  return Status::OK();
}

template ARROW_EXPORT Status FromString(
    const std::string& s, Decimal32* out, int* precision, int* scale);
template ARROW_EXPORT Status FromString(
    const std::string& s, Decimal64* out, int* precision, int* scale);
template ARROW_EXPORT Status FromString(
    const std::string& s, Decimal128* out, int* precision, int* scale);

void StringToInteger(
    const std::string& whole, const std::string& fractional, int8_t sign, int32_t* out) {
  DCHECK(sign == -1 || sign == 1);
  DCHECK_NE(out, nullptr);
  DCHECK(!whole.empty() || !fractional.empty());
  if (!whole.empty()) {
    *out = std::stoi(whole, nullptr, 10) *
           static_cast<int32_t>(pow(10.0, static_cast<double>(fractional.size())));
  }
  if (!fractional.empty()) { *out += std::stoi(fractional, nullptr, 10); }
  *out *= sign;
}

void StringToInteger(
    const std::string& whole, const std::string& fractional, int8_t sign, int64_t* out) {
  DCHECK(sign == -1 || sign == 1);
  DCHECK_NE(out, nullptr);
  DCHECK(!whole.empty() || !fractional.empty());
  if (!whole.empty()) {
    *out = static_cast<int64_t>(std::stoll(whole, nullptr, 10)) *
           static_cast<int64_t>(pow(10.0, static_cast<double>(fractional.size())));
  }
  if (!fractional.empty()) { *out += std::stoll(fractional, nullptr, 10); }
  *out *= sign;
}

void StringToInteger(
    const std::string& whole, const std::string& fractional, int8_t sign, int128_t* out) {
  DCHECK(sign == -1 || sign == 1);
  DCHECK_NE(out, nullptr);
  DCHECK(!whole.empty() || !fractional.empty());
  *out = int128_t(whole + fractional) * sign;
}

void FromBytes(const uint8_t* bytes, Decimal32* decimal) {
  DCHECK_NE(bytes, nullptr);
  DCHECK_NE(decimal, nullptr);
  decimal->value = *reinterpret_cast<const int32_t*>(bytes);
}

void FromBytes(const uint8_t* bytes, Decimal64* decimal) {
  DCHECK_NE(bytes, nullptr);
  DCHECK_NE(decimal, nullptr);
  decimal->value = *reinterpret_cast<const int64_t*>(bytes);
}

constexpr static const size_t BYTES_IN_128_BITS = 128 / CHAR_BIT;
constexpr static const size_t LIMB_SIZE =
    sizeof(std::remove_pointer<int128_t::backend_type::limb_pointer>::type);
constexpr static const size_t BYTES_PER_LIMB = BYTES_IN_128_BITS / LIMB_SIZE;

void FromBytes(const uint8_t* bytes, bool is_negative, Decimal128* decimal) {
  DCHECK_NE(bytes, nullptr);
  DCHECK_NE(decimal, nullptr);

  auto& decimal_value(decimal->value);
  int128_t::backend_type& backend(decimal_value.backend());
  backend.resize(BYTES_PER_LIMB, BYTES_PER_LIMB);
  std::memcpy(backend.limbs(), bytes, BYTES_IN_128_BITS);
  if (is_negative) { decimal->value = -decimal->value; }
}

void ToBytes(const Decimal32& value, uint8_t** bytes) {
  DCHECK_NE(*bytes, nullptr);
  *reinterpret_cast<int32_t*>(*bytes) = value.value;
}

void ToBytes(const Decimal64& value, uint8_t** bytes) {
  DCHECK_NE(*bytes, nullptr);
  *reinterpret_cast<int64_t*>(*bytes) = value.value;
}

void ToBytes(const Decimal128& decimal, uint8_t** bytes, bool* is_negative) {
  DCHECK_NE(*bytes, nullptr);
  DCHECK_NE(is_negative, nullptr);

  /// TODO(phillipc): boost multiprecision is unreliable here, int128_t can't be
  /// roundtripped
  const auto& backend(decimal.value.backend());
  auto boost_bytes = reinterpret_cast<const uint8_t*>(backend.limbs());
  std::memcpy(*bytes, boost_bytes, BYTES_IN_128_BITS);
  *is_negative = backend.isneg();
}

}  // namespace decimal
}  // namespace arrow


// Copyright (c) 2012-2013 The PPCoin developers
// Copyright (c) 2014 The BlackCoin developers
// Copyright (c) 2018 The NIX Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp>

#include <pos/kernel.h>
#include <txdb.h>
#include <validation.h>
#include <chainparams.h>
#include <serialize.h>
#include <streams.h>
#include <hash.h>
#include <script/interpreter.h>
#include <script/script.h>
#include <script/ismine.h> // valtype
#include <policy/policy.h>
#include <consensus/validation.h>
#include <coins.h>

/**
 * Stake Modifier (hash modifier of proof-of-stake):
 * The purpose of stake modifier is to prevent a txout (coin) owner from
 * computing future proof-of-stake generated by this txout at the time
 * of transaction confirmation. To meet kernel protocol, the txout
 * must hash with a future stake modifier to generate the proof.
 */
uint256 ComputeStakeModifierV2(const CBlockIndex *pindexPrev, const uint256 &kernel)
{
    if (!pindexPrev)
        return uint256();  // genesis block's modifier is 0

    CDataStream ss(SER_GETHASH, 0);
    ss << kernel << pindexPrev->bnStakeModifier;
    return Hash(ss.begin(), ss.end());
}

/**
 * BlackCoin kernel protocol
 * coinstake must meet hash target according to the protocol:
 * kernel (input 0) must meet the formula
 *     hash(nStakeModifier + txPrev.block.nTime + txPrev.nTime + txPrev.vout.hash + txPrev.vout.n + nTime) < bnTarget * nWeight
 * this ensures that the chance of getting a coinstake is proportional to the
 * amount of coins one owns.
 * The reason this hash is chosen is the following:
 *   nStakeModifier: scrambles computation to make it very difficult to precompute
 *                   future proof-of-stake
 *   txPrev.block.nTime: prevent nodes from guessing a good timestamp to
 *                       generate transaction for future advantage,
 *                       obsolete since v3
 *   txPrev.nTime: slightly scrambles computation
 *   txPrev.vout.hash: hash of txPrev, to reduce the chance of nodes
 *                     generating coinstake at the same time
 *   txPrev.vout.n: output number of txPrev, to reduce the chance of nodes
 *                  generating coinstake at the same time
 *   nTime: current timestamp
 *   block/tx hash should not be used here as they can be generated in vast
 *   quantities so as to generate blocks faster, degrading the system back into
 *   a proof-of-work situation.
 */
bool CheckStakeKernelHash(const CBlockIndex *pindexPrev,
    uint32_t nBits, uint32_t nBlockFromTime,
    CAmount prevOutAmount, const COutPoint &prevout, uint32_t nTime,
    uint256 &hashProofOfStake, uint256 &targetProofOfStake,
    bool fPrintProofOfStake)
{
    // CheckStakeKernelHashV2

    if (nTime < nBlockFromTime)  // Transaction timestamp violation
        return error("%s: nTime violation", __func__);

    arith_uint256 bnTarget;
    bool fNegative;
    bool fOverflow;

    bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
    if (fNegative || fOverflow || bnTarget == 0)
        return error("%s: SetCompact failed.", __func__);

    // Weighted target
    int64_t nValueIn = prevOutAmount;
    arith_uint256 bnWeight = arith_uint256(nValueIn);
    bnTarget *= bnWeight;

    targetProofOfStake = ArithToUint256(bnTarget);

    uint256 bnStakeModifier = pindexPrev->bnStakeModifier;

    CDataStream ss(SER_GETHASH, 0);
    ss << bnStakeModifier;
    ss << nBlockFromTime << prevout.hash << prevout.n << nTime;
    hashProofOfStake = Hash(ss.begin(), ss.end());

    /*
    LogPrintf("CheckStakeKernelHash(): \n"
              "nValue=%llf, \n"
              "bnTarget=%s > hashProofOfStake=%s \n"
              "bnStakeModifier =%s\n"
              "prevout hash=%s\n"
              "prevout n=%d\n"
              "block from time =%d\n"
              "current block time =%d\n"
              , nValueIn/COIN, bnTarget.ToString(), hashProofOfStake.ToString(), bnStakeModifier.ToString(), prevout.hash.ToString(), prevout.n, nBlockFromTime, nTime);
    */
    // Now check if proof-of-stake hash meets target protocol
    if (UintToArith256(hashProofOfStake) > bnTarget)
        return false;

    return true;
}

bool IsConfirmedInNPrevBlocks(const uint256 &hashBlock, const CBlockIndex *pindexFrom, int nMaxDepth, int &nActualDepth)
{
    for (const CBlockIndex *pindex = pindexFrom; pindex && pindexFrom->nHeight - pindex->nHeight < nMaxDepth; pindex = pindex->pprev)
    if (hashBlock == pindex->GetBlockHash())
    {
        nActualDepth = pindexFrom->nHeight - pindex->nHeight;
        return true;
    };

    return false;
}

static bool CheckAge(const CBlockIndex *pindexTip, const uint256 &hashKernelBlock, int &nDepth)
{
    // pindexTip is the current tip of the chain
    // hashKernelBlock is the hash of the block containing the kernel transaction

    int nRequiredDepth = pindexTip->nHeight + 1 >= Params().GetConsensus().nStartGhostFeeDistribution ?
                COINBASE_MATURITY_V2 : COINBASE_MATURITY;

    bool fTestNet = (Params().NetworkIDString() == CBaseChainParams::TESTNET);
    if(fTestNet)
        nRequiredDepth = COINBASE_MATURITY_TESTNET;

    if (IsConfirmedInNPrevBlocks(hashKernelBlock, pindexTip, nRequiredDepth, nDepth))
        return false;
    return true;
}

// Check kernel hash target and coinstake signature
bool CheckProofOfStake(const CBlockIndex *pindexPrev, const CTransaction &tx, int64_t nTime, unsigned int nBits, uint256 &hashProofOfStake, uint256 &targetProofOfStake)
{
    // pindexPrev is the current tip, the block the new block will connect on
    // nTime is the time of the new/next block
    CValidationState state;

    if (!tx.IsCoinStake()
        || tx.vin.size() < 1)
        return state.DoS(100, error("%s: malformed-txn %s", __func__, tx.GetHash().ToString()), REJECT_INVALID, "malformed-txn");

    uint256 hashBlock;
    CTransactionRef txPrev;

    // Kernel (input 0) must match the stake hash target per coin age (nBits)
    const CTxIn &txin = tx.vin[0];

    uint32_t nBlockFromTime;
    int nDepth;
    CScript kernelPubKey;
    CAmount amount;

    Coin coin;
    if (!pcoinsTip->GetCoin(txin.prevout, coin) || coin.IsSpent())
    {
        // Must find the prevout in the txdb / blocks

        CBlock blockKernel; // block containing stake kernel, GetTransaction should only fill the header.
        if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), blockKernel, true)
            || txin.prevout.n >= txPrev->vout.size())
            return state.DoS(10, error("%s: prevout-not-in-chain", __func__), REJECT_INVALID, "prevout-not-in-chain");

        const CTxOut outPrev = txPrev->vout[txin.prevout.n];

        int nDepth;
        if (!CheckAge(pindexPrev, hashBlock, nDepth))
            return state.DoS(100, error("%s: Tried to stake at depth %d", __func__, nDepth + 1), REJECT_INVALID, "invalid-stake-depth");

        kernelPubKey = outPrev.scriptPubKey;
        amount = outPrev.nValue;
        nBlockFromTime = blockKernel.nTime;
    } else
    {
        CBlockIndex *pindex = chainActive[coin.nHeight];
        if (!pindex)
            return state.DoS(100, error("%s: invalid-prevout", __func__), REJECT_INVALID, "invalid-prevout");

        nDepth = pindexPrev->nHeight - coin.nHeight;

        int nRequiredDepth = pindexPrev->nHeight + 1 >= Params().GetConsensus().nStartGhostFeeDistribution ?
                    COINBASE_MATURITY_V2 : COINBASE_MATURITY;

        bool fTestNet = (Params().NetworkIDString() == CBaseChainParams::TESTNET);
        if(fTestNet)
            nRequiredDepth = COINBASE_MATURITY_TESTNET;

        if (nRequiredDepth > nDepth)
            return state.DoS(100, error("%s: Tried to stake at depth %d", __func__, nDepth + 1), REJECT_INVALID, "invalid-stake-depth");

        kernelPubKey = coin.out.scriptPubKey;
        amount = coin.out.nValue;
        nBlockFromTime = pindex->GetBlockTime();
    };

    const CScript &scriptSig = txin.scriptSig;
    const CScriptWitness *witness = &txin.scriptWitness;
    ScriptError serror = SCRIPT_ERR_OK;
    // Redundant: all inputs are checked later during CheckInputs
    if (!VerifyScript(scriptSig, kernelPubKey, witness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&tx, 0, amount), &serror))
        return state.DoS(100, error("%s: verify-script-failed, txn %s, reason %s", __func__, tx.GetHash().ToString(), ScriptErrorString(serror)),
            REJECT_INVALID, "verify-script-failed");

    if (!CheckStakeKernelHash(pindexPrev, nBits, nBlockFromTime,
        amount, txin.prevout, nTime, hashProofOfStake, targetProofOfStake, LogAcceptCategory(BCLog::POS)))
        return state.DoS(1, // may occur during initial download or if behind on block chain sync
            error("%s: INFO: check kernel failed on coinstake %s, hashProof=%s", __func__, tx.GetHash().ToString(), hashProofOfStake.ToString()),
            REJECT_INVALID, "check-kernel-failed");

    // Ensure the input scripts all match and that the total output value to the input script is not less than the total input value.
    // Leaving a window for compromised staking nodes to reassign the blockreward to an attacker's address.
    // If coin owners detect this, they can move their coin to a new address.

    //Check if delegate service is charging a fee and is just
    if (HasIsCoinstakeOp(kernelPubKey))
    {
        // Sum value from any extra inputs and check script is the same
        for (size_t k = 1; k < tx.vin.size(); ++k)
        {
            const CTxIn &txin = tx.vin[k];
            Coin coin;
            if (!pcoinsTip->GetCoin(txin.prevout, coin) || coin.IsSpent())
            {
                if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), hashBlock, true)
                    || txin.prevout.n >= txPrev->vout.size())
                    return state.DoS(1, error("%s: prevout-not-in-chain %d", __func__, k), REJECT_INVALID, "prevout-not-in-chain");

                const CTxOut outPrev = txPrev->vout[txin.prevout.n];

                if (kernelPubKey != outPrev.scriptPubKey)
                    return state.DoS(100, error("%s: mixed-prevout-scripts %d", __func__, k), REJECT_INVALID, "mixed-prevout-scripts");
                amount += outPrev.nValue;

                LogPrint(BCLog::POS, "%s: Input %d of coinstake %s is spent.", k, tx.GetHash().ToString());
            } else
            {
                if (kernelPubKey != coin.out.scriptPubKey)
                    return state.DoS(100, error("%s: mixed-prevout-scripts %d", __func__, k), REJECT_INVALID, "mixed-prevout-scripts");
                amount += coin.out.nValue;
            }
        }

        // Get block reward
        CAmount nReward = Params().GetProofOfStakeReward(pindexPrev, 0);
        if (nReward < 0)
            return false;

        // Check if contract allows fee payouts
        int64_t feeOut = 0;
        CAmount feeAmount = 0;
        if(GetCoinstakeScriptFee(kernelPubKey, feeOut)){
            double feePercent = (double)feeOut;
            if(feeOut > 10000 || feeOut < 0){
                return state.DoS(100, error("%s: GetCoinstakeScriptFee-failed, txn %s", __func__, tx.GetHash().ToString()),
                    REJECT_INVALID, "GetCoinstakeScriptFee-failed");
            }
            feePercent /= 100;
            amount += nReward * (double)((100.0 - feePercent)/100.0);
            feeAmount = nReward * ((feePercent)/100);
        }
        else
            amount += nReward;

        CScript scriptOut;
        bool hasScriptFeeAddress = false;
        bool foundFeeAddress = true;
        if(GetCoinstakeScriptFeeRewardAddress(kernelPubKey, scriptOut)){
            hasScriptFeeAddress = true;
            foundFeeAddress = false;
        }

        CAmount nVerify = 0;
        for (const auto &txout : tx.vout)
        {
            const CScript pOutPubKey = txout.scriptPubKey;

            if (pOutPubKey == kernelPubKey)
                nVerify += txout.nValue;

            //Check for delegate fee address payout
            if(hasScriptFeeAddress){
                if(scriptOut == pOutPubKey && feeAmount == txout.nValue)
                    foundFeeAddress = true;
            }
        }

        if (nVerify < amount)
            return state.DoS(100, error("%s: verify-amount-script-failed, txn %s", __func__, tx.GetHash().ToString()),
                REJECT_INVALID, "verify-amount-script-failed");

        if (!foundFeeAddress)
            return state.DoS(100, error("%s: foundFeeAddress-failed, txn %s", __func__, tx.GetHash().ToString()),
                REJECT_INVALID, "foundFeeAddress-failed");
    }

    return true;
}

// Check whether the coinstake timestamp meets protocol
bool CheckCoinStakeTimestamp(int nHeight, int64_t nTimeBlock)
{
    return (nTimeBlock & Params().GetStakeTimestampMask(nHeight)) == 0;
}

bool CheckKernel(const CBlockIndex *pindexPrev, unsigned int nBits, int64_t nTime, const COutPoint &prevout, int64_t *pBlockTime)
{
    uint256 hashProofOfStake, targetProofOfStake;

    Coin coin;
    if (!pcoinsTip->GetCoin(prevout, coin))
        return error("%s: prevout not found", __func__);
    if (coin.IsSpent())
        return error("%s: prevout is spent", __func__);

    CBlockIndex *pindex = chainActive[coin.nHeight];
    if (!pindex)
        return false;

    int coinbaseMaturity = chainActive.Height() >= Params().GetConsensus().nCoinMaturityReductionHeight ?
                COINBASE_MATURITY_V2 : COINBASE_MATURITY;

    bool fTestNet = (Params().NetworkIDString() == CBaseChainParams::TESTNET);
    if(fTestNet)
        coinbaseMaturity = COINBASE_MATURITY_TESTNET;

    int nRequiredDepth = (int)(coinbaseMaturity-1);

    int nDepth = pindexPrev->nHeight - coin.nHeight;

    if (nRequiredDepth > nDepth)
        return false;

    if (pBlockTime)
        *pBlockTime = pindex->GetBlockTime();

    CAmount amount = coin.out.nValue;
    return CheckStakeKernelHash(pindexPrev, nBits, *pBlockTime,
        amount, prevout, nTime, hashProofOfStake, targetProofOfStake);
}


//
// Copyright (c) 2017 CNRS
//
// This file is part of tsid
// tsid is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
// tsid 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 GNU
// General Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// tsid If not, see
// <http://www.gnu.org/licenses/>.
//

#ifndef SOLVERABSTRACT_HH_
#define SOLVERABSTRACT_HH_

#include <hpp/bezier-com-traj/local_config.hh>
#include <Eigen/Dense>

namespace solvers {

/**
 * Possible states of the solver.
 */
enum optim_status { OPTIM_OPTIMAL = 0, OPTIM_INFEASIBLE = 1 };

static const double UNBOUNDED_UP = 100000.;
static const double UNBOUNDED_DOWN = -100000.;

typedef Eigen::MatrixXd MatrixXd;
typedef Eigen::VectorXd VectorXd;
typedef Eigen::VectorXi VectorXi;
typedef const Eigen::Ref<const VectorXd>& Cref_vectorX;

enum BEZIER_COM_TRAJ_DLLAPI SolverType {
  SOLVER_QUADPROG = 0x00001
// SOLVER_QUADPROG_SPARSE  = 0x00002
#ifdef USE_GLPK_SOLVER
  ,
  SOLVER_GLPK = 0x00002
#endif
};

/**
 * @brief Struct used to return the results of the trajectory generation
 * problem.
 */
struct BEZIER_COM_TRAJ_DLLAPI ResultData {
  ResultData() : success_(false), cost_(-1.), x(VectorXd::Zero(0)) {}

  ResultData(const bool success, const double cost, Cref_vectorX x) : success_(success), cost_(cost), x(x) {}

  ResultData(const ResultData& other) : success_(other.success_), cost_(other.cost_), x(other.x) {}
  ~ResultData() {}

  ResultData& operator=(const ResultData& other) {
    success_ = (other.success_);
    cost_ = (other.cost_);
    x = (other.x);
    return *this;
  }
  bool success_;  // whether the optimization was successful
  double cost_;   // cost evaluation for the solved control point
  VectorXd x;     // control point
};

// min g'x
// st  CIx <= ci0
//     CEx  = ce0
/**
 * @brief solve Solve a QP or LP given
 * init position and velocity, 0 velocity constraints (acceleration constraints are ignored)
 * @param pData problem Data. Should contain only one contact phase.
 * @param Ts timelength of each contact phase. Should only contain one value
 * @param timeStep time that the solver has to stop.
 * @return ResultData a struct containing the resulting trajectory, if success is true.
 */
ResultData BEZIER_COM_TRAJ_DLLAPI solve(const MatrixXd& A, const VectorXd& b, const MatrixXd& D, const VectorXd& d,
                                        const MatrixXd& Hess, const VectorXd& g, const VectorXd& initGuess,
                                        Cref_vectorX minBounds, Cref_vectorX maxBounds, const SolverType solver);

} /* namespace solvers */

#endif /* SOLVERABSTRACT_HH_ */


#ifndef PHASER_TYPES
#define PHASER_TYPES

#include <vector>

#include <boost/smart_ptr.hpp>
#include <scitbx/vec3.h>
#include <scitbx/mat3.h>
#include <scitbx/array_family/shared.h>
#include <scitbx/array_family/misc_functions.h>

namespace phaser { namespace af = scitbx::af; }
namespace phaser { namespace fn = scitbx::fn; }
typedef double floatType;

namespace phaser {

    typedef std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<floatType> > > > > > float6D;
    typedef std::vector<std::vector<std::vector<std::vector<std::vector<floatType> > > > > float5D;
    typedef std::vector<std::vector<std::vector<std::vector<floatType> > > > float4D;
    typedef std::vector<std::vector<std::vector<floatType> > > float3D;
    typedef std::vector<std::vector<floatType> > float2D;
    typedef std::vector<floatType> float1D;

    typedef std::complex<floatType> cmplxType;
    typedef std::vector<std::vector<std::vector<std::vector<cmplxType> > > > cmplx4D;
    typedef std::vector<std::vector<std::vector<cmplxType> > > cmplx3D;
    typedef std::vector<std::vector<cmplxType> > cmplx2D;
    typedef std::vector<cmplxType> cmplx1D;

    typedef std::vector<std::vector<std::vector<std::vector<bool> > > > bool4D;
    typedef std::vector<std::vector<std::vector<bool> > > bool3D;
    typedef std::vector<std::vector<bool> > bool2D;
    typedef std::vector<bool> bool1D;

    typedef std::vector<std::vector<std::vector<std::vector<unsigned> > > > unsigned4D;
    typedef std::vector<std::vector<std::vector<unsigned> > > unsigned3D;
    typedef std::vector<std::vector<unsigned> > unsigned2D;
    typedef std::vector<unsigned> unsigned1D;

    typedef std::vector<std::vector<std::vector<std::vector<std::string> > > > string4D;
    typedef std::vector<std::vector<std::vector<std::string> > > string3D;
    typedef std::vector<std::vector<std::string> > string2D;
    typedef std::vector<std::string> string1D;

    typedef std::vector<std::vector<std::vector<std::vector<int> > > > int4D;
    typedef std::vector<std::vector<std::vector<int> > > int3D;
    typedef std::vector<std::vector<int> > int2D;
    typedef std::vector<int> int1D;

    typedef scitbx::vec3<floatType> dvect3;
    typedef scitbx::mat3<floatType> dmat33;
    typedef scitbx::vec3<int> ivect3;
    typedef scitbx::mat3<int> imat33;

    typedef double dFloatType;
    typedef std::vector<std::vector<std::vector<std::vector<dFloatType> > > > dFloat4D;
    typedef std::vector<std::vector<std::vector<dFloatType> > > dFloat3D;
    typedef std::vector<std::vector<dFloatType> > dFloat2D;
    typedef std::vector<dFloatType> dFloat1D;

    typedef std::complex<double> dCmplxType;
    typedef std::vector<std::vector<std::vector<std::vector<dCmplxType> > > > dCmplx4D;
    typedef std::vector<std::vector<std::vector<dCmplxType> > > dCmplx3D;
    typedef std::vector<std::vector<dCmplxType> > dCmplx2D;
    typedef std::vector<dCmplxType> dCmplx1D;

}

#endif


// 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_STRATEGIES_BUFFER_JOIN_ROUND_HPP
#define BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_JOIN_ROUND_HPP

#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/math.hpp>

#include <boost/geometry/extensions/strategies/buffer_side.hpp>

#define BOOST_GEOMETRY_BUFFER_NO_HELPER_POINTS

namespace boost { namespace geometry
{

namespace strategy { namespace buffer
{

template<typename PointOut>
struct join_round2
{
    typedef PointOut vector_type;

    template <typename Vector, typename Point1, typename Point2>
    static inline Vector create_vector(Point1 const& p1, Point2 const& p2)
    {
        Vector v;
        geometry::convert(p1, v);
        subtract_point(v, p2);
        return v;
    }

    inline join_round2(int max_level = 4)
        : m_max_level(max_level)
    {}

    typedef typename coordinate_type<PointOut>::type coordinate_type;
    int m_max_level;

    template <typename OutputIterator, typename Point, typename PointP, typename Point1, typename Point2>
    inline void mid_points(Point const& vertex, PointP const& perpendicular,
                Point1 const& p1, Point2 const& p2,
                coordinate_type const& buffer_distance,
                coordinate_type const& max_distance,
                OutputIterator out,
                int level = 1) const
    {
        // Generate 'vectors'
        coordinate_type vp1_x = get<0>(p1) - get<0>(vertex);
        coordinate_type vp1_y = get<1>(p1) - get<1>(vertex);

        coordinate_type vp2_x = (get<0>(p2) - get<0>(vertex));
        coordinate_type vp2_y = (get<1>(p2) - get<1>(vertex));

        // Average them to generate vector in between
        coordinate_type two = 2;
        coordinate_type v_x = (vp1_x + vp2_x) / two;
        coordinate_type v_y = (vp1_y + vp2_y) / two;

        coordinate_type between_length = sqrt(v_x * v_x + v_y * v_y);

        coordinate_type const positive_buffer_distance = geometry::math::abs(buffer_distance);
        coordinate_type prop = positive_buffer_distance / between_length;

        PointOut mid_point;
        set<0>(mid_point, get<0>(vertex) + v_x * prop);
        set<1>(mid_point, get<1>(vertex) + v_y * prop);

        if (buffer_distance > max_distance)
        {
            // Calculate point projected on original perpendicular segment,
            // using vector maths
            vector_type v = create_vector<vector_type>(perpendicular, vertex);
            vector_type w = create_vector<vector_type>(mid_point, vertex);

            coordinate_type c1 = dot_product(w, v);
            if (c1 > 0)
            {
                coordinate_type c2 = dot_product(v, v);
                if (c2 > c1)
                {
                    coordinate_type b = c1 / c2;

                    PointOut projected_point;

                    multiply_value(v, b);
                    geometry::convert(vertex, projected_point);
                    add_point(projected_point, v);

                    coordinate_type projected_distance = geometry::distance(projected_point, mid_point);

                    if (projected_distance > max_distance)
                    {
                        // Do not generate from here on.
                        return;
                    }
                }
            }
        }

        if (level < m_max_level)
        {
            mid_points(vertex, perpendicular, p1, mid_point, positive_buffer_distance, max_distance, out, level + 1);
        }
        *out++ = mid_point;
        if (level < m_max_level)
        {
            mid_points(vertex, perpendicular, mid_point, p2, positive_buffer_distance, max_distance, out, level + 1);
        }
    }

    template <typename OutputIterator, typename Point, typename Point2>
    inline OutputIterator apply(Point const& vertex,
                Point2 const& perpendicular,
                Point2 const& p1, Point2 const& p2,
                coordinate_type const& buffer_distance,
                coordinate_type const& max_distance,
                OutputIterator out) const
    {
        mid_points(vertex, perpendicular, p1, p2, buffer_distance, max_distance, out);
        return out;
    }
};

template<typename PointOut>
struct join_none
{
    template <typename OutputIterator, typename Point, typename Point2,
        typename DistanceType>
    inline OutputIterator apply(Point const& ,
                Point2 const& ,
                Point2 const& , Point2 const& ,
                DistanceType const& ,
                DistanceType const& ,
                OutputIterator out) const
    {
        return out;
    }
};

}} // namespace strategy::buffer

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_JOIN_ROUND_HPP