/* Boost interval/compare/set.hpp template implementation file
 *
 * Copyright Guillaume Melquiond 2002-2003
 * Permission to use, copy, modify, sell, and distribute this software
 * is hereby granted without fee provided that the above copyright notice
 * appears in all copies and that both that copyright notice and this
 * permission notice appear in supporting documentation,
 *
 * None of the above authors make any representation about the
 * suitability of this software for any purpose. It is provided "as
 * is" without express or implied warranty.
 *
 * $Id: set.hpp,v 1.2 2003/02/05 17:34:31 gmelquio Exp $
 */

#ifndef BOOST_NUMERIC_INTERVAL_COMPARE_SET_HPP
#define BOOST_NUMERIC_INTERVAL_COMPARE_SET_HPP

#include <boost/numeric/interval/detail/interval_prototype.hpp>
#include <boost/numeric/interval/utility.hpp>

namespace boost {
namespace numeric {
namespace interval_lib {
namespace compare {
namespace set {

template<class T, class Policies1, class Policies2> inline
bool operator<(const interval<T, Policies1>& x, const interval<T, Policies2>& y)
{
  return proper_subset(x, y);
}

template<class T, class Policies1, class Policies2> inline
bool operator<=(const interval<T, Policies1>& x, const interval<T, Policies2>& y)
{
  return subset(x, y);
}

template<class T, class Policies1, class Policies2> inline
bool operator>(const interval<T, Policies1>& x, const interval<T, Policies2>& y)
{
  return proper_subset(y, x);
}

template<class T, class Policies1, class Policies2> inline
bool operator>=(const interval<T, Policies1>& x, const interval<T, Policies2>& y)
{
  return subset(y, x);
}

template<class T, class Policies1, class Policies2> inline
bool operator==(const interval<T, Policies1>& x, const interval<T, Policies2>& y)
{
  return equal(y, x);
}

template<class T, class Policies1, class Policies2> inline
bool operator!=(const interval<T, Policies1>& x, const interval<T, Policies2>& y)
{
  return !equal(y, x);
}

} // namespace set
} // namespace compare
} // namespace interval_lib
} // namespace numeric
} // namespace boost

#endif // BOOST_NUMERIC_INTERVAL_COMPARE_SET_HPP


// Copyright (c) 2015
// Author: Chrono Law
#include <cmath>
#include <std.hpp>
#include <typeinfo>
using namespace std;

#include <boost/utility/result_of.hpp>
using namespace boost;

//////////////////////////////////////////

template<typename F, typename T>
typename boost::result_of<F(T)>::type call_func(F f, T t)
{   return f(t);}

void case1()
{
    typedef double (*Func)(double d);
    Func func = sqrt;

    boost::result_of<Func(double)>::type x = func(5.0);
    cout << typeid(x).name() << endl;

    auto y =  call_func(func, 5.0);
    cout << typeid(y).name() << endl;

}

int main()
{
    case1();
}


/*

Copyright (c) 2005-2017, 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 TESTELLIPTICBOXDOMAINPDEMODIFIER_HPP_
#define TESTELLIPTICBOXDOMAINPDEMODIFIER_HPP_

#include <cxxtest/TestSuite.h>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include "CheckpointArchiveTypes.hpp"

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

#include "ArchiveOpener.hpp"
#include "SmartPointers.hpp"
#include "ReplicatableVector.hpp"
#include "AbstractCellBasedWithTimingsTestSuite.hpp"
#include "EllipticBoxDomainPdeModifier.hpp"
#include "AveragedSourceEllipticPde.hpp"
#include "UniformCellCycleModel.hpp"
#include "ApoptoticCellProperty.hpp"
#include "DifferentiatedCellProliferativeType.hpp"
#include "CellsGenerator.hpp"
#include "MeshBasedCellPopulation.hpp"
#include "HoneycombMeshGenerator.hpp"
#include "NodeBasedCellPopulation.hpp"
#include "VertexBasedCellPopulation.hpp"
#include "HoneycombVertexMeshGenerator.hpp"
#include "PottsBasedCellPopulation.hpp"
#include "PottsMeshGenerator.hpp"
#include "CaBasedCellPopulation.hpp"
#include "UniformSourceEllipticPde.hpp"

// This test is always run sequentially (never in parallel)
#include "FakePetscSetup.hpp"

/*
 * In this test suite we check the solution of the AveragedPdes for each population type.
 * In each case we are solving Laplacian U = f where f is constant in different regions.
 * We test on a square with half apoptotic cells and the PDE mesh is twice the size.
 */
class TestEllipticBoxDomainPdeModifier : public AbstractCellBasedWithTimingsTestSuite
{
public:

    void TestEllipticConstructor() throw(Exception)
    {
        // Create PDE and boundary condition objects
        MAKE_PTR_ARGS(UniformSourceEllipticPde<2>, p_pde, (-0.1));
        MAKE_PTR_ARGS(ConstBoundaryCondition<2>, p_bc, (1.0));

        // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
        ChastePoint<2> lower(-10.0, -10.0);
        ChastePoint<2> upper(10.0, 10.0);
        MAKE_PTR_ARGS(ChasteCuboid<2>, p_cuboid, (lower, upper));

        // Create a PDE modifier and set the name of the dependent variable in the PDE
        MAKE_PTR_ARGS(EllipticBoxDomainPdeModifier<2>, p_pde_modifier, (p_pde, p_bc, false, p_cuboid, 2.0));
        p_pde_modifier->SetDependentVariableName("averaged quantity");

        // Test that member variables are initialised correctly
        TS_ASSERT_EQUALS(p_pde_modifier->rGetDependentVariableName(), "averaged quantity");
        TS_ASSERT_DELTA(p_pde_modifier->GetStepSize(), 2.0, 1e-5);
        TS_ASSERT_EQUALS(p_pde_modifier->AreBcsSetOnBoxBoundary(), true);

        // Coverage of some set and methods
        p_pde_modifier->SetBcsOnBoxBoundary(false);
        TS_ASSERT_EQUALS(p_pde_modifier->AreBcsSetOnBoxBoundary(), false);

        // Check that the finite element mesh is correct
        TS_ASSERT_EQUALS(p_pde_modifier->mpFeMesh->GetNumNodes(), 121u);
        TS_ASSERT_EQUALS(p_pde_modifier->mpFeMesh->GetNumBoundaryNodes(), 40u);
        TS_ASSERT_EQUALS(p_pde_modifier->mpFeMesh->GetNumElements(), 200u);
        TS_ASSERT_EQUALS(p_pde_modifier->mpFeMesh->GetNumBoundaryElements(), 40u);

        ChasteCuboid<2> bounding_box = p_pde_modifier->mpFeMesh->CalculateBoundingBox();
        TS_ASSERT_DELTA(bounding_box.rGetUpperCorner()[0],  10.0, 1e-5);
        TS_ASSERT_DELTA(bounding_box.rGetUpperCorner()[1],  10.0, 1e-5);
        TS_ASSERT_DELTA(bounding_box.rGetLowerCorner()[0], -10.0, 1e-5);
        TS_ASSERT_DELTA(bounding_box.rGetLowerCorner()[1], -10.0, 1e-5);

        // Coverage
        TS_ASSERT_EQUALS(p_pde_modifier->GetOutputGradient(),false); // Defaults to false
        p_pde_modifier->SetOutputGradient(true);
        TS_ASSERT_EQUALS(p_pde_modifier->GetOutputGradient(),true);
    }

    void TestArchiveEllipticBoxDomainPdeModifier() throw(Exception)
    {
        // Create a file for archiving
        OutputFileHandler handler("archive", false);
        handler.SetArchiveDirectory();
        std::string archive_filename = handler.GetOutputDirectoryFullPath() + "EllipticBoxDomainPdeModifier.arch";

        // Separate scope to write the archive
        {
            // Create PDE and boundary condition objects
            MAKE_PTR_ARGS(UniformSourceEllipticPde<2>, p_pde, (-0.1));
            MAKE_PTR_ARGS(ConstBoundaryCondition<2>, p_bc, (1.0));

            // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
            ChastePoint<2> lower(-10.0, -10.0);
            ChastePoint<2> upper(10.0, 10.0);
            MAKE_PTR_ARGS(ChasteCuboid<2>, p_cuboid, (lower, upper));

            // Create a PDE modifier and set the name of the dependent variable in the PDE
            std::vector<double> data(10);
            for (unsigned i=0; i<10; i++)
            {
                data[i] = i + 0.45;
            }
            Vec vector = PetscTools::CreateVec(data);
            EllipticBoxDomainPdeModifier<2> modifier(p_pde, p_bc, false, p_cuboid, 2.0, vector);
            modifier.SetDependentVariableName("averaged quantity");

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

            // Serialize via pointer
            AbstractCellBasedSimulationModifier<2,2>* const p_modifier = &modifier;
            output_arch << p_modifier;
        }

        // Separate scope to read the archive
        {
            AbstractCellBasedSimulationModifier<2,2>* p_modifier2;

            // Restore the modifier
            std::ifstream ifs(archive_filename.c_str());
            boost::archive::text_iarchive input_arch(ifs);

            input_arch >> p_modifier2;

            // Test that member variables are correct
            TS_ASSERT_EQUALS((static_cast<EllipticBoxDomainPdeModifier<2>*>(p_modifier2))->rGetDependentVariableName(), "averaged quantity");
            TS_ASSERT_DELTA((static_cast<EllipticBoxDomainPdeModifier<2>*>(p_modifier2))->GetStepSize(), 2.0, 1e-5);
            TS_ASSERT_EQUALS((static_cast<EllipticBoxDomainPdeModifier<2>*>(p_modifier2))->AreBcsSetOnBoxBoundary(), true);

            Vec solution = (static_cast<EllipticBoxDomainPdeModifier<2>*>(p_modifier2))->GetSolution();
            ReplicatableVector solution_repl(solution);

            TS_ASSERT_EQUALS(solution_repl.GetSize(), 10u);
            for (unsigned i=0; i<10; i++)
            {
                TS_ASSERT_DELTA(solution_repl[i], i + 0.45, 1e-6);
            }

            delete p_modifier2;
        }
    }

    void TestMeshBasedSquareMonolayer() throw (Exception)
    {
        HoneycombMeshGenerator generator(10,10,0);
        MutableMesh<2,2>* p_mesh = generator.GetMesh();

        std::vector<CellPtr> cells;
        MAKE_PTR(DifferentiatedCellProliferativeType, p_differentiated_type);
        CellsGenerator<UniformCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasicRandom(cells, p_mesh->GetNumNodes(), p_differentiated_type);

        // Make cells with x<5.0 apoptotic (so no source term)
        boost::shared_ptr<AbstractCellProperty> p_apoptotic_property =
                cells[0]->rGetCellPropertyCollection().GetCellPropertyRegistry()->Get<ApoptoticCellProperty>();
        for (unsigned i=0; i<cells.size(); i++)
        {
            c_vector<double,2> cell_location;
            cell_location = p_mesh->GetNode(i)->rGetLocation();
            if (cell_location(0) < 5.0)
            {
                cells[i]->AddCellProperty(p_apoptotic_property);
            }
        }
        TS_ASSERT_EQUALS(p_apoptotic_property->GetCellCount(),50u);

        MeshBasedCellPopulation<2> cell_population(*p_mesh, cells);

        // Set up simulation time for file output
        SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1);

        // Create PDE and boundary condition objects
        MAKE_PTR_ARGS(AveragedSourceEllipticPde<2>, p_pde, (cell_population, -0.1));
        MAKE_PTR_ARGS(ConstBoundaryCondition<2>, p_bc, (1.0));

        // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
        ChastePoint<2> lower(-5.0, -5.0);
        ChastePoint<2> upper(15.0, 15.0);
        MAKE_PTR_ARGS(ChasteCuboid<2>, p_cuboid, (lower, upper));

        // Create a PDE modifier and set the name of the dependent variable in the PDE
        MAKE_PTR_ARGS(EllipticBoxDomainPdeModifier<2>, p_pde_modifier, (p_pde, p_bc, false, p_cuboid));
        p_pde_modifier->SetDependentVariableName("variable");

        // For coverage output the solution gradient
        p_pde_modifier->SetOutputGradient(true);
        p_pde_modifier->SetupSolve(cell_population,"TestAveragedBoxEllipticPdeWithMeshOnSquare");

        // Test the solution at some fixed points to compare with other cell populations
        CellPtr p_cell_0 = cell_population.GetCellUsingLocationIndex(0);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[0], 0, .01e-4);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[1], 0.0, 1e-4);
        TS_ASSERT_DELTA( p_cell_0->GetCellData()->GetItem("variable"), 0.8605, 1e-4);

        TS_ASSERT_DELTA( p_cell_0->GetCellData()->GetItem("variable_grad_x"), -0.0323, 1e-4);
        TS_ASSERT_DELTA( p_cell_0->GetCellData()->GetItem("variable_grad_y"), -0.0179, 1e-4);
    }

    void TestNodeBasedSquareMonolayer() throw (Exception)
    {
        HoneycombMeshGenerator generator(10,10,0);
        MutableMesh<2,2>* p_generating_mesh = generator.GetMesh();
        NodesOnlyMesh<2>* p_mesh = new NodesOnlyMesh<2>;
        p_mesh->ConstructNodesWithoutMesh(*p_generating_mesh, 1.5);

        std::vector<CellPtr> cells;
        MAKE_PTR(DifferentiatedCellProliferativeType, p_differentiated_type);
        CellsGenerator<UniformCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasicRandom(cells, p_mesh->GetNumNodes(), p_differentiated_type);

        // Make cells with x<5.0 apoptotic (so no source term)
        boost::shared_ptr<AbstractCellProperty> p_apoptotic_property =
                cells[0]->rGetCellPropertyCollection().GetCellPropertyRegistry()->Get<ApoptoticCellProperty>();
        for (unsigned i=0; i<cells.size(); i++)
        {
            c_vector<double,2> cell_location;
            cell_location = p_mesh->GetNode(i)->rGetLocation();
            if (cell_location(0) < 5.0)
            {
                cells[i]->AddCellProperty(p_apoptotic_property);
            }
        }
        TS_ASSERT_EQUALS(p_apoptotic_property->GetCellCount(),50u);

        NodeBasedCellPopulation<2> cell_population(*p_mesh, cells);

        // Set up simulation time for file output
        SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1);

        // Create PDE and boundary condition objects
        MAKE_PTR_ARGS(AveragedSourceEllipticPde<2>, p_pde, (cell_population, -0.1));
        MAKE_PTR_ARGS(ConstBoundaryCondition<2>, p_bc, (1.0));

        // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
        ChastePoint<2> lower(-5.0, -5.0);
        ChastePoint<2> upper(15.0, 15.0);
        MAKE_PTR_ARGS(ChasteCuboid<2>, p_cuboid, (lower, upper));

        // Create a PDE modifier and set the name of the dependent variable in the PDE
        MAKE_PTR_ARGS(EllipticBoxDomainPdeModifier<2>, p_pde_modifier, (p_pde, p_bc, false, p_cuboid));
        p_pde_modifier->SetDependentVariableName("variable");

        p_pde_modifier->SetupSolve(cell_population,"TestAveragedBoxEllipticPdeWithNodeOnSquare");

        // Test the solution at some fixed points to compare with other cell populations
        CellPtr p_cell_0 = cell_population.GetCellUsingLocationIndex(0);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[0], 0.0, 1e-4);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[1], 0.0, 1e-4);
        TS_ASSERT_DELTA(p_cell_0->GetCellData()->GetItem("variable"), 0.8605, 1e-4);

        // Clear memory
        delete p_mesh;
    }

    void TestVertexBasedSquareMonolayer() throw (Exception)
    {
        HoneycombVertexMeshGenerator generator(10,10);
        MutableVertexMesh<2,2>* p_mesh = generator.GetMesh();

        p_mesh->Translate(-0.5,-sqrt(3.0)/3); // Shift so cells are on top of those in the above centre based tests

        std::vector<CellPtr> cells;
        MAKE_PTR(DifferentiatedCellProliferativeType, p_differentiated_type);
        CellsGenerator<UniformCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasicRandom(cells, p_mesh->GetNumElements(), p_differentiated_type);

        // Make cells with x<5.0 apoptotic (so no source term)
        boost::shared_ptr<AbstractCellProperty> p_apoptotic_property =
                cells[0]->rGetCellPropertyCollection().GetCellPropertyRegistry()->Get<ApoptoticCellProperty>();
        for (unsigned i=0; i<cells.size(); i++)
        {
            c_vector<double,2> cell_location;
            cell_location = p_mesh->GetCentroidOfElement(i);
            if (cell_location(0) < 5.0)
            {
                cells[i]->AddCellProperty(p_apoptotic_property);
            }
        }
        TS_ASSERT_EQUALS(p_apoptotic_property->GetCellCount(),50u);

        VertexBasedCellPopulation<2> cell_population(*p_mesh, cells);

        // Set up simulation time for file output
        SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1);

        // Create PDE and boundary condition objects
        MAKE_PTR_ARGS(AveragedSourceEllipticPde<2>, p_pde, (cell_population, -0.1));
        MAKE_PTR_ARGS(ConstBoundaryCondition<2>, p_bc, (1.0));

        // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
        ChastePoint<2> lower(-5.0, -5.0);
        ChastePoint<2> upper(15.0, 15.0);
        MAKE_PTR_ARGS(ChasteCuboid<2>, p_cuboid, (lower, upper));

        // Create a PDE modifier and set the name of the dependent variable in the PDE
        MAKE_PTR_ARGS(EllipticBoxDomainPdeModifier<2>, p_pde_modifier, (p_pde, p_bc, false, p_cuboid));
        p_pde_modifier->SetDependentVariableName("variable");

        p_pde_modifier->SetupSolve(cell_population,"TestAveragedBoxEllipticPdeWithVertexOnSquare");

        // Test the solution at some fixed points to compare with other cell populations
        CellPtr p_cell_0 = cell_population.GetCellUsingLocationIndex(0);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[0], 0, 1e-4);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[1], 0, 1e-4);
        TS_ASSERT_DELTA(p_cell_0->GetCellData()->GetItem("variable"), 0.8605, 1e-4);
    }

    void TestPottsBasedSquareMonolayer() throw (Exception)
    {
        PottsMeshGenerator<2> generator(50, 10, 4, 50, 10, 4);
        PottsMesh<2>* p_mesh = generator.GetMesh();

        // Translate and scale so cells are on top of those in the above centre based tests
        p_mesh->Translate(-6.5,-6.5);
        p_mesh->Scale(0.25,0.25 *sqrt(3.0)*0.5);

        std::vector<CellPtr> cells;
        MAKE_PTR(DifferentiatedCellProliferativeType, p_differentiated_type);
        CellsGenerator<UniformCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasicRandom(cells, p_mesh->GetNumElements(), p_differentiated_type);

        // Make cells with x<5.0 apoptotic (so no source term)
        boost::shared_ptr<AbstractCellProperty> p_apoptotic_property =
                cells[0]->rGetCellPropertyCollection().GetCellPropertyRegistry()->Get<ApoptoticCellProperty>();
        for (unsigned i=0; i<cells.size(); i++)
        {
            c_vector<double,2> cell_location;
            cell_location = p_mesh->GetCentroidOfElement(i);
            if (cell_location(0) < 5.0)
            {
                cells[i]->AddCellProperty(p_apoptotic_property);
            }
        }
        TS_ASSERT_EQUALS(p_apoptotic_property->GetCellCount(),50u);

        PottsBasedCellPopulation<2> cell_population(*p_mesh, cells);

        // Set up simulation time for file output
        SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1);

        // Create PDE and boundary condition objects
        MAKE_PTR_ARGS(AveragedSourceEllipticPde<2>, p_pde, (cell_population, -0.1));
        MAKE_PTR_ARGS(ConstBoundaryCondition<2>, p_bc, (1.0));

        // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
        ChastePoint<2> lower(-5.0, -5.0);
        ChastePoint<2> upper(15.0, 15.0);
        MAKE_PTR_ARGS(ChasteCuboid<2>, p_cuboid, (lower, upper));

        // Create a PDE modifier and set the name of the dependent variable in the PDE
        MAKE_PTR_ARGS(EllipticBoxDomainPdeModifier<2>, p_pde_modifier, (p_pde, p_bc, false, p_cuboid));
        p_pde_modifier->SetDependentVariableName("variable");

        p_pde_modifier->SetupSolve(cell_population,"TestAveragedBoxEllipticPdeWithPottsOnSquare");

        // Test the solution at some fixed points to compare with other cell populations
        CellPtr p_cell_0 = cell_population.GetCellUsingLocationIndex(0);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[0], 0.0, 1e-4);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[1], 0.0, 1e-4);
        TS_ASSERT_DELTA(p_cell_0->GetCellData()->GetItem("variable"), 0.8605, 1e-1); // Testing against off-lattice models

        TS_ASSERT_DELTA(p_cell_0->GetCellData()->GetItem("variable"), 0.8513, 1e-4); // Testing against on-lattice models
    }

    void TestCaBasedSquareMonolayer() throw (Exception)
    {
        PottsMeshGenerator<2> generator(10, 0, 0, 10, 0, 0);
        PottsMesh<2>* p_mesh = generator.GetMesh();

        // Scale so cells are on top of those in the above centre based tests
        p_mesh->Scale(1.0,sqrt(3.0)*0.5);

        // Specify where cells lie
        std::vector<unsigned> location_indices;
        for (unsigned i=0; i<100; i++)
        {
            location_indices.push_back(i);
        }

        std::vector<CellPtr> cells;
        MAKE_PTR(DifferentiatedCellProliferativeType, p_differentiated_type);
        CellsGenerator<UniformCellCycleModel, 2> cells_generator;
        cells_generator.GenerateBasicRandom(cells, location_indices.size(), p_differentiated_type);

        // Make cells with x<5.0 apoptotic (so no source term)
        boost::shared_ptr<AbstractCellProperty> p_apoptotic_property =
                cells[0]->rGetCellPropertyCollection().GetCellPropertyRegistry()->Get<ApoptoticCellProperty>();
        for (unsigned i=0; i<cells.size(); i++)
        {
            c_vector<double,2> cell_location;
            cell_location = p_mesh->GetNode(i)->rGetLocation();
            if (cell_location(0) < 5.0)
            {
                cells[i]->AddCellProperty(p_apoptotic_property);
            }
        }
        TS_ASSERT_EQUALS(p_apoptotic_property->GetCellCount(),50u);

        CaBasedCellPopulation<2> cell_population(*p_mesh, cells, location_indices);

        // Set up simulation time for file output
        SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1);

        // Create PDE and boundary condition objects
        MAKE_PTR_ARGS(AveragedSourceEllipticPde<2>, p_pde, (cell_population, -0.1));
        MAKE_PTR_ARGS(ConstBoundaryCondition<2>, p_bc, (1.0));

        // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
        ChastePoint<2> lower(-5.0, -5.0);
        ChastePoint<2> upper(15.0, 15.0);
        MAKE_PTR_ARGS(ChasteCuboid<2>, p_cuboid, (lower, upper));

        // Create a PDE modifier and set the name of the dependent variable in the PDE
        MAKE_PTR_ARGS(EllipticBoxDomainPdeModifier<2>, p_pde_modifier, (p_pde, p_bc, false, p_cuboid));
        p_pde_modifier->SetDependentVariableName("variable");

        p_pde_modifier->SetupSolve(cell_population,"TestAveragedBoxEllipticPdeWithCaOnSquare");

        // Test the solution at some fixed points to compare with other cell populations
        CellPtr p_cell_0 = cell_population.GetCellUsingLocationIndex(0);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[0], 0.0, 1e-4);
        TS_ASSERT_DELTA(cell_population.GetLocationOfCellCentre(p_cell_0)[1], 0.0, 1e-4);
        TS_ASSERT_DELTA(p_cell_0->GetCellData()->GetItem("variable"), 0.8605, 1e-1); // Testing against off-lattice models

        TS_ASSERT_DELTA(p_cell_0->GetCellData()->GetItem("variable"), 0.8513, 1e-4); // Testing against on-lattice models
    }

    void TestEllipticBoxDomainPdeModifierIn1d() throw(Exception)
    {
        // Create mesh
        std::vector<Node<1>*> nodes;
        nodes.push_back(new Node<1>(0, true,  0.0));
        nodes.push_back(new Node<1>(1, false, 1.0));
        nodes.push_back(new Node<1>(2, false, 2.0));
        nodes.push_back(new Node<1>(3, false, 3.0));
        nodes.push_back(new Node<1>(4, true,  4.0));

        NodesOnlyMesh<1> mesh;
        mesh.ConstructNodesWithoutMesh(nodes, 1.5);

        // Create cells
        std::vector<CellPtr> cells;
        MAKE_PTR(DifferentiatedCellProliferativeType, p_differentiated_type);
        CellsGenerator<UniformCellCycleModel, 1> cells_generator;
        cells_generator.GenerateBasicRandom(cells, mesh.GetNumNodes(), p_differentiated_type);

        // Set up cell population
        NodeBasedCellPopulation<1> cell_population(mesh, cells);

        // Set up simulation time for file output
        SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1);

        // Create PDE and boundary condition objects
        MAKE_PTR_ARGS(AveragedSourceEllipticPde<1>, p_pde, (cell_population, -0.1));
        MAKE_PTR_ARGS(ConstBoundaryCondition<1>, p_bc, (1.0));

        // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
        ChastePoint<1> lower(-5.0);
        ChastePoint<1> upper(15.0);
        MAKE_PTR_ARGS(ChasteCuboid<1>, p_cuboid, (lower, upper));

        // Create a PDE modifier and set the name of the dependent variable in the PDE
        MAKE_PTR_ARGS(EllipticBoxDomainPdeModifier<1>, p_pde_modifier, (p_pde, p_bc, false, p_cuboid));
        p_pde_modifier->SetDependentVariableName("variable");

        p_pde_modifier->SetOutputGradient(true);

        p_pde_modifier->SetupSolve(cell_population,"TestEllipticBoxDomainPdeModifierIn1d");

        // Test the solution at some fixed points to compare with other cell populations
        CellPtr p_cell_2 = cell_population.GetCellUsingLocationIndex(2);
        TS_ASSERT_DELTA(p_cell_2->GetCellData()->GetItem("variable"), 0.3172, 1e-2);
        TS_ASSERT_DELTA(p_cell_2->GetCellData()->GetItem("variable_grad_x"), -0.0250, 1e-2);

        // Clear memory
        for (unsigned i=0; i<nodes.size(); i++)
        {
            delete nodes[i];
        }
    }

    void TestEllipticBoxDomainPdeModifierIn3d() throw(Exception)
    {
        // Create a simple mesh
        TetrahedralMesh<3,3> temp_mesh;
        temp_mesh.ConstructCuboid(3,3,3);
        NodesOnlyMesh<3> mesh;
        mesh.ConstructNodesWithoutMesh(temp_mesh, 1.5);

        // Create cells
        std::vector<CellPtr> cells;
        MAKE_PTR(DifferentiatedCellProliferativeType, p_differentiated_type);
        CellsGenerator<UniformCellCycleModel, 3> cells_generator;
        cells_generator.GenerateBasicRandom(cells, mesh.GetNumNodes(), p_differentiated_type);

        // Set up cell population
        NodeBasedCellPopulation<3> cell_population(mesh, cells);

        // Set up simulation time for file output
        SimulationTime::Instance()->SetEndTimeAndNumberOfTimeSteps(1.0, 1);

        // Create PDE and boundary condition objects
        MAKE_PTR_ARGS(AveragedSourceEllipticPde<3>, p_pde, (cell_population, -0.1));
        MAKE_PTR_ARGS(ConstBoundaryCondition<3>, p_bc, (1.0));

        // Create a ChasteCuboid on which to base the finite element mesh used to solve the PDE
        ChastePoint<3> lower(-5.0, -5.0, -5.0);
        ChastePoint<3> upper(15.0, 15.0, 15.0);
        MAKE_PTR_ARGS(ChasteCuboid<3>, p_cuboid, (lower, upper));

        // Create a PDE modifier and set the name of the dependent variable in the PDE
        MAKE_PTR_ARGS(EllipticBoxDomainPdeModifier<3>, p_pde_modifier, (p_pde, p_bc, false, p_cuboid));
        p_pde_modifier->SetDependentVariableName("variable");

        p_pde_modifier->SetOutputGradient(true);

        p_pde_modifier->SetupSolve(cell_population,"TestEllipticBoxDomainPdeModifierIn3d");

        // Test the solution at some fixed points to compare with other cell populations
        CellPtr p_cell_62 = cell_population.GetCellUsingLocationIndex(13);
        TS_ASSERT_DELTA(p_cell_62->GetCellData()->GetItem("variable"), 0.8841, 1e-2);
        TS_ASSERT_DELTA(p_cell_62->GetCellData()->GetItem("variable_grad_x"), -0.0117, 1e-2);
        TS_ASSERT_DELTA(p_cell_62->GetCellData()->GetItem("variable_grad_y"), 0.0510, 1e-2);
        TS_ASSERT_DELTA(p_cell_62->GetCellData()->GetItem("variable_grad_z"), -0.0435, 1e-2);
    }
};

#endif /*TESTELLIPTICBOXDOMAINPDEMODIFIER_HPP_*/


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

#include <nt2/sdk/config/types.hpp>
#include <nt2/sdk/meta/as_real.hpp>
#include <boost/type_traits/is_same.hpp>

#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/basic.hpp>

////////////////////////////////////////////////////////////////////////////////
// Test that as_real is correct w/r to original sign
////////////////////////////////////////////////////////////////////////////////
NT2_TEST_CASE(as_real)
{
  using nt2::meta::as_real;
  using boost::is_same;

  NT2_TEST( (is_same<as_real<double       >::type,double  >::value ));
  NT2_TEST( (is_same<as_real<float        >::type,float   >::value ));
  NT2_TEST( (is_same<as_real<nt2::int64_t >::type,double  >::value ));
  NT2_TEST( (is_same<as_real<nt2::int32_t >::type,float   >::value ));
  NT2_TEST( (is_same<as_real<nt2::uint64_t>::type,double  >::value ));
  NT2_TEST( (is_same<as_real<nt2::uint32_t>::type,float   >::value ));
}


// Copyright (c) 2021 Graphcore Ltd. All rights reserved.
#define BOOST_TEST_MODULE Test_AAPI_loop_accumulate
#include <boost/test/unit_test.hpp>

#include <popart/graph.hpp>
#include <popart/iarray.hpp>
#include <popart/ir.hpp>
#include <popart/names.hpp>
#include <popart/ndarraywrapper.hpp>
#include <popart/op/accumulate.hpp>
#include <popart/op/exchange/hostcopy.hpp>
#include <popart/op/loop.hpp>
#include <popart/optimizervalue.hpp>
#include <popart/session.hpp>
#include <popart/stepio.hpp>
#include <popart/tensor.hpp>
#include <popart/tensorinfo.hpp>
#include <popart/tensors.hpp>
#include <popart/testdevice.hpp>
#include <popart/util.hpp>

#include <onnx/onnx_pb.h>

#include <memory>
#include <tuple>
#include <vector>

using namespace popart;

namespace {

std::tuple<LoopOp *, Graph &> createLoopOp(Ir &ir,
                                           Graph &parentGraph,
                                           const std::string &subgraphName,
                                           const int maxTripCount);

} // namespace

/*
  int accum = 0
  for i in range(10):
    accum += 1

  ==> accum = 10
 */
BOOST_AUTO_TEST_CASE(TestLoopAccumulation) {
  constexpr int loopTripCount = 10;
  TensorInfo info{DataType::FLOAT, Shape{2, 2}};
  const std::vector<float> accumHost(info.nelms(), 0.0f);
  const std::vector<float> oneHost(info.nelms(), 1.0f);
  constexpr float expectedAccumVal = 10.0f;

  auto ir      = std::make_unique<Ir>();
  Graph &graph = ir->getMainGraph();

  ////// Create accum tensor in parent graph.

  TensorId accum    = "accum";
  TensorId accumOut = ir->createIntermediateTensorId(accum);

  graph.getTensors().addVarInit(accum, info, accumHost.data(), {"accum"});

  ////// Create loop op.

  const auto accumLG    = createLoopOp(*ir, graph, "accumLoop", 10);
  LoopOp *accumLoop     = std::get<0>(accumLG);
  Graph &accumLoopGraph = std::get<1>(accumLG);

  ////// actual body: accum += 1

  const auto sgAccum = addScope(accumLoopGraph, accum);
  accumLoop->addLoopInput(std::max(LoopOp::getFirstInputInIndex(),
                                   accumLoop->input->maxIndex() + 1),
                          accum,
                          sgAccum,
                          false);

  const auto one = addScope(accumLoopGraph, TensorId{"one"});
  accumLoopGraph.getTensors().addConstInit(one, info, oneHost.data(), {"one"});

  const TensorId sgAccumOut = ir->createIntermediateTensorId(sgAccum);

  auto accumOp = accumLoopGraph.createConnectedOp<AccumulateOp>(
      {{AccumulateOp::getVarToUpdateInIndex(), sgAccum},
       {AccumulateOp::getUpdaterInIndex(), one}},
      {{AccumulateOp::getUpdatedVarOutIndex(), sgAccumOut}},
      AccumulationType::Add,
      OptimizerValue{},
      Op::Settings{accumLoopGraph, "accum", accumLoopGraph.getScope()});

  accumOp->settings.executionContext = ExecutionContext::Normal;
  accumOp->setup();

  accumLoop->addLoopOutput(
      accumLoop->output->maxIndex() + 1, accumOut, sgAccumOut, false);

  accumLoop->setup();

  // HostStore accumOut
  // Note, instead of anchoring and HostStoring this ActGrad tensor, we could
  // alternatively use loop->addModified on sgAccum Variable, then
  // session->weightsToHost at runtime to get the final value back.

  // Must set DataFlow:
  //  - Must set bps so devicex creates stream callbacks that operate on/expect
  //    the correct amount of data. We use 1 as "batches" and "steps" do not
  //    make sense in this explicit custom program; we do not run the same
  //    program on many batches of data, we just have the one piece of data that
  //    we want to stream back to host.
  //  - Must anchor the HostStore'd tensor as the poplar streams will be created
  //    for the (remapped) anchor tensors, and HostStorex will use this stream.
  //  - TODO(T39576): Remove need to set AnchorReturnType. They implictly
  //    specify how/when to stream a tensor back to host, but we have explictly
  //    described how to do this using HostStores. Currently, we set All as this
  //    ensures the tensor is unconditionally streamed when we want it to be,
  //    and because it is the only one actually implemented.
  constexpr int bps = 1;
  ir->setDataFlow(DataFlow{bps, {{accumOut, AnchorReturnType("All")}}});

  TensorId streamAccumOut = ir->getAnchorRemap().getRight(accumOut);

  auto hostStoreYOp = graph.createConnectedOp<HostStoreOp>(
      {{HostStoreOp::getLocalTensorInIndex(), accumOut}},
      {},
      Onnx::CustomOperators::HostStore,
      Op::Settings{graph, "hostStoreAccumOut"},
      streamAccumOut);

  hostStoreYOp->setup();

  ////////////// Set Ir state required for lowering

  auto &opts                   = ir->getSessionOptions();
  opts.enableExplicitMainLoops = true;
  opts.useHostCopyOps          = true;

  // Sets ScheduledPreLoss on all vertices, which determines if lowered into
  // forward or backward fragment.
  ir->updateVertices();

  // As the final step before lowering, must mark the Ir as "prepared", or the
  // lowering will immediately throw.
  ir->setIsPrepared();

  ///// Lower Ir

  const auto session = InferenceSession::createFromIr(
      std::move(ir), createTestDevice(TEST_TARGET));

  BOOST_TEST_MESSAGE("Created the Session");

  session->prepareDevice();

  BOOST_TEST_MESSAGE("Session has prepared device");

  std::vector<float> accumOutHost(info.nelms());
  NDArrayWrapper<float> accumOutAnchor(accumOutHost.data(), info);
  std::map<TensorId, IArray &> anchors = {{accumOut, accumOutAnchor}};

  StepIO stepio({}, anchors);

  session->weightsFromHost();
  session->run(stepio);

  BOOST_TEST_MESSAGE("Session has run program.");

  // Test actual accumOut against expectedAccumOutVal.

  using boost::test_tools::tolerance;

  for (std::size_t i = 0; i < accumOutHost.size(); ++i) {
    BOOST_TEST(accumOutHost[i] == expectedAccumVal, tolerance(1e-8));
  }
}

namespace {

/**
 * @brief Create and return a LoopOp (with it's initial subgraph) in the parent
 * graph.
 *
 * @param ir The Ir this all happens in.
 * @param parentGraph The graph in which to create the LoopOp. The LoopOp's
 * subgraph will be a child graph of this graph.
 * @param loopName The name of the LoopOp. The LoopOp's subgraph will have
 * '-subgraph' appended to this as its name.
 * @param maxTripCount The max trip count to set on the LoopOp.
 * @return std::tuple<LoopOp *, Graph &> The LoopOp and its subgraph that have
 * been created.
 */
std::tuple<LoopOp *, Graph &> createLoopOp(Ir &ir,
                                           Graph &parentGraph,
                                           const std::string &loopName,
                                           const int maxTripCount) {
  const auto subgraphName = loopName + "-subgraph";

  // Create subgraph of LoopOp.

  Graph &loopSubgraph = ir.createGraph(GraphId{subgraphName});

  // Add mandatory loop iterator tensor to subgraph (is not an output)
  TensorId loopIter = addScope(loopSubgraph, reservedLoopIteratorPrefix());
  loopSubgraph.addInput(loopIter, TensorInfo{DataType::INT32, {}});

  // Add mandatory loop condition tensor to subgraph (is also an output)
  TensorId loopCond = addScope(loopSubgraph, reservedLoopCondPrefix());
  loopSubgraph.addInput(loopCond, TensorInfo{DataType::BOOL, {}});
  loopSubgraph.markAsOutput(loopCond);

  // Create LoopOp in parent.

  Op::Settings loopSettings(parentGraph, loopName);
  loopSettings.executionContext = ExecutionContext::Normal;

  auto loop = parentGraph.createOp<LoopOp>(
      Onnx::Operators::Loop_11, loopSettings, loopSubgraph);

  loop->setTripCountValue(maxTripCount);

  return std::forward_as_tuple(loop, loopSubgraph);
}

} // namespace


#include <numpy_eigen/boost_python_headers.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <sm/timing/Timer.hpp>
using namespace boost::python;

//typedef UniformCubicBSpline<Eigen::Dynamic> UniformCubicBSplineX;

void import_rotational_kinematics_python();
void export_rotations();
void export_transformations();
void export_quaternion_algebra();
void export_homogeneous_coordinates();
void exportTransformation();
void exportHomogeneousPoint();
void exportTimestampCorrectors();
void exportPropertyTree();
void exportEigen();
void exportUncertainVector();
void exportMatrixArchive();
void exportLogging();
void exportNsecTime();
void exportRandom();
void export_eigen_property_tree();
void export_kinematics_property_tree();

void printTiming()
{
    sm::timing::Timing::print(std::cout);
}

BOOST_PYTHON_MODULE(libsm_python)
{
    def("printTiming", &printTiming);
  import_rotational_kinematics_python();
  export_rotations();
  export_transformations();
  export_quaternion_algebra();
  export_homogeneous_coordinates();
  exportTransformation();
  exportHomogeneousPoint();
  exportTimestampCorrectors();
  exportPropertyTree();
  exportEigen();
  exportUncertainVector();
  exportMatrixArchive();
  exportLogging();
  exportNsecTime();
  exportRandom();
  export_eigen_property_tree();
  export_kinematics_property_tree();
}


#pragma once

#include <type_traits>
#include <Eigen/Core>

namespace Eigen {
using Vector2ui = Matrix<unsigned int, 2, 1>;
using Vector3ui = Matrix<unsigned int, 3, 1>;
using Vector4ui = Matrix<unsigned int, 4, 1>;
} // namespace Eigen

namespace vgl {
/*constexpr glm::vec4 test;
template <typename>
struct is_glm_vec : std::false_type {};

template <glm::length_t L, typename T, glm::qualifier Q>
struct is_glm_vec<glm::vec<L, T, Q>> : std::true_type {};

template <typename T>
constexpr bool is_glm_vec_v = is_glm_vec<T>::value;*/
}


// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

#ifndef BOOST_HANA_TEST_AUTO_UNFOLDS_HPP
#define BOOST_HANA_TEST_AUTO_UNFOLDS_HPP

#include <boost/hana/assert.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/fold_left.hpp>
#include <boost/hana/fold_right.hpp>
#include <boost/hana/if.hpp>
#include <boost/hana/integral_constant.hpp>
#include <boost/hana/optional.hpp>
#include <boost/hana/unfold_left.hpp>
#include <boost/hana/unfold_right.hpp>

#include <laws/base.hpp>
#include <support/minimal_product.hpp>
#include "test_case.hpp"

TestCase test_unfold_left{[]{
    namespace hana = boost::hana;

    hana::test::_injection<0> f{};
    auto stop_at = [=](auto stop) {
        return [=](auto x) {
            return hana::if_(hana::equal(stop, x),
                hana::nothing,
                hana::just(::minimal_product(x + hana::int_c<1>, f(x)))
            );
        };
    };

    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_left<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<0>)),
        MAKE_TUPLE()
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_left<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<1>)),
        MAKE_TUPLE(f(hana::int_c<0>))
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_left<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<2>)),
        MAKE_TUPLE(f(hana::int_c<1>), f(hana::int_c<0>))
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_left<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<3>)),
        MAKE_TUPLE(f(hana::int_c<2>), f(hana::int_c<1>), f(hana::int_c<0>))
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_left<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<4>)),
        MAKE_TUPLE(f(hana::int_c<3>), f(hana::int_c<2>), f(hana::int_c<1>), f(hana::int_c<0>))
    ));
}};

TestCase test_unfold_right{[]{
    namespace hana = boost::hana;

    hana::test::_injection<0> f{};
    auto stop_at = [=](auto stop) {
        return [=](auto x) {
            return hana::if_(hana::equal(stop, x),
                hana::nothing,
                hana::just(::minimal_product(f(x), x + hana::int_c<1>))
            );
        };
    };

    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_right<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<0>)),
        MAKE_TUPLE()
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_right<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<1>)),
        MAKE_TUPLE(f(hana::int_c<0>))
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_right<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<2>)),
        MAKE_TUPLE(f(hana::int_c<0>), f(hana::int_c<1>))
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_right<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<3>)),
        MAKE_TUPLE(f(hana::int_c<0>), f(hana::int_c<1>), f(hana::int_c<2>))
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        hana::unfold_right<TUPLE_TAG>(hana::int_c<0>, stop_at(hana::int_c<4>)),
        MAKE_TUPLE(f(hana::int_c<0>), f(hana::int_c<1>), f(hana::int_c<2>), f(hana::int_c<3>))
    ));
}};

// Make sure unfolds can be reversed under certain conditions.
TestCase test_unfold_undo{[]{
    namespace hana = boost::hana;
    using hana::test::ct_eq;

    auto z = ct_eq<999>{};
    auto f = ::minimal_product;
    auto g = [=](auto k) {
        return hana::if_(hana::equal(k, z),
            hana::nothing,
            hana::just(k)
        );
    };

    // Make sure the special conditions are met
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        g(z),
        hana::nothing
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        g(f(ct_eq<0>{}, z)),
        hana::just(::minimal_product(ct_eq<0>{}, z))
    ));
    BOOST_HANA_CONSTANT_CHECK(hana::equal(
        g(f(z, ct_eq<0>{})),
        hana::just(::minimal_product(z, ct_eq<0>{}))
    ));

    // Make sure the reversing works
    {
        auto xs = MAKE_TUPLE();
        BOOST_HANA_CONSTANT_CHECK(hana::equal(
            hana::unfold_left<TUPLE_TAG>(hana::fold_left(xs, z, f), g),
            xs
        ));
        BOOST_HANA_CONSTANT_CHECK(hana::equal(
            hana::unfold_right<TUPLE_TAG>(hana::fold_right(xs, z, f), g),
            xs
        ));
    }
    {
        auto xs = MAKE_TUPLE(ct_eq<0>{});
        BOOST_HANA_CONSTANT_CHECK(hana::equal(
            hana::unfold_left<TUPLE_TAG>(hana::fold_left(xs, z, f), g),
            xs
        ));
        BOOST_HANA_CONSTANT_CHECK(hana::equal(
            hana::unfold_right<TUPLE_TAG>(hana::fold_right(xs, z, f), g),
            xs
        ));
    }
    {
        auto xs = MAKE_TUPLE(ct_eq<0>{}, ct_eq<1>{});
        BOOST_HANA_CONSTANT_CHECK(hana::equal(
            hana::unfold_left<TUPLE_TAG>(hana::fold_left(xs, z, f), g),
            xs
        ));
        BOOST_HANA_CONSTANT_CHECK(hana::equal(
            hana::unfold_right<TUPLE_TAG>(hana::fold_right(xs, z, f), g),
            xs
        ));
    }
    {
        auto xs = MAKE_TUPLE(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{});
        BOOST_HANA_CONSTANT_CHECK(hana::equal(
            hana::unfold_left<TUPLE_TAG>(hana::fold_left(xs, z, f), g),
            xs
        ));
        BOOST_HANA_CONSTANT_CHECK(hana::equal(
            hana::unfold_right<TUPLE_TAG>(hana::fold_right(xs, z, f), g),
            xs
        ));
    }
}};

#endif // !BOOST_HANA_TEST_AUTO_UNFOLDS_HPP


#pragma once

#include <cassert>
#include <list>
#include <unordered_map>
#include <vector>

#include <boost/heap/fibonacci_heap.hpp>

namespace hypergraphlib {

/* A collection of distinct values, ordered by their keys. The key for every
 * value is initially zero.
 *
 * Supports incrementing the key of a value in constant time as well as removing
 * one of the values with maximum key in time linear to the number of buckets.
 *
 * Useful for computing vertex orderings for unweighted hypergraphs. See [M'05]
 * for more details.
 */
class BucketHeap {
public:
  /* Create a bucket list with the given values and capacity (number of
   * buckets). The values should be unique.
   *
   * Time complexity: O(n), where n in the number of values.
   */
  BucketHeap(std::vector<int> values, size_t capacity);

  /* Increment the key of the value.
   *
   * Time complexity: O(1).
   */
  void increment(int value);

  /* Pop an arbitrary value with a maximum key.
   *
   * Time complexity: Expected is O(1), worst-case is O(b), where b is the
   * number of buckets.
   */
  int pop();

  /* Pop a (key, value) pair with a maximum key.
   *
   * Time complexity: Expected is O(1), worst-case is O(b), where b is the
   * number of buckets.
   */
  std::pair<size_t, int> pop_key_val();

private:
  const size_t capacity_;

  // buckets_[i] is a collection of all values with key = i
  std::vector<std::list<int>> buckets_;

  // A mapping of values to their keys
  std::unordered_map<int, size_t> val_to_keys_;

  // A mapping of values to their iterators (for fast deletion)
  std::unordered_map<int, std::list<int>::iterator> val_to_its_;

  // The current maximum key
  size_t max_key_;
};

/* Wrapper of boost::fibonacci_heap that conforms to the BucketHeap interface
 */
template<typename EdgeWeightType>
class FibonacciHeap {
public:
  FibonacciHeap(const std::vector<int> &values, [[maybe_unused]] size_t capacity) {
    for (const int v : values) {
      auto handle = heap_.push({0, v});
      const auto[it, inserted] = handles_.insert({v, handle});
      assert(inserted);
    }
  }

  /* Increment the key of the value.
   *
   * Time complexity: constant
   */
  void increment(const int value, const EdgeWeightType amount) {
    auto handle = handles_.at(value);
    auto[key, val] = *handle;
    *handle = {key + amount, val};
    heap_.increase(handle);
  }

  /* Pop an arbitrary value with a maximum key.
   *
   * Time complexity: constant
   */
  int pop() {
    return pop_key_val().second;
  }

  std::pair<EdgeWeightType, int> pop_key_val() {
    const auto pair = heap_.top();
    heap_.pop();
    return pair;
  }

private:
  // Elements are ordered by their edge weight, and keep a reference to the vertex ID
  using element_t = std::pair<EdgeWeightType, int>;
  using handle_t = typename boost::heap::fibonacci_heap<element_t>::handle_type;

  std::unordered_map<int, handle_t> handles_;

  boost::heap::fibonacci_heap<element_t> heap_;
};

}


/*
Copyright (c) 2015-2019, Florian Sittel (www.lettis.net) and Daniel Nagel
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. 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.

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.
*/
#pragma once

#include <vector>
#include <map>
#include <set>
#include <stdexcept>
#include <string>

#include <boost/program_options.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <boost/numeric/ublas/io.hpp>

#include "tools.hpp"
/*! \file
 * \brief Most Probable Path Clustering
 *
 * \sa \link Clustering::MPP
 */

namespace Clustering {
  /*!
   * \brief functions related to "Most Probable Path"-clustering
   *
   * This module contains all function for dynamical clustering. In contrast to
   * density-based clustering, can it only be applied to previously clustered
   * trajectories. The idea is to create, based on a microstate input, a
   * coarse-grained model (macrostates).
   * The most probable path depends strongly on the selected timescale (mpp
   * time). If the input was dynamically cored, the mpp time needs to be
   * greater than the coring time.
   */
  namespace MPP {
    //! BOOST implementation of a sparse matrix for floats
    using SparseMatrixF = boost::numeric::ublas::mapped_matrix<float>;
    //! Neighborhood per frame
    using Neighborhood = Clustering::Tools::Neighborhood;
    //! read (row-normalized) transition matrix from file
    SparseMatrixF
    read_transition_probabilities(std::string fname);
    //! count transitions from one to the other cluster with certain lag
    //! and return as count matrix (row/col := from/to)
    SparseMatrixF
    transition_counts(std::vector<std::size_t> trajectory
                    , std::vector<std::size_t> concat_limits
                    , std::size_t n_lag_steps
                    , std::size_t i_max = 0);
    //! same as 'transition_counts', but with reweighting account for
    //! differently sized trajectory chunks (as given by concat_limits)
    SparseMatrixF
    weighted_transition_counts(std::vector<std::size_t> trajectory
                             , std::vector<std::size_t> concat_limits
                             , std::size_t n_lag_steps);
    //! compute transition matrix from counts by normalization of rows
    SparseMatrixF
    row_normalized_transition_probabilities(SparseMatrixF count_matrix
                                          , std::set<std::size_t> microstate_names);
    //! update transition matrix after lumping states into sinks
    SparseMatrixF
    updated_transition_probabilities(SparseMatrixF transition_matrix
                                   , std::map<std::size_t, std::size_t> sinks
                                   , std::map<std::size_t, std::size_t> pops);
    //! compute immediate future (i.e. without lag) of every state from highest probable transitions;
    //! exclude self-transitions.
    std::map<std::size_t, std::size_t>
    single_step_future_state(SparseMatrixF transition_matrix,
                             std::set<std::size_t> cluster_names,
                             float q_min,
                             std::map<std::size_t, float> min_free_energy);
    //! for every state, compute most probable path by following
    //! the 'future_state'-mapping recursively
    std::map<std::size_t, std::vector<std::size_t>>
    most_probable_path(std::map<std::size_t, std::size_t> future_state, std::set<std::size_t> cluster_names);
    //! compute cluster populations
    std::map<std::size_t, std::size_t>
    microstate_populations(std::vector<std::size_t> clusters, std::set<std::size_t> cluster_names);
    //! assign every state the lowest free energy value
    //! of all of its frames.
    std::map<std::size_t, float>
    microstate_min_free_energy(const std::vector<std::size_t>& clustering,
                               const std::vector<float>& free_energy);
    //! compute path sinks, i.e. states of highest metastability,
    //! and lowest free energy per path. these sinks will be states all other
    //! states of the given path will be lumped into.
    std::map<std::size_t, std::size_t>
    path_sinks(std::vector<std::size_t> clusters,
               std::map<std::size_t, std::vector<std::size_t>> mpp,
               SparseMatrixF transition_matrix,
               std::set<std::size_t> cluster_names,
               float q_min,
               std::vector<float> free_energy);
    //! lump states based on path sinks and return new trajectory.
    //! new microstates will have IDs of sinks.
    std::vector<std::size_t>
    lumped_trajectory(std::vector<std::size_t> trajectory,
                      std::map<std::size_t, std::size_t> sinks);
    //! run clustering for given Q_min value
    std::tuple<std::vector<std::size_t>
             , std::map<std::size_t, std::size_t>
             , SparseMatrixF>
    fixed_metastability_clustering(std::vector<std::size_t> initial_trajectory,
                                   SparseMatrixF trans_prob,
                                   float q_min,
                                   std::vector<float> free_energy);
    /*!
     * \brief MPP clustering control function and user interface
     *
     * \param input input file with microstate trajectory
     * \param basename name format for output files
     * \param lagtime lag for transition estimation in units of frame numbers
     * \param qmin-from lower limit for metastability (Q_min)
     * \param qmin-to upper limit for metastability (Q_min)
     * \param qmin-step stepping for metastability (Q_min)
     * \param concat-nframes no. of frames per trajectory.
     * \param concat-limits length of concated trajectories.
     * \return void
     * \note Lagtime should be greater than the coring time/ smallest
     *       timescale.
     */
    void
    main(boost::program_options::variables_map args);
  } // end namespace Clustering::MPP
} // end namespace Clustering


// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "Framework/TestingFramework.hpp"

#include <boost/functional/hash.hpp>
#include <cstddef>
#include <numeric>
#include <unordered_map>
#include <utility>
#include <vector>

#include "DataStructures/DataBox/Tag.hpp"
#include "DataStructures/Index.hpp"
#include "DataStructures/SliceIterator.hpp"
#include "DataStructures/Variables.hpp"
#include "Domain/Structure/Direction.hpp"
#include "Domain/Structure/DirectionMap.hpp"
#include "Domain/Structure/Element.hpp"
#include "Domain/Structure/ElementId.hpp"
#include "Domain/Structure/Neighbors.hpp"
#include "Evolution/DgSubcell/CorrectPackagedData.hpp"
#include "Evolution/DgSubcell/Mesh.hpp"
#include "Evolution/DgSubcell/Projection.hpp"
#include "Evolution/DiscontinuousGalerkin/MortarData.hpp"
#include "NumericalAlgorithms/Spectral/Mesh.hpp"
#include "NumericalAlgorithms/Spectral/Spectral.hpp"
#include "Time/Slab.hpp"
#include "Time/Time.hpp"
#include "Time/TimeStepId.hpp"
#include "Utilities/Gsl.hpp"
#include "Utilities/TMPL.hpp"

namespace {
struct Var1 : db::SimpleTag {
  using type = Scalar<DataVector>;
};

template <size_t Dim>
struct Var2 : db::SimpleTag {
  using type = tnsr::i<DataVector, Dim, Frame::Inertial>;
};

template <size_t Dim>
void test() {
  CAPTURE(Dim);
  using Vars = Variables<tmpl::list<Var1, Var2<Dim>>>;
  const Mesh<Dim> volume_dg_mesh{5, Spectral::Basis::Legendre,
                                 Spectral::Quadrature::GaussLobatto};
  const Mesh<Dim> volume_subcell_mesh =
      evolution::dg::subcell::fd::mesh(volume_dg_mesh);
  DirectionMap<Dim, Neighbors<Dim>> neighbors{};
  for (size_t i = 0; i < 2 * Dim; ++i) {
    neighbors[gsl::at(Direction<Dim>::all_directions(), i)] =
        Neighbors<Dim>{{ElementId<Dim>{i + 1, {}}}, {}};
  }
  const Element<Dim> element{ElementId<Dim>{0, {}}, neighbors};
  const TimeStepId time_step_id{true, 1, Time{Slab{1.1, 4.4}, {3, 10}}};

  CAPTURE(volume_dg_mesh);
  CAPTURE(volume_subcell_mesh);
  for (size_t direction_to_check = 0; direction_to_check < Dim;
       ++direction_to_check) {
    CAPTURE(direction_to_check);
    Index<Dim> volume_face_extents = volume_subcell_mesh.extents();
    ++volume_face_extents[direction_to_check];
    Vars lower_packaged_data{volume_face_extents.product()};
    Vars upper_packaged_data{volume_face_extents.product()};
    const size_t number_of_independent_components = Variables<
        tmpl::list<Var1, Var2<Dim>>>::number_of_independent_components;
    const auto set_volume_data = [&lower_packaged_data,
                                  &upper_packaged_data]() {
      std::iota(lower_packaged_data.data(),
                lower_packaged_data.data() + lower_packaged_data.size(), 1.0);
      std::iota(upper_packaged_data.data(),
                upper_packaged_data.data() + upper_packaged_data.size(),
                1.0 + upper_packaged_data.size());
    };
    set_volume_data();
    // Save a copy of the lower/upper data so we can compare points in the
    // volume/away from the interfaces.
    const Vars interior_lower_packaged_data = lower_packaged_data;
    const Vars interior_upper_packaged_data = upper_packaged_data;

    std::unordered_map<std::pair<Direction<Dim>, ElementId<Dim>>,
                       evolution::dg::MortarData<Dim>,
                       boost::hash<std::pair<Direction<Dim>, ElementId<Dim>>>>
        mortar_data{};
    const Direction<Dim> upper{direction_to_check, Side::Upper};
    const Direction<Dim> lower{direction_to_check, Side::Lower};
    const std::pair upper_neighbor{upper,
                                   *element.neighbors().at(upper).begin()};
    const std::pair lower_neighbor{lower,
                                   *element.neighbors().at(lower).begin()};
    evolution::dg::MortarData<Dim>& upper_mortar_data =
        mortar_data[upper_neighbor] = {};
    evolution::dg::MortarData<Dim>& lower_mortar_data =
        mortar_data[lower_neighbor] = {};

    const Mesh<Dim - 1> dg_face_mesh =
        volume_dg_mesh.slice_away(direction_to_check);
    std::vector<double> upper_neighbor_data(
        number_of_independent_components *
        dg_face_mesh.number_of_grid_points());
    std::iota(upper_neighbor_data.begin(), upper_neighbor_data.end(),
              1.0 + 2.0 * upper_packaged_data.size());
    std::vector<double> lower_neighbor_data(
        number_of_independent_components *
        dg_face_mesh.number_of_grid_points());
    std::iota(
        lower_neighbor_data.begin(), lower_neighbor_data.end(),
        1.0 + 2.0 * upper_packaged_data.size() + upper_neighbor_data.size());

    upper_mortar_data.insert_neighbor_mortar_data(time_step_id, dg_face_mesh,
                                                  upper_neighbor_data);
    lower_mortar_data.insert_neighbor_mortar_data(time_step_id, dg_face_mesh,
                                                  lower_neighbor_data);

    // Check with only remote data
    evolution::dg::subcell::correct_package_data<false>(
        make_not_null(&lower_packaged_data),
        make_not_null(&upper_packaged_data), direction_to_check, element,
        volume_subcell_mesh, mortar_data);

    const size_t volume_grid_points = volume_face_extents.product();
    const size_t slice_grid_points =
        volume_face_extents.slice_away(direction_to_check).product();
    const Mesh<Dim - 1> subcell_face_mesh =
        volume_subcell_mesh.slice_away(direction_to_check);
    const auto perform_face_check = [&dg_face_mesh, direction_to_check,
                                     slice_grid_points, &subcell_face_mesh,
                                     &volume_face_extents, volume_grid_points](
                                        const auto& face_dg_data,
                                        const auto& volume_packaged_data,
                                        const size_t subcell_index) {
      Vars face_vars_data{dg_face_mesh.number_of_grid_points()};
      std::copy(face_dg_data.begin(), face_dg_data.end(),
                face_vars_data.data());
      if constexpr (Dim > 1) {
        face_vars_data = evolution::dg::subcell::fd::project(
            face_vars_data, dg_face_mesh, subcell_face_mesh.extents());
      } else {
        (void)subcell_face_mesh;
      }
      for (SliceIterator si(volume_face_extents, direction_to_check,
                            subcell_index);
           si; ++si) {
        CAPTURE(si.volume_offset());
        CAPTURE(si.slice_offset());
        for (size_t i = 0; i < number_of_independent_components; ++i) {
          CAPTURE(i);
          CHECK(volume_packaged_data
                    .data()[i * volume_grid_points + si.volume_offset()] ==
                approx(face_vars_data
                           .data()[i * slice_grid_points + si.slice_offset()]));
        }
      }
    };
    const auto perform_interior_check =
        [direction_to_check, &volume_face_extents, volume_grid_points](
            const auto& expected_volume_packaged_data,
            const auto& volume_packaged_data, const size_t start_index,
            const size_t one_past_end_index) {
          for (size_t slice_index = start_index;
               slice_index < one_past_end_index; ++slice_index) {
            for (SliceIterator si(volume_face_extents, direction_to_check,
                                  slice_index);
                 si; ++si) {
              for (size_t i = 0; i < number_of_independent_components; ++i) {
                CHECK(volume_packaged_data.data()[i * volume_grid_points +
                                                  si.volume_offset()] ==
                      approx(expected_volume_packaged_data
                                 .data()[i * volume_grid_points +
                                         si.volume_offset()]));
              }
            }
          }
        };

    perform_face_check(upper_neighbor_data, upper_packaged_data,
                       volume_face_extents[direction_to_check] - 1);
    perform_face_check(lower_neighbor_data, lower_packaged_data, 0);
    perform_interior_check(interior_upper_packaged_data, upper_packaged_data, 0,
                           volume_face_extents[direction_to_check] - 1);
    perform_interior_check(interior_lower_packaged_data, lower_packaged_data, 1,
                           volume_face_extents[direction_to_check]);

    // Reset volume data and then check that we can project both local and
    // remote data (note the `true` template parameter to
    // `correct_package_data`)
    set_volume_data();

    std::vector<double> upper_local_data(number_of_independent_components *
                                         dg_face_mesh.number_of_grid_points());
    std::iota(upper_local_data.begin(), upper_local_data.end(), 1.0e6);
    std::vector<double> lower_local_data(number_of_independent_components *
                                         dg_face_mesh.number_of_grid_points());
    std::iota(lower_local_data.begin(), lower_local_data.end(), 1.0e7);
    upper_mortar_data.insert_local_mortar_data(time_step_id, dg_face_mesh,
                                               upper_local_data);
    lower_mortar_data.insert_local_mortar_data(time_step_id, dg_face_mesh,
                                               lower_local_data);

    evolution::dg::subcell::correct_package_data<true>(
        make_not_null(&lower_packaged_data),
        make_not_null(&upper_packaged_data), direction_to_check, element,
        volume_subcell_mesh, mortar_data);

    perform_face_check(upper_neighbor_data, upper_packaged_data,
                       volume_face_extents[direction_to_check] - 1);
    perform_face_check(lower_neighbor_data, lower_packaged_data, 0);
    perform_face_check(upper_local_data, lower_packaged_data,
                       volume_face_extents[direction_to_check] - 1);
    perform_face_check(lower_local_data, upper_packaged_data, 0);

    perform_interior_check(interior_upper_packaged_data, upper_packaged_data, 1,
                           volume_face_extents[direction_to_check] - 1);
    perform_interior_check(interior_lower_packaged_data, lower_packaged_data, 1,
                           volume_face_extents[direction_to_check] - 1);

    // Check that if the local data is in the map but not requested to be
    // overwritten then we don't overwrite it.
    set_volume_data();

    evolution::dg::subcell::correct_package_data<false>(
        make_not_null(&lower_packaged_data),
        make_not_null(&upper_packaged_data), direction_to_check, element,
        volume_subcell_mesh, mortar_data);

    perform_face_check(upper_neighbor_data, upper_packaged_data,
                       volume_face_extents[direction_to_check] - 1);
    perform_face_check(lower_neighbor_data, lower_packaged_data, 0);

    perform_interior_check(interior_upper_packaged_data, upper_packaged_data, 0,
                           volume_face_extents[direction_to_check] - 1);
    perform_interior_check(interior_lower_packaged_data, lower_packaged_data, 1,
                           volume_face_extents[direction_to_check]);
  }
}
}  // namespace

SPECTRE_TEST_CASE("Unit.Evolution.Subcell.CorrectPackagedData",
                  "[Evolution][Unit]") {
  test<1>();
  test<2>();
  test<3>();
}


#include "OT/Base/PvwBaseOT.h"
#include "OT/Base/Math/DMC.h"
#include "Crypto/PRNG.h"
#include "Crypto/sha1.h"
#include "Network/Channel.h"
#include "cryptopp/osrng.h"
#include "Common/Log.h"

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>

//#include <boost/thread/tss.hpp>
//void Cleanup_Miracl(Miracl* miracl)
//{
//	if (miracl)
//	{
//		bOPRF::Log::out << "deleting Miracle" << bOPRF::Log::endl;
//		delete miracl;
//	}
//}

using namespace std;
namespace bOPRF {

	const char* role_to_str(OTRole role)
	{
		if (role == Receiver)
			return "Receiver";
		if (role == Sender)
			return "Sender";
		return "Both";
	}

	OTRole INV_ROLE(OTRole role)
	{
		if (role == Receiver)
			return Sender;
		if (role == Sender)
			return Receiver;
		else
			return Both;
	}

	void send_if_ot_sender(Channel& channel, vector<ByteStream>& os, OTRole role)
	{

		if (role == Sender)
		{
			channel.asyncSendCopy(os[0].data(), os[0].size());
			//os[0].Send(channel);
		}
		else if (role == Receiver)
		{

			channel.recv(os[1]);
			//os[1].setp(0);
			//os[1].Receive(channel);
		}
		else
		{
			// both sender + receiver

			channel.asyncSendCopy(os[0]);
			channel.recv(os[1]);
			//os[0].Send(channel);
			//os[1].setp(0);
			//os[1].Receive(channel);
			//P->send_receive_player(os);
		}
	}

	void send_if_ot_receiver(Channel& channel, vector<ByteStream>& os, OTRole role)
	{
		if (role == Receiver)
		{
			channel.asyncSendCopy(os[0]);
		}
		else if (role == Sender)
		{
			channel.recv(os[1]);
			//P->receive(os[1]);
		}
		else
		{
			// both
			channel.asyncSendCopy(os[0]);
			channel.recv(os[1]);
			//P->send_receive_player(os);
		}
	}

	/*
	 * pack/unpack routines for Miracl data types
	 */

	void pack(ByteStream& s, const Big& z)
	{
		u8 data[50];
		i32 len = to_binary(z, 50, (char*)data, false);
		s.append((u8*)&len, sizeof(u32));
		s.append(data, len);
	}

	void unpack(Big& z, ByteStream& s)
	{
		u8 data[50];
		i32 len;
		s.consume((u8*)&len, sizeof(i32));
		s.consume(data, len);
		z = from_binary(len, (char*)data);
	}

	void pack(ByteStream& s, const ECn& P)
	{
		Big x, y;
		P.get(x, y);
		pack(s, x);
		pack(s, y);
	}

	void unpack(ECn& P, ByteStream& s)
	{
		Big x, y;
		unpack(x, s);
		unpack(y, s);
		P = ECn(x, y);
	}

	//#define BASEOT_DEBUG

		// Run the PVW OTs
	void Exec_OT(vector< vector<ECn> >& Miracl_Sender_Inputs,
		BitVector& OT_Receiver_Inputs,
		vector<ECn>& Miracl_Receiver_Outputs,
		const CRS& crs,
		csprng& Miracl_RNG,
		PRNG& G,
		Channel& channel,
		OTRole role)
	{
		u64 n = OT_Receiver_Inputs.size();
		//Log::out << Log::PvwBaseOT << "Starting base OTs as " << role_to_str(role) << ", n = " << n << Log::endl;
		vector<ByteStream> strm(2);

		Big z;
		vector<SK> sk(n);
		PK pk;
		if (role & Receiver)
		{
			// Generate my receiver inputs
			OT_Receiver_Inputs.randomize(G);
			for (u64 i = 0; i < n; i++)
			{
				// Generate public keys on my branch
				KeyGen(sk[i], pk, OT_Receiver_Inputs[i], crs, Miracl_RNG);

				pack(strm[0], pk.g);
				pack(strm[0], pk.h);
			}
		}
		strm[1].setp(0);

		// Send receiver's public keys over
		send_if_ot_receiver(channel, strm, role);

		ECn c0, c1;

		if (role & Sender)
		{
			strm[0].setp(0);
			for (u64 i = 0; i < n; i++)
			{
				// Generate sender inputs
				z = strong_rand(&Miracl_RNG, crs.bit_size(), 2);
				Miracl_Sender_Inputs[i][0] = z*crs.get_g(0);
				z = strong_rand(&Miracl_RNG, crs.bit_size(), 2);
				Miracl_Sender_Inputs[i][1] = z*crs.get_g(0);

				// Unpack public keys, encrypt my two messages on the correct
				// branch and send them back
				unpack(pk.g, strm[1]);
				unpack(pk.h, strm[1]);

				pk.Encrypt(c0, c1, Miracl_Sender_Inputs[i][0], 0, crs, Miracl_RNG);
				pack(strm[0], c0);
				pack(strm[0], c1);
#ifdef BASEOT_DEBUG
				//Log::out << "m[" << i << ", 0] = " << Miracl_Sender_Inputs[i][0] << Log::endl;
				pack(strm[0], Miracl_Sender_Inputs[i][0]);
#endif
				pk.Encrypt(c0, c1, Miracl_Sender_Inputs[i][1], 1, crs, Miracl_RNG);
				pack(strm[0], c0);
				pack(strm[0], c1);
#ifdef BASEOT_DEBUG
				//Log::out << "m[" << i << ", 1] = " << Miracl_Sender_Inputs[i][1] << Log::endl;
				pack(strm[0], Miracl_Sender_Inputs[i][1]);
#endif
			}
		}

		// Sender sends ciphertexts over
		strm[1].setp(0);
		send_if_ot_sender(channel, strm, role);

#ifdef BASEOT_DEBUG
		ECn m0, m1;
#endif

		if (role & Receiver)
		{
			// Now unpack the received ciphertexts, decrypt the one we want
			// and store it
			for (u64 i = 0; i < n; i++)
			{
				unpack(c0, strm[1]);
				unpack(c1, strm[1]);
#ifdef BASEOT_DEBUG
				unpack(m0, strm[1]);
#endif
				if (OT_Receiver_Inputs[i] == 0)
				{
					sk[i].Decrypt(Miracl_Receiver_Outputs[i], c0, c1);
#ifdef BASEOT_DEBUG
					if (Miracl_Receiver_Outputs[i] != m0)
					{
						Log::out << "Bad PvwBaseOT message received" << Log::endl;
						Log::out << "Received   " << Miracl_Receiver_Outputs[i] << Log::endl;
						Log::out << "wanted m0  " << m0 << Log::endl;
						throw std::runtime_error("rt error at " LOCATION);
					}
#endif
				}
				unpack(c0, strm[1]);
				unpack(c1, strm[1]);
#ifdef BASEOT_DEBUG
				unpack(m1, strm[1]);
#endif
				if (OT_Receiver_Inputs[i] == 1)
				{
					sk[i].Decrypt(Miracl_Receiver_Outputs[i], c0, c1);
#ifdef BASEOT_DEBUG
					if (Miracl_Receiver_Outputs[i] != m1)
					{
						Log::out << "Bad PvwBaseOT message " << i << " received" << Log::endl;
						Log::out << "Received   " << Miracl_Receiver_Outputs[i] << Log::endl;
						Log::out << "wanted m1  " << m1 << Log::endl;
						throw std::runtime_error("rt error at " LOCATION);
					}
#endif
				}

				//Log::out << Log::PvwBaseOT << "m"<< OT_Receiver_Inputs.get_bit(i) <<"[" << i << "] = " << Miracl_Receiver_Outputs[i] << Log::endl;

			}
		}
		//Log::out << Log::PvwBaseOT << "Exit base OT" << Log::endl;
	}

	void PvwBaseOT::exec_base(PRNG& G)
	{
		// Set up crs
	  CRS crs(&(*GetPrecision()));
		//Log::out << "check 0" << Log::endl;

		// Initialize a secure random number generator for Miracl
		csprng Miracl_RNG;
		u8 data[100];
		//Log::out << "check 1" << Log::endl;
		G.get_u8s(data, 100);
		//CryptoPP::OS_GenerateRandomBlock(false, data, sizeof(u8) * 100);

		strong_init(&Miracl_RNG, 100, (char*)data, 0L);
		///Log::out << "check 2" << Log::endl;

		vector< vector<ECn> > Miracl_Sender_Inputs(nOT, vector<ECn>(2));
		vector<ECn>           Miracl_Receiver_Outputs(nOT);

		Exec_OT(Miracl_Sender_Inputs, receiver_inputs, Miracl_Receiver_Outputs, crs, Miracl_RNG, G, mChannel, mOTRole);

		ByteStream s;
		u8 buff[SHA1::HashSize];
		//CBC_MAC cbc;
		SHA1 sha;
		// Hash PVW output into byte strings
		for (int i = 0; i < nOT; i++)
		{
			if (mOTRole & Sender)
			{
				s.setp(0);
				pack(s, Miracl_Sender_Inputs[i][0]);

				sha.Reset();
				sha.Update(s.data(), s.size());
				sha.Final(buff);
				sender_inputs[i][0] = *(block*)buff;

				//cbc.zero_key();
				//cbc.Update(s);
				//cbc.Finalize(sender_inputs[i][0]);
#ifdef BASEOT_DEBUG
				s.setp(0);
				pack(s, Miracl_Sender_Inputs[i][0]);
				Log::out << Log::PvwBaseOT << "m[" << i << ", 0] s = " << s << Log::endl;
				mChannel.Send(s);
				s.setp(0);
				s.append(sender_inputs[i][0]);
				mChannel.AsyncSendCopy(s);
				Log::out << Log::PvwBaseOT << "m[" << i << ", 0]   = " << sender_inputs[i][0] << Log::endl;
#endif
				s.setp(0);
				pack(s, Miracl_Sender_Inputs[i][1]);
				sha.Reset();
				sha.Update(s.data(), s.size());
				sha.Final(buff);

				//cbc.zero_key();
				//cbc.Update(s);
				//cbc.Finalize(sender_inputs[i][1]);
				sender_inputs[i][1] = *(block*)buff;
#ifdef BASEOT_DEBUG
				s.setp(0);
				pack(s, Miracl_Sender_Inputs[i][1]);
				mChannel.Send(s);
				Log::out << Log::PvwBaseOT << "m[" << i << ", 1] s = " << s << Log::endl;

				s.setp(0);
				s.append(sender_inputs[i][1]);
				mChannel.AsyncSendCopy(s);
				Log::out << Log::PvwBaseOT << "m[" << i << ", 1]   = " << sender_inputs[i][1] << Log::endl;
#endif
			}
			if (mOTRole & Receiver)
			{
				s.setp(0);
				pack(s, Miracl_Receiver_Outputs[i]);
				sha.Reset();
				sha.Update(s.data(), s.size());
				sha.Final(buff);

				receiver_outputs[i] = *(block*)buff;

				//cbc.zero_key();
				//cbc.Update(s);
				//cbc.Finalize(receiver_outputs[i]);

#ifdef BASEOT_DEBUG
				Log::out << Log::PvwBaseOT << "s " << s << Log::endl;
				ECn ecm0, ecm1;
				block m0, m1;

				s.setp(0);
				mChannel.recv(s);
				unpack(ecm0, s);
				s.setp(0);
				mChannel.recv(s);
				s.consume(m0);

				s.setp(0);
				mChannel.recv(s);
				unpack(ecm1, s);
				s.setp(0);
				mChannel.recv(s);
				s.consume(m1);

				if (receiver_inputs[i])
				{
					if (Miracl_Receiver_Outputs[i] != ecm1)
					{
						Log::out << "Bad PvwBaseOT Miracl message " << i << " received" << Log::endl;
						Log::out << "Received   " << Miracl_Receiver_Outputs[i] << Log::endl;
						Log::out << "wanted m1  " << ecm1 << Log::endl;
						throw std::runtime_error("rt error at " LOCATION);
					}

					if (receiver_outputs[i] != m1)
					{
						Log::out << "Bad PvwBaseOT message " << i << " received" << Log::endl;
						Log::out << "Received   " << receiver_outputs[i] << Log::endl;
						Log::out << "wanted m1  " << m1 << Log::endl;
						throw std::runtime_error("rt error at " LOCATION);
					}
				}
				else
				{

					if (Miracl_Receiver_Outputs[i] != ecm0)
					{
						Log::out << "Bad PvwBaseOT Miracl message " << i << " received" << Log::endl;
						Log::out << "Received   " << Miracl_Receiver_Outputs[i] << Log::endl;
						Log::out << "wanted m0  " << ecm0 << Log::endl;
						throw std::runtime_error("rt error at " LOCATION);
					}

					if (receiver_outputs[i] != m0)
					{
						Log::out << "Bad PvwBaseOT message " << i << " received" << Log::endl;
						Log::out << "Received   " << receiver_outputs[i] << Log::endl;
						Log::out << "wanted m0  " << m0 << Log::endl;
						throw std::runtime_error("rt error at " LOCATION);
					}
				}
#endif
			}

		}
		deletePercision();
		//delete GetPrecision();
		//Log::out << "base ots done" << Log::endl;
	}

	void PvwBaseOT::check()
	{
		ByteStream os;
		block tmp;

		for (int i = 0; i < nOT; i++)
		{
			if (mOTRole & Sender)
			{
				// send both inputs over
				os.append(sender_inputs[i][0]);
				os.append(sender_inputs[i][1]);

				if (eq(sender_inputs[i][0], sender_inputs[i][1]))
					throw std::runtime_error("rt error at " LOCATION);

				mChannel.asyncSendCopy(os);
			}

			if (mOTRole & Receiver)
			{
				mChannel.recv(os);

				os.consume((u8*)&tmp, sizeof(block));

				if (receiver_inputs[i] == 1)
				{
					os.consume((u8*)&tmp, sizeof(block));
				}

				if (neq(tmp, receiver_outputs[i]))
				{
					Log::out << "Base Incorrect OT" << Log::endl;
					Log::out << "I        have " << receiver_outputs[i] << Log::endl;
					Log::out << "but they have " << tmp << Log::endl;

					throw std::runtime_error("Exit");;
				}
			}
			os.setp(0);
		}
	}

}


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

#include <iostream>

#include <madym/tests/mdm_test_utils.h>
#include <madym/mdm_AIF.h>
#include <madym/dce_models/mdm_DCEModelGenerator.h>

void test_model_time_series(
	const std::string &modelName,
	mdm_AIF &AIF)
{
	//Read in the model calibration file
	auto nTimes = AIF.AIFTimes().size();
	int nParams;
	std::vector<double> CtCalibration(nTimes);
	std::string modelFileName = mdm_test_utils::calibration_dir() + modelName + ".dat";

	std::ifstream modelFileStream(modelFileName, std::ios::in | std::ios::binary);
	modelFileStream.read(reinterpret_cast<char*>(&nParams), sizeof(int));

	std::vector<double> initialParams(nParams);
	for (double &p : initialParams)
		modelFileStream.read(reinterpret_cast<char*>(&p), sizeof(double));
	for (double &c : CtCalibration)
		modelFileStream.read(reinterpret_cast<char*>(&c), sizeof(double));
	modelFileStream.close();
	BOOST_TEST_MESSAGE(boost::format(
		"Read time series for %1% from binary calibration file") % modelName);

	//Now create the model and compute model time series
	auto modelType = mdm_DCEModelGenerator::ParseModelName(modelName);
	BOOST_REQUIRE_MESSAGE(modelType != mdm_DCEModelGenerator::UNDEFINED,
		"Model name " << modelName << "Is undefined ");

  AIF.setAIFType(mdm_AIF::AIF_TYPE::AIF_POP);
  AIF.setPIFType(mdm_AIF::PIF_TYPE::PIF_POP);
	auto model = mdm_DCEModelGenerator::createModel(AIF,
		modelType, {},
		initialParams, {}, {}, {}, {}, {}, {});

	model->computeCtModel(nTimes);
	std::vector<double> Ct = model->CtModel();
	BOOST_TEST_MESSAGE("Test DCE models, values match: " + modelName);
	BOOST_CHECK(mdm_test_utils::vectors_near_equal(
        Ct, CtCalibration, 0.0001));
}

BOOST_AUTO_TEST_SUITE(test_mdm)

BOOST_AUTO_TEST_CASE(test_DCE_models) {
	BOOST_TEST_MESSAGE("======= Testing DCE models implemented in mdm library =======");

	//Read in dynamic times from calibration file
	int nTimes;
	std::string timesFileName(mdm_test_utils::calibration_dir() + "dyn_times.dat");
	std::ifstream timesFileStream(timesFileName, std::ios::in | std::ios::binary);
	timesFileStream.read(reinterpret_cast<char*>(&nTimes), sizeof(int));

	std::vector<double> dynTimes(nTimes);
	for (double &t : dynTimes)
		timesFileStream.read(reinterpret_cast<char*>(&t), sizeof(double));
	timesFileStream.close();

	//For the AIF, read in the injection image, haematocrit correction and dose
	//then the values
	int injectionImage;
	double hct;
	double dose;
	std::vector<double> aifVals(nTimes);
	std::vector<double> pifVals(nTimes);

	std::string aifFileName(mdm_test_utils::calibration_dir() + "aif.dat");
	std::ifstream aifFileStream(aifFileName, std::ios::in | std::ios::binary);
	aifFileStream.read(reinterpret_cast<char*>(&injectionImage), sizeof(int));
	aifFileStream.read(reinterpret_cast<char*>(&hct), sizeof(double));
	aifFileStream.read(reinterpret_cast<char*>(&dose), sizeof(double));
	aifFileStream.close();

	//Create AIF
	mdm_AIF AIF;
	AIF.setAIFTimes(dynTimes);
	AIF.setPrebolus(injectionImage);
	AIF.setHct(hct);
	AIF.setDose(dose);

	//Create model concentrations for each model type
	test_model_time_series(
		"ETM",
		AIF);
	test_model_time_series(
		"DIETM",
		AIF);
	test_model_time_series(
		"AUEM",
		AIF);
	test_model_time_series(
		"DISCM",
		AIF);
	test_model_time_series(
		"2CXM",
		AIF);
	test_model_time_series(
		"DI2CXM",
		AIF);
	test_model_time_series(
		"DIBEM",
		AIF);
  test_model_time_series(
    "PATLAK",
    AIF);
}

BOOST_AUTO_TEST_SUITE_END() //


//---------------------------------------------------------------------------//
//!
//! \file   MonteCarlo_WHIncoherentPhotonScatteringDistribution.cpp
//! \author Alex Robinson
//! \brief  The Waller-Hartree incoherent photon scattering distribution def.
//!
//---------------------------------------------------------------------------//

// Boost Includes
#include <boost/function.hpp>
#include <boost/bind.hpp>

// FRENSIE Includes
#include "MonteCarlo_WHIncoherentPhotonScatteringDistribution.hpp"
#include "MonteCarlo_PhotonKinematicsHelpers.hpp"
#include "Utility_PhysicalConstants.hpp"
#include "Utility_GaussKronrodIntegrator.hpp"
#include "Utility_DesignByContract.hpp"

namespace MonteCarlo{

// Constructor
WHIncoherentPhotonScatteringDistribution::WHIncoherentPhotonScatteringDistribution(
	  const std::shared_ptr<const ScatteringFunction>& scattering_function,
	  const double kahn_sampling_cutoff_energy )
  : IncoherentPhotonScatteringDistribution( kahn_sampling_cutoff_energy ),
    d_scattering_function( scattering_function )
{
  // Make sure the scattering function is valid
  testPrecondition( scattering_function.get() );
}

// Evaluate the distribution
double WHIncoherentPhotonScatteringDistribution::evaluate(
				   const double incoming_energy,
				   const double scattering_angle_cosine ) const
{
  // Make sure the incoming energy is valid
  testPrecondition( incoming_energy > 0.0 );
  // Make sure the scattering angle cosine is valid
  testPrecondition( scattering_angle_cosine >= -1.0 );
  testPrecondition( scattering_angle_cosine <= 1.0 );

  const double scattering_function_value =
    this->evaluateScatteringFunction( incoming_energy,
				      scattering_angle_cosine );

  const double diff_kn_cross_section =
    this->evaluateKleinNishinaDist( incoming_energy,
				    scattering_angle_cosine );

  return diff_kn_cross_section*scattering_function_value;
}

// Evaluate the integrated cross section (b)
double WHIncoherentPhotonScatteringDistribution::evaluateIntegratedCrossSection(
						  const double incoming_energy,
						  const double precision) const
{
  // Make sure the incoming energy is valid
  testPrecondition( incoming_energy > 0.0 );

  // Evaluate the integrated cross section
  boost::function<double (double x)> diff_cs_wrapper =
    boost::bind<double>( &WHIncoherentPhotonScatteringDistribution::evaluate,
			 boost::cref( *this ),
			 incoming_energy,
			 _1 );

  double abs_error, integrated_cs;

  Utility::GaussKronrodIntegrator<double> quadrature_gkq_set( precision );

  quadrature_gkq_set.integrateAdaptively<15>( diff_cs_wrapper,
					     -1.0,
					     1.0,
					     integrated_cs,
					     abs_error );

  // Make sure the integrated cross section is valid
  testPostcondition( integrated_cs > 0.0 );

  return integrated_cs;
}

// Sample an outgoing energy and direction from the distribution
/*! \details This function will only sample a Compton line energy (no
 * Doppler broadening).
 */
void WHIncoherentPhotonScatteringDistribution::sample(
				     const double incoming_energy,
				     double& outgoing_energy,
				     double& scattering_angle_cosine ) const
{
  // Make sure the incoming energy is valid
  testPrecondition( incoming_energy > 0.0 );

  Counter trial_dummy;

  return this->sampleAndRecordTrials( incoming_energy,
				      outgoing_energy,
				      scattering_angle_cosine,
				      trial_dummy );
}

// Sample an outgoing energy and direction and record the number of trials
/*! \details This function will only sample a Compton line energy (no
 * Doppler broadening).
 */
void WHIncoherentPhotonScatteringDistribution::sampleAndRecordTrials(
					    const double incoming_energy,
					    double& outgoing_energy,
					    double& scattering_angle_cosine,
					    Counter& trials ) const
{
  // Make sure the incoming energy is valid
  testPrecondition( incoming_energy > 0.0 );

  // Evaluate the maximum scattering function value
  const double max_scattering_function_value =
    this->evaluateScatteringFunction( incoming_energy, -1.0 );

  while( true )
  {
    this->sampleAndRecordTrialsKleinNishina( incoming_energy,
					     outgoing_energy,
					     scattering_angle_cosine,
					     trials );

    const double scattering_function_value =
      this->evaluateScatteringFunction( incoming_energy,
					scattering_angle_cosine );

    const double scaled_random_number = max_scattering_function_value*
      Utility::RandomNumberGenerator::getRandomNumber<double>();

    if( scaled_random_number <= scattering_function_value )
      break;
  }

  // Make sure the scattering angle cosine is valid
  testPostcondition( scattering_angle_cosine >= -1.0 );
  testPostcondition( scattering_angle_cosine <= 1.0 );
  // Make sure the compton line energy is valid
  testPostcondition( outgoing_energy <= incoming_energy );
}

} // end MonteCarlo namespace

//---------------------------------------------------------------------------//
// end MonteCarlo_WHIncoherentPhotonScatteringDistribution.cpp
//---------------------------------------------------------------------------//


#ifndef STAN_MATH_PRIM_SCAL_PROB_BINOMIAL_LOGIT_LPMF_HPP
#define STAN_MATH_PRIM_SCAL_PROB_BINOMIAL_LOGIT_LPMF_HPP

#include <stan/math/prim/scal/meta/is_constant_struct.hpp>
#include <stan/math/prim/scal/meta/partials_return_type.hpp>
#include <stan/math/prim/scal/meta/operands_and_partials.hpp>
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp>
#include <stan/math/prim/scal/err/check_bounded.hpp>
#include <stan/math/prim/scal/err/check_finite.hpp>
#include <stan/math/prim/scal/err/check_greater_or_equal.hpp>
#include <stan/math/prim/scal/err/check_less_or_equal.hpp>
#include <stan/math/prim/scal/err/check_nonnegative.hpp>
#include <stan/math/prim/scal/fun/size_zero.hpp>
#include <stan/math/prim/scal/fun/constants.hpp>
#include <stan/math/prim/scal/fun/inv_logit.hpp>
#include <stan/math/prim/scal/fun/log1m.hpp>
#include <stan/math/prim/scal/fun/log_inv_logit.hpp>
#include <stan/math/prim/scal/fun/multiply_log.hpp>
#include <stan/math/prim/scal/fun/value_of.hpp>
#include <stan/math/prim/scal/fun/binomial_coefficient_log.hpp>
#include <stan/math/prim/scal/fun/lbeta.hpp>
#include <stan/math/prim/scal/meta/VectorBuilder.hpp>
#include <stan/math/prim/scal/meta/include_summand.hpp>
#include <stan/math/prim/scal/meta/scalar_seq_view.hpp>
#include <stan/math/prim/scal/fun/inc_beta.hpp>
#include <boost/random/binomial_distribution.hpp>
#include <boost/random/variate_generator.hpp>

namespace stan {
namespace math {

/**
 * Binomial log PMF in logit parametrization. Binomial(n|n, inv_logit(alpha))
 *
 * If given vectors of matching lengths, returns
 * the log sum of probabilities.
 *
 * @param n successes variable
 * @param N population size parameter
 * @param alpha logit transformed probability parameter
 *
 * @return log probability or log sum of probabilities
 *
 * @throw std::domain_error if N is negative or probability parameter is invalid
 * @throw std::invalid_argument if vector sizes do not match
 */
template <bool propto, typename T_n, typename T_N, typename T_prob>
typename return_type<T_prob>::type binomial_logit_lpmf(const T_n& n,
                                                       const T_N& N,
                                                       const T_prob& alpha) {
  typedef typename stan::partials_return_type<T_n, T_N, T_prob>::type
      T_partials_return;

  static const char* function = "binomial_logit_lpmf";

  if (size_zero(n, N, alpha))
    return 0.0;

  T_partials_return logp = 0;
  check_bounded(function, "Successes variable", n, 0, N);
  check_nonnegative(function, "Population size parameter", N);
  check_finite(function, "Probability parameter", alpha);
  check_consistent_sizes(function, "Successes variable", n,
                         "Population size parameter", N,
                         "Probability parameter", alpha);

  if (!include_summand<propto, T_prob>::value)
    return 0.0;

  scalar_seq_view<T_n> n_vec(n);
  scalar_seq_view<T_N> N_vec(N);
  scalar_seq_view<T_prob> alpha_vec(alpha);
  size_t size = max_size(n, N, alpha);

  operands_and_partials<T_prob> ops_partials(alpha);

  if (include_summand<propto>::value) {
    for (size_t i = 0; i < size; ++i)
      logp += binomial_coefficient_log(N_vec[i], n_vec[i]);
  }

  VectorBuilder<true, T_partials_return, T_prob> log_inv_logit_alpha(
      length(alpha));
  for (size_t i = 0; i < length(alpha); ++i)
    log_inv_logit_alpha[i] = log_inv_logit(value_of(alpha_vec[i]));

  VectorBuilder<true, T_partials_return, T_prob> log_inv_logit_neg_alpha(
      length(alpha));
  for (size_t i = 0; i < length(alpha); ++i)
    log_inv_logit_neg_alpha[i] = log_inv_logit(-value_of(alpha_vec[i]));

  for (size_t i = 0; i < size; ++i)
    logp += n_vec[i] * log_inv_logit_alpha[i]
            + (N_vec[i] - n_vec[i]) * log_inv_logit_neg_alpha[i];

  if (length(alpha) == 1) {
    T_partials_return temp1 = 0;
    T_partials_return temp2 = 0;
    for (size_t i = 0; i < size; ++i) {
      temp1 += n_vec[i];
      temp2 += N_vec[i] - n_vec[i];
    }
    if (!is_constant_struct<T_prob>::value) {
      ops_partials.edge1_.partials_[0]
          += temp1 * inv_logit(-value_of(alpha_vec[0]))
             - temp2 * inv_logit(value_of(alpha_vec[0]));
    }
  } else {
    if (!is_constant_struct<T_prob>::value) {
      for (size_t i = 0; i < size; ++i)
        ops_partials.edge1_.partials_[i]
            += n_vec[i] * inv_logit(-value_of(alpha_vec[i]))
               - (N_vec[i] - n_vec[i]) * inv_logit(value_of(alpha_vec[i]));
    }
  }

  return ops_partials.build(logp);
}

template <typename T_n, typename T_N, typename T_prob>
inline typename return_type<T_prob>::type binomial_logit_lpmf(
    const T_n& n, const T_N& N, const T_prob& alpha) {
  return binomial_logit_lpmf<false>(n, N, alpha);
}

}  // namespace math
}  // namespace stan
#endif


// Copyright (c) 2014, NICTA.
// This file is licensed under the General Public License version 3 or later.
// See the COPYRIGHT file.

/**
 * Prior object for world params
 *
 * @file world.hpp
 * @author Lachlan McCalman
 * @date 2014
 */

#pragma once
#include <random>
#include <Eigen/Core>
#include "datatype/world.hpp"
#include "datatype/datatypes.hpp"
#include "distrib/multigaussian.hpp"
#include <glog/logging.h>

namespace obsidian
{
  namespace prior
  {
    class WorldParamsPrior
    {
    public:
      // construct
      WorldParamsPrior(const std::vector<distrib::MultiGaussian>& ctrlpts_, const std::vector<Eigen::MatrixXi>& ctrlptMasks_,
                       const std::vector<Eigen::MatrixXd>& ctrlptMins_, const std::vector<Eigen::MatrixXd>& ctrlptMaxs_,
                       const Eigen::VectorXd& ctrlptCoupledSds_, const Eigen::VectorXd& ctrlptUncoupledSds_,
                       const std::vector<distrib::MultiGaussian>& properties_, const std::vector<Eigen::VectorXi>& propMasks_,
                       const std::vector<Eigen::VectorXd>& propMins_, const std::vector<Eigen::VectorXd>& propMaxs_,
                       const std::vector<BoundaryClass>& classes_)
          : ctrlptMasks(ctrlptMasks_),
            ctrlptMins(ctrlptMins_),
            ctrlptMaxs(ctrlptMaxs_),
            ctrlptCoupledSds(ctrlptCoupledSds_),
            ctrlptUncoupledSds(ctrlptUncoupledSds_),
            ctrlptPrior(ctrlpts_),
            propMasks(propMasks_),
            propMins(propMins_),
            propMaxs(propMaxs_),
            propertyPrior(properties_),
            classes(classes_)
      {
        for (uint l = 0; l < propMasks.size(); l++)
        {
          for (uint p = 0; p < propMasks_[l].size(); p++)
          {
            if (!propMasks_[l](p))
            {
              propertyPrior[l].sigma.row(p).setZero();
              propertyPrior[l].sigma.col(p).setZero();
              propertyPrior[l].sigma(p, p) = 1;
            }
          }
        }
        for (uint l = 0; l < ctrlptMasks_.size(); l++)
        {
          Eigen::MatrixXi masks = ctrlptMasks_[l];
          masks.resize(masks.rows() * masks.cols(), 1);
          for (uint p = 0; p < masks.rows(); p++)
          {
            if (!masks(p))
            {
              ctrlptPrior[l].sigma.row(p).setZero();
              ctrlptPrior[l].sigma.col(p).setZero();
              ctrlptPrior[l].sigma(p, p) = 1;
            }
          }
        }
        WorldParams minParams;
        WorldParams maxParams;
        minParams.rockProperties = propMins;
        maxParams.rockProperties = propMaxs;
        minParams.controlPoints = ctrlptMins;
        maxParams.controlPoints = ctrlptMaxs;
        thetaMin = deconstruct(minParams);
        thetaMax = deconstruct(maxParams);
        VLOG(1) << "Theta min:" << thetaMin.transpose();
        VLOG(1) << "Theta max:" << thetaMax.transpose();
      }

      Eigen::VectorXd thetaMinBound();

      Eigen::VectorXd thetaMaxBound();

      // build a WorldParams object from a flat vector
      WorldParams reconstruct(const Eigen::VectorXd& theta) const;

      // Evaluate log likelihood of theta under this prior
      double evaluatePDF(const Eigen::VectorXd& theta) const;

      // randomly sample a valid set of parameters
      Eigen::VectorXd sample(std::mt19937 &gen) const;

      // Method to compute the size of the prior
      uint size() const;

      // turn a WorldParams object into a flat vector
      Eigen::VectorXd deconstruct(const WorldParams& params) const;

      // private:
      std::vector<Eigen::MatrixXi> ctrlptMasks;
      std::vector<Eigen::MatrixXd> ctrlptMins;
      std::vector<Eigen::MatrixXd> ctrlptMaxs;
      Eigen::VectorXd ctrlptCoupledSds;
      Eigen::VectorXd ctrlptUncoupledSds;
      std::vector<distrib::MultiGaussian> ctrlptPrior;
      std::vector<Eigen::VectorXi> propMasks;
      std::vector<Eigen::VectorXd> propMins;
      std::vector<Eigen::VectorXd> propMaxs;
      std::vector<distrib::MultiGaussian> propertyPrior;
      std::vector<BoundaryClass> classes;
      Eigen::VectorXd thetaMin;
      Eigen::VectorXd thetaMax;
    };
  } //namespace prior
} //namespace obsidian


#include "Random.h"

#include <unistd.h> // for windows
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <boost/timer.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>

Random::Random(unsigned long s, int threadid)
{
  if (s==0)
    seed=Random::makeSeed(threadid);
  else
    seed=s^((unsigned long)threadid);
}

/*
 unsigned long Random::getRandomInt()
{
  //Park-Miller "Minimal Standard" PRNG

  unsigned long hi, lo;

  lo= 16807 * (seed & 0xffff);
  hi= 16807 * (seed >> 16);

  lo+= (hi & 0x7fff) << 16;
  lo+= hi >> 15;

  if (lo >= 0x7FFFFFFF) lo-=0x7FFFFFFF;

  return (seed=lo);
}

unsigned long Random::getRandomInt(unsigned long max)
{
  return this->getRandomInt() % max; //XXX: not uniform, but good enough
}
*/
unsigned long Random::getRandomInt(unsigned long max, float a)
{
  float r=getRandomInt(max);
  r=pow(r,a)/pow(max,a)*max;
  return r;
}

/*
float Random::getRandomReal()
{
  return (float)this->getRandomInt() / ((unsigned long)(1) << 31);
}
*/

unsigned long Random::makeSeed(int threadid)
{
  return ((unsigned long)std::time(0))^((unsigned long)getpid()<<6)^((unsigned long)threadid);
}