/*

Copyright (c) 2005-2015, University of Oxford.
All rights reserved.

University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.

This file is part of Chaste.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 * Neither the name of the University of Oxford nor the names of its
   contributors may be used to endorse or promote products derived from this
   software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TESTALARCON2004OXYGENBASEDCELLCYCLEODESYSTEM_HPP_
#define TESTALARCON2004OXYGENBASEDCELLCYCLEODESYSTEM_HPP_

#include <cxxtest/TestSuite.h>

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <stdio.h>
#include <vector>
#include <iostream>

#include "OutputFileHandler.hpp"

#include "Alarcon2004OxygenBasedCellCycleOdeSystem.hpp"
#include "RungeKutta4IvpOdeSolver.hpp"
#include "RungeKuttaFehlbergIvpOdeSolver.hpp"
#include "BackwardEulerIvpOdeSolver.hpp"
#include "Timer.hpp"

#include "FakePetscSetup.hpp"

/**
 * This class contains tests for Alarcon2004OxygenBasedCellCycleOdeSystem,
 * a system of ODEs that are used by the cell-cycle model
 * Alarcon2004OxygenBasedCellCycleModel to determine when a cell is ready
 * to divide.
 */
class TestAlarcon2004OxygenBasedCellCycleOdeSystem : public CxxTest::TestSuite
{
public:

    /**
     * Test derivative calculations (correct values calculated using Matlab).
     */
    void TestAlarcon2004Equations()
    {
        // Set up
        double time = 0.0;
        double oxygen_concentration = 1.0;

        Alarcon2004OxygenBasedCellCycleOdeSystem normal_system(oxygen_concentration, false);
        Alarcon2004OxygenBasedCellCycleOdeSystem cancer_system(oxygen_concentration, true);

        std::vector<double> initial_conditions = normal_system.GetInitialConditions();

        std::vector<double> normal_derivs(initial_conditions.size());
        std::vector<double> cancer_derivs(initial_conditions.size());
        normal_system.EvaluateYDerivatives(time, initial_conditions, normal_derivs);
        cancer_system.EvaluateYDerivatives(time, initial_conditions, cancer_derivs);

        /**
         * Test derivatives are correct initially
         * (correct values calculated using Matlab code)
         */

        // Normal cell
        TS_ASSERT_DELTA(normal_derivs[0], 455.630699088, 1e-5);
        TS_ASSERT_DELTA(normal_derivs[1], 1.83000000000, 1e-5);
        TS_ASSERT_DELTA(normal_derivs[2], 3.00000000000, 1e-5);
        TS_ASSERT_DELTA(normal_derivs[3], 1.50000000000, 1e-5);
        TS_ASSERT_DELTA(normal_derivs[4], -5.4060000000, 1e-5);
        TS_ASSERT_DELTA(normal_derivs[5], 0.00000000000, 1e-5);

        // Cancer cell
        TS_ASSERT_DELTA(cancer_derivs[0], 455.630699088, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs[1], 1.83600000000, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs[2], 0.42000000000, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs[3], 1.50000000000, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs[4], -5.4060000000, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs[5], 0.00000000000, 1e-5);

        /**
         * Again test derivatives are correct initially, but for
         * different initial conditions (corresponding to a low
         * oxygen concentration). The usual initial condition for
         * z is zero, so we need to change it to see any difference.
         */
        oxygen_concentration = 0.1;

        Alarcon2004OxygenBasedCellCycleOdeSystem normal_system2(oxygen_concentration, false);
        Alarcon2004OxygenBasedCellCycleOdeSystem cancer_system2(oxygen_concentration, true);

        std::vector<double> normal_derivs2(initial_conditions.size());
        normal_system2.SetDefaultInitialCondition(2, 0.1);

        std::vector<double> cancer_derivs2(initial_conditions.size());
        cancer_system2.SetDefaultInitialCondition(2, 0.1);

        std::vector<double> initial_conditions2 = normal_system2.GetInitialConditions();

        normal_system2.EvaluateYDerivatives(time, initial_conditions2, normal_derivs2);
        cancer_system2.EvaluateYDerivatives(time, initial_conditions2, cancer_derivs2);

        // Normal cell
        TS_ASSERT_DELTA(normal_derivs2[0], 455.630699088, 1e-5);
        TS_ASSERT_DELTA(normal_derivs2[1], 1.81500000000, 1e-5);
        TS_ASSERT_DELTA(normal_derivs2[2], 2.94545454545, 1e-5);
        TS_ASSERT_DELTA(normal_derivs2[3], 1.50000000000, 1e-5);
        TS_ASSERT_DELTA(normal_derivs2[4], -5.4060000000, 1e-5);
        TS_ASSERT_DELTA(normal_derivs2[5], 0.00000000000, 1e-5);

        // Cancer cell
        TS_ASSERT_DELTA(cancer_derivs2[0], 455.630699088, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs2[1], 1.82100000000, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs2[2], 0.36545454545, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs2[3], 1.50000000000, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs2[4], -5.4060000000, 1e-5);
        TS_ASSERT_DELTA(cancer_derivs2[5], 0.00000000000, 1e-5);
    }

    /**
     * Test two ODE solvers with this ODE system (correct values calculated using the Matlab solver ode15s).
     *
     */
    void TestAlarcon2004Solver() throw(Exception)
    {
        // Set up
        double oxygen_concentration = 1.0;
        Alarcon2004OxygenBasedCellCycleOdeSystem alarcon_system(oxygen_concentration, false);

        // Create ODE solvers
        RungeKutta4IvpOdeSolver rk4_solver;
        RungeKuttaFehlbergIvpOdeSolver rkf_solver;
        BackwardEulerIvpOdeSolver back_solver(6);

        // Set up for solver
        OdeSolution solutions;
        std::vector<double> initial_conditions = alarcon_system.GetInitialConditions();
        double h_value = 1e-4; // maximum tolerance

        // Solve the ODE system using a Runge Kutta fourth order solver
        Timer::Reset();
        solutions = rk4_solver.Solve(&alarcon_system, initial_conditions, 0.0, 10.0, h_value, h_value);
        Timer::Print("1. Runge-Kutta");

        // Reset maximum tolerance for Runge Kutta Fehlber solver
        h_value = 1e-1;

        // Solve the ODE system using a Runge Kutta Fehlber solver
        initial_conditions = alarcon_system.GetInitialConditions();
        Timer::Reset();
        solutions = rkf_solver.Solve(&alarcon_system, initial_conditions, 0.0, 10.0, h_value, 1e-4);
        Timer::Print("1. Runge-Kutta-Fehlberg");

        // Test that solutions are accurate for a small time increase
        int end = solutions.rGetSolutions().size() - 1;

        // Test that the solver stops at the right time
        TS_ASSERT_DELTA(solutions.rGetTimes()[end], 9.286356375, 1e-2);

        // Test solution - note the high tolerances
        TS_ASSERT_DELTA(solutions.rGetSolutions()[end][0], 0.004000000000000, 1e-3);
        TS_ASSERT_DELTA(solutions.rGetSolutions()[end][1], 0.379221366479055, 1e-3);
        TS_ASSERT_DELTA(solutions.rGetSolutions()[end][2], 0.190488726735972, 1e-3);
        TS_ASSERT_DELTA(solutions.rGetSolutions()[end][3], 9.962110289977730, 1e-3);
        TS_ASSERT_DELTA(solutions.rGetSolutions()[end][4], 0.096476600742599, 1e-3);
        TS_ASSERT_DELTA(solutions.rGetSolutions()[end][5], 1.000000000000000, 1e-3);
    }

    void TestArchiving()
    {
        OutputFileHandler handler("archive", false);
        std::string archive_filename = handler.GetOutputDirectoryFullPath() + "alarcon_ode.arch";

        {
            double oxygen_concentration = 0.7;
            bool is_labelled = true;

            Alarcon2004OxygenBasedCellCycleOdeSystem ode_system(oxygen_concentration, is_labelled);

            TS_ASSERT_DELTA(ode_system.GetOxygenConcentration(), 0.70, 1e-6);
            TS_ASSERT_EQUALS(ode_system.IsLabelled(), true);

            std::vector<double> initial_conditions = ode_system.GetInitialConditions();
            TS_ASSERT_EQUALS(initial_conditions.size(), 6u);
            TS_ASSERT_DELTA(initial_conditions[0], 0.90, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[1], 0.01, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[2], 0.00, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[3], 5.00, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[4], 1.00, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[5], 0.70, 1e-6);

            // Create an output archive
            std::ofstream ofs(archive_filename.c_str());
            boost::archive::text_oarchive output_arch(ofs);

            // Archive ODE system
            AbstractOdeSystem* const p_const_ode_system = &ode_system;
            output_arch << p_const_ode_system;
        }

        {
            AbstractOdeSystem* p_ode_system;

            // Create an input archive
            std::ifstream ifs(archive_filename.c_str(), std::ios::binary);
            boost::archive::text_iarchive input_arch(ifs);

            // Restore from the archive
            input_arch >> p_ode_system;

            // Check that archiving worked correctly
            TS_ASSERT_DELTA(static_cast<Alarcon2004OxygenBasedCellCycleOdeSystem*>(p_ode_system)->GetOxygenConcentration(), 0.70, 1e-6);
            TS_ASSERT_EQUALS(static_cast<Alarcon2004OxygenBasedCellCycleOdeSystem*>(p_ode_system)->IsLabelled(), true);

            std::vector<double> initial_conditions = p_ode_system->GetInitialConditions();
            TS_ASSERT_EQUALS(initial_conditions.size(), 6u);
            TS_ASSERT_DELTA(initial_conditions[0], 0.90, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[1], 0.01, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[2], 0.00, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[3], 5.00, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[4], 1.00, 1e-6);
            TS_ASSERT_DELTA(initial_conditions[5], 0.70, 1e-6);

            // Tidy up
            delete p_ode_system;
        }
    }
};

#endif /*TESTALARCON2004OXYGENBASEDCELLCYCLEODESYSTEM_HPP_*/


#include <boost/property_map/dynamic_property_map.hpp>
#include <boost/graph/graphml.hpp>

#include "include_and_types.cpp"
#include "my_pearce.cpp"
#include "my_nuutila.cpp"
#include "my_tarjan.cpp"
#include "my_pearce_not_recursive.cpp"

using namespace boost;

// Utility function to check if the results of the various algorithms are correct
template <class Result1, class Result2>
bool compare_results(const Result1 r1, const Result2 r2){
    if (r1.size() != r2.size())
        return false;
    int maxVal=0;
    int minVal=0;
    for(int i=0; i!=r1.size(); i++){
        maxVal = std::max(maxVal, r1[i]);
        minVal = std::min(minVal, r2[i]);
    }
    minVal-=1;
    maxVal+=1;
    int comp[maxVal];
    for (int i=0; i != maxVal; i++)
        comp[i]=minVal;

    for (int i = 0; i != r1.size(); i++){
        if (comp[r1[i]]==minVal) {
            for (int j = 0; j < i; j++) {
                if (r1[i] != r1[j] && r2[i] == r2[j])
                    return false;
            }
            comp[r1[i]] = r2[i];
        }
        if (comp[r1[i]]!=r2[i]){
            return false;
        }
    }
    return true;
}

std::vector<int> correct_nuutila_root(std::vector<int> vec){
    bool ok = false;
    while(!ok){
        ok = true;
        for(int i=0; i<vec.size(); i++){
            if(vec[i] != i && vec[i]!= vec[vec[i]]){
                vec[i]=vec[vec[i]];
                ok=false;
            }
        }
    }
    return vec;
}

int main(int, char*[])
{
    Graph g;
    dynamic_properties dp;
    // read graph from stdin
    read_graphml(std::cin, g, dp);

    // the boost graph library implementation, used to check correctness of the results
    std::vector<int> bgl_component(num_vertices(g)), discover_time(num_vertices(g));
    std::vector<default_color_type> bgl_color(num_vertices(g));
    std::vector<Vertex> bgl_root(num_vertices(g));
    int num_bgl = strong_components(g,
                                    make_iterator_property_map(bgl_component.begin(), get(vertex_index, g)),
                                    root_map(make_iterator_property_map(bgl_root.begin(), get(vertex_index, g))).
                                    color_map(make_iterator_property_map(bgl_color.begin(), get(vertex_index, g))).
                                    discover_time_map(make_iterator_property_map(discover_time.begin(), get(vertex_index, g))));

    // Tarjan's algorithm over the given graph
    std::cout << "Tarjan\t\t" << std::flush;
    TarjanClass<typeInt, typeInt, typeInt, typeBool, typeBool, typeInt> tarjan(&g);
    std::vector<int>* component = tarjan.tarjan_scc();

    // Nuutila's algorithm over the given graph
    std::cout << "Nuutila\t\t" << std::flush;
    NuutilaClass<typeInt, typeInt, typeBool> nuutila(&g);
    std::vector<int>* root_nuutila = nuutila.nuutila_scc();

    // Pearce's recursive algorithm over the given graph
    std::cout << "Pearce\t\t" << std::flush;
    PearceClass<typeInt> pearce(&g);
    std::vector<int>* rindex = pearce.pearce_scc();

    // Pearce's non recursive algorithm over the given graph
    std::cout << "PearceNR\t\t" << std::flush;
    PearceNR <typeBool, typeInt> pearcenr(&g);
    std::vector<int>* rindexNR = pearcenr.pearce_not_recursive_scc();

    // Print the number of components returned by the bgl implementation
    std::cout << "Components:\t" << num_bgl << std::endl;
    // check correctness of the results
    std::cout << "Correct:\t" << (compare_results(bgl_component, *component) && compare_results(bgl_component, *root_nuutila) &&
        compare_results(bgl_component, *rindex) && compare_results(bgl_component, *rindexNR)) << std::endl;
}


// Base-2 logarithm bithack.

#ifndef _AFJDFJSDFSD_PYOPENCL_HEADER_SEEN_BITLOG_HPP
#define _AFJDFJSDFSD_PYOPENCL_HEADER_SEEN_BITLOG_HPP

#include <climits>
#include <boost/cstdint.hpp>

namespace pyopencl
{
  extern const char log_table_8[];

  inline unsigned bitlog2_16(boost::uint16_t v)
  {
    if (unsigned long t = v >> 8)
      return 8+log_table_8[t];
    else
      return log_table_8[v];
  }

  inline unsigned bitlog2_32(boost::uint32_t v)
  {
    if (boost::uint16_t t = v >> 16)
      return 16+bitlog2_16(t);
    else
      return bitlog2_16(v);
  }

  inline unsigned bitlog2(unsigned long v)
  {
#if (ULONG_MAX != 4294967295)
    if (boost::uint32_t t = v >> 32)
      return 32+bitlog2_32(t);
    else
#endif
      return bitlog2_32(v);
  }
}

#endif


#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <boost/multiprecision/cpp_int.hpp>
using namespace boost::multiprecision;
using namespace std;
int main() {
    int d; cin >> d;
    cpp_int mini = 10000000000000, sum = 0;
    vector<int> a(d, 0);
    for (int i = 0; i < d; i++) cin >> a[i];
    for (int i = 0; i < d; i++) {
        cpp_int b; cin >> b; sum += (cpp_int)a[i];
        if (sum >= b) mini = min(mini, b);
    }
    if (mini == 10000000000000) mini = -1;
    cout << mini << endl;
}


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

#include "ssmkit/distribution/categorical.hpp"

using namespace ssmkit;

BOOST_AUTO_TEST_SUITE(distribution_categorical);

// Number of Monte-Carlo runs
constexpr int mc_n = 500000;

BOOST_AUTO_TEST_CASE(mc_test_random_default_pdf)
{
  // testing default constructor

  // categorical distribution with only one category = 0
  distribution::Categorical pdf;
  arma::Col<unsigned int> samples(mc_n);
  random::setRandomSeed();
  samples.for_each([&pdf](auto &val){val = pdf.random();});
  // check if any sample is non zero
  BOOST_CHECK(!arma::any(samples));
}

BOOST_AUTO_TEST_CASE(mc_test_random_arbitary_pdf)
{
  // testing distribution with given probabilities
  arma::vec probabilities{0.1, 0.3, 0.05, 0.0, 0.55};
  distribution::Categorical pdf(probabilities);

  // making histogram of returned samples
  arma::vec hist{0, 0, 0, 0, 0};
  random::setRandomSeed();
  for(int ii=0; ii<mc_n; ++ii)
    ++hist(pdf.random());
  // normalize histogram
  auto hist_n = hist / mc_n;
  // check if normalized histogram is equal to the given probabilities
  BOOST_CHECK(arma::approx_equal(hist_n, probabilities, "absdiff", 0.005));
}

BOOST_AUTO_TEST_CASE(likelihood_test)
{
}

BOOST_AUTO_TEST_SUITE_END();


#include <scitbx/array_family/boost_python/flex_fwd.h>

#include <boost/python/def.hpp>
#include <boost/python/args.hpp>

#include <scitbx/math/jacks_expf.h>
#include <scitbx/array_family/shared.h>
#include <tbxx/error_utils.hpp>

namespace scitbx { namespace math {

namespace {

  af::shared<float>
  jacks_expf_a(
    af::const_ref<float> const& array_of_float)
  {
    af::shared<float> result(
      array_of_float.size(),
      af::init_functor_null<float>());
    for(std::size_t i=0;i<array_of_float.size();i++) {
      result[i] = jacks_expf(array_of_float[i]);
    }
    return result;
  }

  union float_unsigned
  {
    float f;
    unsigned u;
  };

  namespace float_bits {
    static const unsigned sign = 0x80000000U;
    static const unsigned expo = 0x7F800000U;
    static const unsigned mant_size = 23U;
    static const int expo_min = -127;
    static const int expo_max = 127;
    static const int expo_bias = 127;
  }

  af::shared<float>
  exercise_jacks_expf(
    bool negative_sign,
    int exponent,
    unsigned mantissa_step_size,
    unsigned j_sample)
  {
    TBXX_ASSERT(sizeof(float) == 4);
    TBXX_ASSERT(sizeof(int) == 4);
    TBXX_ASSERT(exponent >= float_bits::expo_min);
    TBXX_ASSERT(exponent <= float_bits::expo_max);
    float_unsigned value;
    value.f = -3.9572185e-13f;
    TBXX_ASSERT(value.u == 2866726279U);
      // expected to be true for IEEE 754 binary32
    af::shared<float> result;
    value.u = 0U;
    if (negative_sign) {
      value.u |= float_bits::sign;
    }
    unsigned uexp = static_cast<unsigned>(exponent + float_bits::expo_bias);
    value.u |= uexp << float_bits::mant_size;
    unsigned j_end = 1U << float_bits::mant_size;
    float je;
    for(unsigned j=0;j<j_end;j+=mantissa_step_size) {
      value.u &= float_bits::sign | float_bits::expo;
      value.u |= j;
      je = jacks_expf(value.f);
      if (j == 0 || j == j_sample) {
        result.push_back(value.f);
        result.push_back(je);
      }
    }
    result.push_back(value.f);
    result.push_back(je);
    return result;
  }

} // namespace <anonymous>

namespace boost_python {

  void wrap_exp_functions()
  {
    using namespace boost::python;
    def("jacks_expf", jacks_expf_a, (arg("array_of_float")));
    def("exercise_jacks_expf", exercise_jacks_expf, (
      arg("negative_sign"),
      arg("exponent"),
      arg("mantissa_step_size"),
      arg("j_sample")));
  }

}}} // namespace scitbx::math::boost_python


#ifndef DEFINICOES_H
#define DEFINICOES_H

#include <Eigen/Dense>
#include <string>

//#define M_FLOAT
#define M_DOUBLE

using namespace Eigen;

#ifdef M_FLOAT
typedef Eigen::Matrix<float, Dynamic, Dynamic> MatrizX;
typedef Matrix<float, Dynamic, 1> VetorX;
typedef float _real;
#define MAX_VALUE FLT_MAX
#else
#ifdef M_DOUBLE
typedef Eigen::Matrix<double, Dynamic, Dynamic> MatrizX;
typedef Matrix<double, Dynamic, 1> VetorX;
typedef double _real;
#define MAX_VALUE DBL_MAX
#endif
#endif

#endif


/*
 Copyright (C) 2017 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 <boost/make_shared.hpp>
#include <ql/math/interpolations/bilinearinterpolation.hpp>
#include <ql/math/interpolations/linearinterpolation.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/yield/forwardcurve.hpp>
#include <qle/termstructures/blackvariancesurfacemoneyness.hpp>

using namespace std;

namespace QuantExt {

BlackVarianceSurfaceMoneyness::BlackVarianceSurfaceMoneyness(
    const Calendar& cal, const Handle<Quote>& spot, const std::vector<Time>& times, const std::vector<Real>& moneyness,
    const std::vector<std::vector<Handle<Quote> > >& blackVolMatrix, const DayCounter& dayCounter, bool stickyStrike)
    : BlackVarianceTermStructure(0, cal), stickyStrike_(stickyStrike), spot_(spot), dayCounter_(dayCounter),
      moneyness_(moneyness), quotes_(blackVolMatrix) {

    QL_REQUIRE(times.size() == blackVolMatrix.front().size(), "mismatch between times vector and vol matrix colums");
    QL_REQUIRE(moneyness_.size() == blackVolMatrix.size(), "mismatch between moneyness vector and vol matrix rows");

    QL_REQUIRE(times[0] >= 0, "cannot have times[0] < 0");

    if (stickyStrike) {
        // we don't want to know if the spot has changed - we take a copy here
        spot_ = Handle<Quote>(boost::make_shared<SimpleQuote>(spot->value()));
    } else {
        registerWith(spot_);
    }

    Size j, i;
    // internally times_ is one bigger than the input "times"
    times_ = std::vector<Time>(times.size() + 1);
    times_[0] = 0.0;
    variances_ = Matrix(moneyness_.size(), times.size() + 1);
    for (i = 0; i < moneyness_.size(); i++) {
        variances_[i][0] = 0.0;
    }
    for (j = 1; j <= times.size(); j++) {
        times_[j] = times[j - 1];
        QL_REQUIRE(times_[j] > times_[j - 1], "dates must be sorted unique!");
        for (i = 0; i < moneyness_.size(); i++) {
            variances_[i][j] = 0.0;
            registerWith(blackVolMatrix[i][j - 1]);
        }
    }

    varianceSurface_ =
        Bilinear().interpolate(times_.begin(), times_.end(), moneyness_.begin(), moneyness_.end(), variances_);
    notifyObservers();
}

void BlackVarianceSurfaceMoneyness::update() {
    TermStructure::update();
    LazyObject::update();
}

void BlackVarianceSurfaceMoneyness::performCalculations() const {
    for (Size j = 1; j < variances_.columns(); j++) {
        for (Size i = 0; i < variances_.rows(); i++) {
            Real vol = quotes_[i][j - 1]->value();
            variances_[i][j] = times_[j] * vol * vol;
        }
    }
    varianceSurface_.update();
}

Real BlackVarianceSurfaceMoneyness::blackVarianceImpl(Time t, Real strike) const {

    calculate();

    if (t == 0.0)
        return 0.0;

    return blackVarianceMoneyness(t, moneyness(t, strike));
}

Real BlackVarianceSurfaceMoneyness::blackVarianceMoneyness(Time t, Real m) const {
    if (t <= times_.back())
        return varianceSurface_(t, m, true);
    else
        return varianceSurface_(times_.back(), m, true) * t / times_.back();
}

BlackVarianceSurfaceMoneynessSpot::BlackVarianceSurfaceMoneynessSpot(
    const Calendar& cal, const Handle<Quote>& spot, const std::vector<Time>& times, const std::vector<Real>& moneyness,
    const std::vector<std::vector<Handle<Quote> > >& blackVolMatrix, const DayCounter& dayCounter, bool stickyStrike)
    : BlackVarianceSurfaceMoneyness(cal, spot, times, moneyness, blackVolMatrix, dayCounter, stickyStrike) {}

Real BlackVarianceSurfaceMoneynessSpot::moneyness(Time, Real strike) const {
    if (strike == Null<Real>() || strike == 0)
        return 1.0;
    else
        return strike / spot_->value();
}

BlackVarianceSurfaceMoneynessForward::BlackVarianceSurfaceMoneynessForward(
    const Calendar& cal, const Handle<Quote>& spot, const std::vector<Time>& times, const std::vector<Real>& moneyness,
    const std::vector<std::vector<Handle<Quote> > >& blackVolMatrix, const DayCounter& dayCounter,
    const Handle<YieldTermStructure>& forTS, const Handle<YieldTermStructure>& domTS, bool stickyStrike)
    : BlackVarianceSurfaceMoneyness(cal, spot, times, moneyness, blackVolMatrix, dayCounter, stickyStrike),
      forTS_(forTS), domTS_(domTS) {

    if (!stickyStrike) {
        QL_REQUIRE(!forTS_.empty(), "foreign discount curve required for atmf surface");
        QL_REQUIRE(!domTS_.empty(), "foreign discount curve required for atmf surface");
        registerWith(forTS_);
        registerWith(domTS_);
    } else {
        for (Size i = 0; i < times_.size(); i++) {
            Time t = times_[i];
            Real fwd = spot_->value() * forTS_->discount(t) / domTS_->discount(t);
            forwards_.push_back(fwd);
        }
        forwardCurve_ = Linear().interpolate(times_.begin(), times_.end(), forwards_.begin());
    }
}

Real BlackVarianceSurfaceMoneynessForward::moneyness(Time t, Real strike) const {
    Real fwd;
    if (strike == Null<Real>() || strike == 0)
        return 1.0;
    else {
        if (stickyStrike_)
            fwd = forwardCurve_(t, true);
        else
            fwd = spot_->value() * forTS_->discount(t) / domTS_->discount(t);
        return strike / fwd;
    }
}

} // namespace QuantExt


#include <boost/python.hpp>
#include "integrand.h"

using namespace Eigen;

GreenIntegrand::GreenIntegrand(const VectorXcd &w_, const double &mu_,
    const MatrixXcd &SE_, const VectorXd &SK_, const double &Hf)
    : md_int::GeneralIntegrand<complex_t>(), mu(mu_),
    H(Hf), wall(w_), SEall(SE_), SK(SK_)
{
  set_dim_in(DIM);
  set_dim_out(MSIZE);
}

void GreenIntegrand::set_data(const int &r)
{
  w = wall(r);
  for (int i = 0; i < MSIZE; ++i)
    SE(i) = SEall(r, MSIZE*i+i);  // diagonal terms
}

void GreenIntegrand::CalculateOriginalIntegrand(const VectorXd &x,
    VectorXcd &y) const {
  double t = SK(0);
  y.resize(dim_out());

  for (int L = 0; L < MSIZE; ++L)
    y(L) =  1./(2*M_PI*t*t)*sqrt(4*t*t-x(0)*x(0)) / (w + mu - x(0) - SE(L));
}

HIntegrand::HIntegrand(const int &Norder, const VectorXd &SK_,
                       const double &Hf_in)
  : md_int::GeneralIntegrand<complex_t>(), N_order(Norder), Hf(Hf_in), SK(SK_)
{
  set_dim_in(DIM);
  set_dim_out(N_order*MSIZE);
}

void HIntegrand::CalculateOriginalIntegrand(const VectorXd &x,
    VectorXcd &y) const {
  double t = SK(0);
  complex_t Hband, Hpow = 1.;
  y.resize(dim_out());
  Hband = x(0);
  for (int n = 0; n < N_order; ++n) {
    Hpow *= Hband;
    for (int i = 0; i < MSIZE; ++i)
      y(MSIZE*n+i) = 1./(2*M_PI*t*t)*sqrt(4*t*t-x(0)*x(0))*Hpow;
  }
}


/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkBoostGraphAdapter.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkBoostBetweennessClustering.h"

#include "vtkBoostConnectedComponents.h"
#include "vtkBoostGraphAdapter.h"
#include "vtkDataSetAttributes.h"
#include "vtkDirectedGraph.h"
#include "vtkFloatArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMutableDirectedGraph.h"
#include "vtkMutableUndirectedGraph.h"
#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"
#include "vtkUndirectedGraph.h"

#include <boost/graph/bc_clustering.hpp>

// @note: This piece of code is modification of algorithm from boost graph
// library. This modified version allows the user to pass edge weight map
namespace boost
{
// Graph clustering based on edge betweenness centrality.
//
// This algorithm implements graph clustering based on edge
// betweenness centrality. It is an iterative algorithm, where in each
// step it compute the edge betweenness centrality (via @ref
// brandes_betweenness_centrality) and removes the edge with the
// maximum betweenness centrality. The @p done function object
// determines when the algorithm terminates (the edge found when the
// algorithm terminates will not be removed).
//
// @param g The graph on which clustering will be performed. The type
// of this parameter (@c MutableGraph) must be a model of the
// VertexListGraph, IncidenceGraph, EdgeListGraph, and Mutable Graph
// concepts.
//
// @param done The function object that indicates termination of the
// algorithm. It must be a ternary function object that accepts the
// maximum centrality, the descriptor of the edge that will be
// removed, and the graph @p g.
//
// @param edge_centrality (UTIL/out2) The property map that will store
// the betweenness centrality for each edge. When the algorithm
// terminates, it will contain the edge centralities for the
// graph. The type of this property map must model the
// ReadWritePropertyMap concept. Defaults to a @c
// iterator_property_map whose value type is
// @c Done::centrality_type and using @c get(edge_index, g) for the
// index map.
//
// @param vertex_index (IN) The property map that maps vertices to
// indices in the range @c [0, num_vertices(g)). This type of this
// property map must model the ReadablePropertyMap concept and its
// value type must be an integral type. Defaults to
// @c get(vertex_index, g).
template <typename MutableGraph, typename Done, typename EdgeCentralityMap, typename EdgeWeightMap,
  typename VertexIndexMap>
void betweenness_centrality_clustering(MutableGraph& g, Done done,
  EdgeCentralityMap edge_centrality, EdgeWeightMap edge_weight_map, VertexIndexMap vertex_index)
{
  typedef typename property_traits<EdgeCentralityMap>::value_type centrality_type;
  typedef typename graph_traits<MutableGraph>::edge_iterator edge_iterator;
  typedef typename graph_traits<MutableGraph>::edge_descriptor edge_descriptor;

  if (has_no_edges(g))
    return;

  // Function object that compares the centrality of edges
  indirect_cmp<EdgeCentralityMap, std::less<centrality_type>> cmp(edge_centrality);

  bool is_done;
  do
  {
    brandes_betweenness_centrality(g,
      edge_centrality_map(edge_centrality)
        .vertex_index_map(vertex_index)
        .weight_map(edge_weight_map));
    std::pair<edge_iterator, edge_iterator> edges_iters = edges(g);
    edge_descriptor e = *max_element(edges_iters.first, edges_iters.second, cmp);
    is_done = done(get(edge_centrality, e), e, g);
    if (!is_done)
      remove_edge(e, g);
  } while (!is_done && !has_no_edges(g));
}
}

vtkStandardNewMacro(vtkBoostBetweennessClustering);

//------------------------------------------------------------------------------
vtkBoostBetweennessClustering::vtkBoostBetweennessClustering()
  : vtkGraphAlgorithm()
  , Threshold(0)
  , UseEdgeWeightArray(false)
  , InvertEdgeWeightArray(false)
  , EdgeWeightArrayName(0)
  , EdgeCentralityArrayName(0)
{
  this->SetNumberOfOutputPorts(2);
}

//------------------------------------------------------------------------------
vtkBoostBetweennessClustering::~vtkBoostBetweennessClustering()
{
  this->SetEdgeWeightArrayName(0);
  this->SetEdgeCentralityArrayName(0);
}

//------------------------------------------------------------------------------
void vtkBoostBetweennessClustering::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  os << indent << "Threshold: " << this->Threshold << endl;
  os << indent << "UseEdgeWeightArray: " << this->UseEdgeWeightArray << endl;
  os << indent << "InvertEdgeWeightArray: " << this->InvertEdgeWeightArray << endl;
  (EdgeWeightArrayName)
    ? os << indent << "EdgeWeightArrayName: " << this->EdgeWeightArrayName << endl
    : os << indent << "EdgeWeightArrayName: nullptr" << endl;

  (EdgeCentralityArrayName)
    ? os << indent << "EdgeCentralityArrayName: " << this->EdgeCentralityArrayName << endl
    : os << indent << "EdgeCentralityArrayName: nullptr" << endl;
}

//------------------------------------------------------------------------------
int vtkBoostBetweennessClustering::RequestData(vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector, vtkInformationVector* outputVector)
{
  // Helpful vars.
  bool isDirectedGraph(false);

  // Get the info objects
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  if (!inInfo)
  {
    vtkErrorMacro("Failed to get input information.");
    return 1;
  }

  vtkInformation* outInfo1 = outputVector->GetInformationObject(0);
  if (!outInfo1)
  {
    vtkErrorMacro("Failed get output1 on information first port.");
  }

  vtkInformation* outInfo2 = outputVector->GetInformationObject(1);
  if (!outInfo2)
  {
    vtkErrorMacro("Failed to get output2 information on second port.");
    return 1;
  }

  // Get the input, output1 and output2.
  vtkGraph* input = vtkGraph::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
  if (!input)
  {
    vtkErrorMacro("Failed to get input graph.");
    return 1;
  }

  if (vtkDirectedGraph::SafeDownCast(input))
  {
    isDirectedGraph = true;
  }

  vtkGraph* output1 = vtkGraph::SafeDownCast(outInfo1->Get(vtkDataObject::DATA_OBJECT()));
  if (!output1)
  {
    vtkErrorMacro("Failed to get output1 graph.");
    return 1;
  }

  vtkGraph* output2 = vtkGraph::SafeDownCast(outInfo2->Get(vtkDataObject::DATA_OBJECT()));
  if (!output2)
  {
    vtkErrorMacro("Failed to get output2 graph.");
    return 1;
  }

  vtkSmartPointer<vtkFloatArray> edgeCM = vtkSmartPointer<vtkFloatArray>::New();
  if (this->EdgeCentralityArrayName)
  {
    edgeCM->SetName(this->EdgeCentralityArrayName);
  }
  else
  {
    edgeCM->SetName("edge_centrality");
  }

  boost::vtkGraphEdgePropertyMapHelper<vtkFloatArray*> helper(edgeCM);

  vtkSmartPointer<vtkDataArray> edgeWeight(0);
  if (this->UseEdgeWeightArray && this->EdgeWeightArrayName)
  {
    if (!this->InvertEdgeWeightArray)
    {
      edgeWeight = input->GetEdgeData()->GetArray(this->EdgeWeightArrayName);
    }
    else
    {
      vtkDataArray* weights = input->GetEdgeData()->GetArray(this->EdgeWeightArrayName);

      if (!weights)
      {
        vtkErrorMacro(<< "Error: Edge weight array " << this->EdgeWeightArrayName
                      << " is set but not found or not a data array.\n");
        return 1;
      }

      edgeWeight.TakeReference(vtkDataArray::CreateDataArray(weights->GetDataType()));

      double range[2];
      weights->GetRange(range);

      if (weights->GetNumberOfComponents() > 1)
      {
        vtkErrorMacro("Expecting single component array.");
        return 1;
      }

      for (int i = 0; i < weights->GetDataSize(); ++i)
      {
        edgeWeight->InsertNextTuple1(range[1] - weights->GetTuple1(i));
      }
    }

    if (!edgeWeight)
    {
      vtkErrorMacro(<< "Error: Edge weight array " << this->EdgeWeightArrayName
                    << " is set but not found or not a data array.\n");
      return 1;
    }
  }

  // First compute the second output and the result will be used
  // as input for the first output.
  if (isDirectedGraph)
  {
    vtkMutableDirectedGraph* out2 = vtkMutableDirectedGraph::New();

    // Copy the data to the second output (as this algorithm most likely
    // going to removed edges (and hence modifies the graph).
    out2->DeepCopy(input);

    if (edgeWeight)
    {
      boost::vtkGraphEdgePropertyMapHelper<vtkDataArray*> helper2(edgeWeight);
      boost::betweenness_centrality_clustering(out2,
        boost::bc_clustering_threshold<double>(this->Threshold, out2, false), helper, helper2,
        boost::get(boost::vertex_index, out2));
    }
    else
    {
      boost::betweenness_centrality_clustering(
        out2, boost::bc_clustering_threshold<double>(this->Threshold, out2, false), helper);
    }
    out2->GetEdgeData()->AddArray(edgeCM);

    // Finally copy the results to the output.
    output2->ShallowCopy(out2);

    out2->Delete();
  }
  else
  {
    vtkMutableUndirectedGraph* out2 = vtkMutableUndirectedGraph::New();

    // Send the data to output2.
    out2->DeepCopy(input);

    if (edgeWeight)
    {
      boost::vtkGraphEdgePropertyMapHelper<vtkDataArray*> helper2(edgeWeight);
      boost::betweenness_centrality_clustering(out2,
        boost::bc_clustering_threshold<double>(this->Threshold, out2, false), helper, helper2,
        boost::get(boost::vertex_index, out2));
    }
    else
    {
      boost::betweenness_centrality_clustering(
        out2, boost::bc_clustering_threshold<double>(this->Threshold, out2, false), helper);
    }
    out2->GetEdgeData()->AddArray(edgeCM);

    // Finally copy the results to the output.
    output2->ShallowCopy(out2);

    out2->Delete();
  }

  // Now take care of the first output.
  vtkSmartPointer<vtkBoostConnectedComponents> bcc(
    vtkSmartPointer<vtkBoostConnectedComponents>::New());

  vtkSmartPointer<vtkGraph> output2Copy(0);

  if (isDirectedGraph)
  {
    output2Copy = vtkSmartPointer<vtkDirectedGraph>::New();
  }
  else
  {
    output2Copy = vtkSmartPointer<vtkUndirectedGraph>::New();
  }

  output2Copy->ShallowCopy(output2);

  bcc->SetInputData(0, output2Copy);
  bcc->Update();

  vtkSmartPointer<vtkGraph> bccOut = bcc->GetOutput(0);

  vtkSmartPointer<vtkAbstractArray> compArray(0);
  if (isDirectedGraph)
  {
    vtkSmartPointer<vtkDirectedGraph> out1(vtkSmartPointer<vtkDirectedGraph>::New());
    out1->ShallowCopy(input);

    compArray = bccOut->GetVertexData()->GetAbstractArray("component");

    if (!compArray)
    {
      vtkErrorMacro("Unable to get component array.");
      return 1;
    }

    out1->GetVertexData()->AddArray(compArray);

    // Finally copy the output to the algorithm output.
    output1->ShallowCopy(out1);
  }
  else
  {
    vtkSmartPointer<vtkUndirectedGraph> out1(vtkSmartPointer<vtkUndirectedGraph>::New());
    out1->ShallowCopy(input);

    compArray = bccOut->GetVertexData()->GetAbstractArray("component");

    if (!compArray)
    {
      vtkErrorMacro("Unable to get component array.");
      return 1;
    }

    out1->GetVertexData()->AddArray(compArray);

    // Finally copy the output to the algorithm output.
    output1->ShallowCopy(out1);
  }

  // Also add the components array to the second output.
  output2->GetVertexData()->AddArray(compArray);

  return 1;
}

//------------------------------------------------------------------------------
int vtkBoostBetweennessClustering::FillOutputPortInformation(int port, vtkInformation* info)
{
  if (port == 0 || port == 1)
  {
    info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkGraph");
  }
  return 1;
}


//
// Copyright (c) 2016 - 2017 Mesh Consultants Inc.
// 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 "Geomlib_TriMeshLoopSubdivide.h"

#include <assert.h>

#include <iostream>
#include <vector>

#include <Urho3D/Core/Variant.h>
#include <Urho3D/Math/Vector3.h>

#include <Eigen/Core>

#pragma warning(push, 0)
#include <igl/edges.h>
#include <igl/edge_flaps.h>
#include <igl/is_boundary_edge.h>
#include <igl/is_border_vertex.h>
#include <igl/adjacency_list.h>
#include <igl/boundary_loop.h>
#pragma warning(pop)

#include "ConversionUtilities.h"
#include "TriMesh.h"

#pragma warning(disable : 4244)

// helper functions quarantined in anonymous namespace
namespace {

	void loop_subdivide_mesh(
		const Eigen::MatrixXf& V,
		const Eigen::MatrixXi& F,
		Eigen::MatrixXf& NV,
		Eigen::MatrixXi& NF
	)
	{
		unsigned numVertices = V.rows();

		// precompute the number of edges
		Eigen::MatrixXi EE;
		//igl::all_edges(F, EE);
		igl::edges(F, EE);

		// precompute edge-face relationship data
		Eigen::MatrixXi E, EI;
		Eigen::MatrixXi EF = Eigen::MatrixXi::Constant(EE.rows(), 2, -1);
		Eigen::VectorXi EMAP;
		igl::edge_flaps(F, E, EMAP, EF, EI);

		// precompute edge boundary data
		Eigen::VectorXi B;
		igl::is_boundary_edge(E, F, B);

		// precompute vertex boundary data
		std::vector<bool> borderFlags = igl::is_border_vertex(V, F);
		std::vector<std::vector<int> > boundaryLoops;
		igl::boundary_loop(F, boundaryLoops);

		// precompute adjacency data
		std::vector<std::vector<int> > adjacencyData;
		igl::adjacency_list(F, adjacencyData);

		//
		NV.resize(V.rows() + E.rows(), 3);
		NV.block(0, 0, numVertices, 3) = V;

		for (unsigned i = 0; i < boundaryLoops.size(); ++i) {

			std::vector<int> loop = boundaryLoops[i];

			for (unsigned j = 0; j < loop.size(); ++j) {
				unsigned prev = (j == 0) ? (loop.size() - 1) : (j - 1);
				unsigned next = (j == loop.size() - 1) ? 0 : (j + 1);
				NV.row(loop[j]) = 0.125f * V.row(loop[prev]) + 0.75f * V.row(loop[j]) + 0.125f * V.row(loop[next]);
			}

		}

		for (unsigned i = 0; i < V.rows(); ++i) {
			if (borderFlags[i]) {
				// border vertex that should have been accounted for at the boundary loop step
			}
			else {
				// interior vertex
				std::vector<int> adj = adjacencyData[i];
				unsigned n = adj.size();
				if (n < 3) {
					std::cerr << "WARNING: loop_subdivide_mesh --- skipping bad vertex....\n";
				}
				else {
					float beta = (n == 3) ? 0.1875f : (0.375f * (1.0f / n));
					Eigen::RowVector3f w = (1.0f - n * beta) * V.row(i);
					for (unsigned j = 0; j < adj.size(); ++j) {
						w += beta * V.row(adj[j]);
					}
					NV.row(i) = w;
				}
			}
		}

		// add points on each edge
		for (unsigned e = 0; e < E.rows(); ++e) {

			int v0 = E(e, 0);
			int v1 = E(e, 1);

			if (B(e) == 0) {
				int v2 = F(EF(e, 0), EI(e, 0));
				int v3 = F(EF(e, 1), EI(e, 1));

				NV.row(numVertices + e) = 0.375f * V.row(v0) + 0.375f * V.row(v1) + 0.125f * V.row(v2) + 0.125f * V.row(v3);
			}
			else if (B(e) == 1) {
				NV.row(numVertices + e) = 0.5f * V.row(v0) + 0.5f * V.row(v1);
			}
			else {
				//
				std::cerr << "WARNING: loop_subdivide_mesh --- skipping edge\n";
			}
		}

		// Subdivide face data
		NF.resize(4 * F.rows(), 3);
		for (unsigned f = 0; f < F.rows(); ++f) {
			// if this is wrong, tho, how on earth are the faces right?
			// ?? anyway, alternative is 3*f + 0,1,2
			int v0 = V.rows() + EMAP(f);
			int v1 = V.rows() + EMAP(F.rows() + f);
			int v2 = V.rows() + EMAP(2 * F.rows() + f);
			/*
			int v0 = V.rows() + EMAP(3 * f);
			int v1 = V.rows() + EMAP(3 * f + 1);
			int v2 = V.rows() + EMAP(3 * f + 2);
			*/

			NF.row(4 * f) = Eigen::RowVector3i(v0, v1, v2);
			NF.row(4 * f + 1) = Eigen::RowVector3i(F(f, 0), v2, v1);
			NF.row(4 * f + 2) = Eigen::RowVector3i(v2, F(f, 1), v0);
			NF.row(4 * f + 3) = Eigen::RowVector3i(v1, v0, F(f, 2));
		}
	}
}

bool Geomlib::TriMeshLoopSubdivide(
	const Urho3D::Variant& meshIn,
	int steps,
	Urho3D::Variant& meshOut
)
{
	if (!TriMesh_Verify(meshIn)) {
		meshOut = Urho3D::Variant();
		return false;
	}

	Eigen::MatrixXf V, NV;
	Eigen::MatrixXi F, NF;
	IglMeshToMatrices(meshIn, V, F);

	loop_subdivide_mesh(V, F, NV, NF);

	meshOut = TriMesh_Make(NV, NF);
	return true;
}


#ifndef ASLAM_CAMERAS_TRIANGULATION_HPP
#define ASLAM_CAMERAS_TRIANGULATION_HPP

#include <Eigen/Core>

namespace aslam {
namespace cameras {

/// \brief Closed form linear triangulation
///
/// Returns the point that is in between the closest point
/// between the two lines. The gap is the distance between
/// the two lines. s0 and s1 are the distance along each ray
/// to the closest point
void triangulate(const Eigen::Vector3d& point0, const Eigen::Vector3d& ray0, const Eigen::Vector3d& point1,
                 const Eigen::Vector3d& ray1, Eigen::Vector3d& outTriangulatedPoint, double& outGap, double& outS0,
                 double& outS1);
}  // namespace cameras
}  // namespace aslam

#endif /* ASLAM_CAMERAS_TRIANGULATION_HPP */