/* Author: Wolfgang Bangerth, Texas A&M University, 2009, 2010 */
/*         Timo Heister, University of Goettingen, 2009, 2010 */

/*    $Id: step-40.cc 28561 2013-02-25 23:16:09Z heister $       */
/*                                                                */
/*    Copyright (C) 2009-2012 by Timo Heister and the deal.II authors */
/*                                                                */
/*    This file is subject to QPL and may not be  distributed     */
/*    without copyright and license information. Please refer     */
/*    to the file deal.II/doc/license.html for the  text  and     */
/*    further information on this license.                        */

// @sect3{Include files}
//
// Most of the include files we need for this program have already been
// discussed in previous programs. In particular, all of the following should
// already be familiar friends:
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/constraint_matrix.h>
#include <deal.II/lac/compressed_simple_sparsity_pattern.h>

#include <deal.II/lac/petsc_parallel_sparse_matrix.h>
#include <deal.II/lac/petsc_parallel_vector.h>
#include <deal.II/lac/petsc_solver.h>
#include <deal.II/lac/petsc_precondition.h>

#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/error_estimator.h>

// The following, however, will be new or be used in new roles. Let's walk
// through them. The first of these will provide the tools of the
// Utilities::System namespace that we will use to query things like the
// number of processors associated with the current MPI universe, or the
// number within this universe the processor this job runs on is:
#include <deal.II/base/utilities.h>
// The next one provides a class, ConditionOStream that allows us to write
// code that would output things to a stream (such as std::cout
// on every processor but throws the text away on all but one of them. We
// could achieve the same by simply putting an if statement in
// front of each place where we may generate output, but this doesn't make the
// code any prettier. In addition, the condition whether this processor should
// or should not produce output to the screen is the same every time -- and
// consequently it should be simple enough to put it into the statements that
// generate output itself.
#include <deal.II/base/conditional_ostream.h>
// After these preliminaries, here is where it becomes more interesting. As
// mentioned in the @ref distributed module, one of the fundamental truths of
// solving problems on large numbers of processors is that there is no way for
// any processor to store everything (e.g. information about all cells in the
// mesh, all degrees of freedom, or the values of all elements of the solution
// vector). Rather, every processor will own a few of each of these
// and, if necessary, may know about a few more, for example the ones
// that are located on cells adjacent to the ones this processor owns
// itself. We typically call the latter ghost cells, ghost nodes
// or ghost elements of a vector. The point of this discussion here is
// that we need to have a way to indicate which elements a particular
// processor owns or need to know of. This is the realm of the IndexSet class:
// if there are a total of $N$ cells, degrees of freedom, or vector elements,
// associated with (non-negative) integral indices $[0,N)$, then both the set
// of elements the current processor owns as well as the (possibly larger) set
// of indices it needs to know about are subsets of the set $[0,N)$. IndexSet
// is a class that stores subsets of this set in an efficient format:
#include <deal.II/base/index_set.h>
// The next header file is necessary for a single function,
// SparsityTools::distribute_sparsity_pattern. The role of this function will
// be explained below.
#include <deal.II/lac/sparsity_tools.h>
// The final two, new header files provide the class
// parallel::distributed::Triangulation that provides meshes distributed
// across a potentially very large number of processors, while the second
// provides the namespace parallel::distributed::GridRefinement that offers
// functions that can adaptively refine such distributed meshes:
#include <deal.II/distributed/tria.h>
#include <deal.II/distributed/grid_refinement.h>

#include <fstream>
#include <iostream>

namespace Step40
{
  using namespace dealii;

  // @sect3{The LaplaceProblem class template}

  // Next let's declare the main class of this program. Its structure is
  // almost exactly that of the step-6 tutorial program. The only significant
  // differences are:
  // - The mpi_communicator variable that
  //   describes the set of processors we want this code to run on. In practice,
  //   this will be MPI_COMM_WORLD, i.e. all processors the batch scheduling
  //   system has assigned to this particular job.
  // - The presence of the pcout variable of type ConditionOStream.
  // - The obvious use of parallel::distributed::Triangulation instead of Triangulation.
  // - The presence of two IndexSet objects that denote which sets of degrees of
  //   freedom (and associated elements of solution and right hand side vectors)
  //   we own on the current processor and which we need (as ghost elements) for
  //   the algorithms in this program to work.
  // - The fact that all matrices and vectors are now distributed. We use
  //   their PETScWrapper versions for this since deal.II's own classes do not
  //   provide %parallel functionality. Note that as part of this class, we
  //   store a solution vector that does not only contain the degrees of freedom
  //   the current processor owns, but also (as ghost elements) all those vector
  //   elements that correspond to "locally relevant" degrees of freedom
  //   (i.e. all those that live on locally owned cells or the layer of ghost
  //   cells that surround it).
  template <int dim>
  class LaplaceProblem
  {
  public:
    LaplaceProblem ();
    ~LaplaceProblem ();

    void run ();

  private:
    void setup_system ();
    void assemble_system ();
    void solve ();
    void refine_grid ();
    void output_results (const unsigned int cycle) const;

    MPI_Comm mpi_communicator;

    parallel::distributed::Triangulation<dim>   triangulation;

    DoFHandler<dim>      dof_handler;
    FE_Q<dim>            fe;

    IndexSet             locally_owned_dofs;
    IndexSet             locally_relevant_dofs;

    ConstraintMatrix     constraints;

    PETScWrappers::MPI::SparseMatrix system_matrix;
    PETScWrappers::MPI::Vector locally_relevant_solution;
    PETScWrappers::MPI::Vector system_rhs;

    ConditionalOStream                pcout;
  };

  // @sect3{The LaplaceProblem class implementation}

  // @sect4{Constructors and destructors}

  // Constructors and destructors are rather trivial. In addition to what we
  // do in step-6, we set the set of processors we want to work on to all
  // machines available (MPI_COMM_WORLD); ask the triangulation to ensure that
  // the mesh remains smooth and free to refined islands, for example; and
  // initialize the pcout variable to only allow processor zero
  // to output anything:
  template <int dim>
  LaplaceProblem<dim>::LaplaceProblem ()
    :
    mpi_communicator (MPI_COMM_WORLD),
    triangulation (mpi_communicator,
                   typename Triangulation<dim>::MeshSmoothing
                   (Triangulation<dim>::smoothing_on_refinement |
                    Triangulation<dim>::smoothing_on_coarsening)),
    dof_handler (triangulation),
    fe (2),
    pcout (std::cout,
           (Utilities::MPI::this_mpi_process(mpi_communicator)
            == 0))
  {}

  template <int dim>
  LaplaceProblem<dim>::~LaplaceProblem ()
  {
    dof_handler.clear ();
  }

  // @sect4{LaplaceProblem::setup_system}

  // The following function is, arguably, the most interesting one in the
  // entire program since it goes to the heart of what distinguishes %parallel
  // step-40 from sequential step-6.
  //
  // At the top we do what we always do: tell the DoFHandler object to
  // distribute degrees of freedom. Since the triangulation we use here is
  // distributed, the DoFHandler object is smart enough to recognize that on
  // each processor it can only distribute degrees of freedom on cells it
  // owns; this is followed by an exchange step in which processors tell each
  // other about degrees of freedom on ghost cell. The result is a DoFHandler
  // that knows about the degrees of freedom on locally owned cells and ghost
  // cells (i.e. cells adjacent to locally owned cells) but nothing about
  // cells that are further away, consistent with the basic philosophy of
  // distributed computing that no processor can know everything.
  template <int dim>
  void LaplaceProblem<dim>::setup_system ()
  {
    dof_handler.distribute_dofs (fe);

    // The next two lines extract some informatino we will need later on,
    // namely two index sets that provide information about which degrees of
    // freedom are owned by the current processor (this information will be
    // used to initialize solution and right hand side vectors, and the system
    // matrix, indicating which elements to store on the current processor and
    // which to expect to be stored somewhere else); and an index set that
    // indicates which degrees of freedom are locally relevant (i.e. live on
    // cells that the current processor owns or on the layer of ghost cells
    // around the locally owned cells; we need all of these degrees of
    // freedom, for example, to estimate the error on the local cells).
    locally_owned_dofs = dof_handler.locally_owned_dofs ();
    DoFTools::extract_locally_relevant_dofs (dof_handler,
                                             locally_relevant_dofs);

    // Next, let us initialize the solution and right hand side vectors. As
    // mentioned above, the solution vector we seek does not only store
    // elements we own, but also ghost entries; on the other hand, the right
    // hand side vector only needs to have the entries the current processor
    // owns since all we will ever do is write into it, never read from it on
    // locally owned cells (of course the linear solvers will read from it,
    // but they do not care about the geometric location of degrees of
    // freedom).
    locally_relevant_solution.reinit (mpi_communicator,
                                      locally_owned_dofs,
                                      locally_relevant_dofs);
    system_rhs.reinit (mpi_communicator,
                       dof_handler.n_dofs(),
                       dof_handler.n_locally_owned_dofs());
    system_rhs = 0;

    // The next step is to compute hanging node and boundary value
    // constraints, which we combine into a single object storing all
    // constraints.
    //
    // As with all other things in %parallel, the mantra must be that no
    // processor can store all information about the entire universe. As a
    // consequence, we need to tell the constraints object for which degrees
    // of freedom it can store constraints and for which it may not expect any
    // information to store. In our case, as explained in the @ref distributed
    // module, the degrees of freedom we need to care about on each processor
    // are the locally relevant ones, so we pass this to the
    // ConstraintMatrix::reinit function. As a side note, if you forget to
    // pass this argument, the ConstraintMatrix class will allocate an array
    // with length equal to the largest DoF index it has seen so far. For
    // processors with high MPI process number, this may be very large --
    // maybe on the order of billions. The program would then allocate more
    // memory than for likely all other operations combined for this single
    // array.
    constraints.clear ();
    constraints.reinit (locally_relevant_dofs);
    DoFTools::make_hanging_node_constraints (dof_handler, constraints);
    VectorTools::interpolate_boundary_values (dof_handler,
                                              0,
                                              ZeroFunction<dim>(),
                                              constraints);
    constraints.close ();

    // The last part of this function deals with initializing the matrix with
    // accompanying sparsity pattern. As in previous tutorial programs, we use
    // the CompressedSimpleSparsityPattern as an intermediate with which we
    // then initialize the PETSc matrix. To do so we have to tell the sparsity
    // pattern its size but as above there is no way the resulting object will
    // be able to store even a single pointer for each global degree of
    // freedom; the best we can hope for is that it stores information about
    // each locally relevant degree of freedom, i.e. all those that we may
    // ever touch in the process of assembling the matrix (the @ref
    // distributed_paper "distributed computing paper" has a long discussion
    // why one really needs the locally relevant, and not the small set of
    // locally active degrees of freedom in this context).
    //
    // So we tell the sparsity pattern its size and what DoFs to store
    // anything for and then ask DoFTools::make_sparsity_pattern to fill it
    // (this function ignores all cells that are not locally owned, mimicking
    // what we will do below in the assembly process). After this, we call a
    // function that exchanges entries in these sparsity pattern between
    // processors so that in the end each processor really knows about all the
    // entries that will exist in that part of the finite element matrix that
    // it will own. The final step is to initialize the matrix with the
    // sparsity pattern.
    CompressedSimpleSparsityPattern csp (dof_handler.n_dofs(),
                                         dof_handler.n_dofs(),
                                         locally_relevant_dofs);
    DoFTools::make_sparsity_pattern (dof_handler,
                                     csp,
                                     constraints, false);
    SparsityTools::distribute_sparsity_pattern (csp,
                                                dof_handler.n_locally_owned_dofs_per_processor(),
                                                mpi_communicator,
                                                locally_relevant_dofs);
    system_matrix.reinit (mpi_communicator,
                          csp,
                          dof_handler.n_locally_owned_dofs_per_processor(),
                          dof_handler.n_locally_owned_dofs_per_processor(),
                          Utilities::MPI::this_mpi_process(mpi_communicator));
  }

  // @sect4{LaplaceProblem::assemble_system}

  // The function that then assembles the linear system is comparatively
  // boring, being almost exactly what we've seen before. The points to watch
  // out for are:
  // - Assembly must only loop over locally owned cells. There
  //   are multiple ways to test that; for example, we could compare a cell's
  //   subdomain_id against information from the triangulation as in
  //   cell->subdomain_id() ==
  //   triangulation.locally_owned_subdomain(), or skip all cells for
  //   which the condition cell->is_ghost() ||
  //   cell->is_artificial() is true. The simplest way, however, is to
  //   simply ask the cell whether it is owned by the local processor.
  // - Copying local contributions into the global matrix must include
  //   distributing constraints and boundary values. In other words, we can now
  //   (as we did in step-6) first copy every local contribution into the global
  //   matrix and only in a later step take care of hanging node constraints and
  //   boundary values. The reason is, as discussed in step-17, that PETSc does
  //   not provide access to arbitrary elements of the matrix once they have
  //   been assembled into it -- in parts because they may simple no longer
  //   reside on the current processor but have instead been shipped to a
  //   different machine.
  // - The way we compute the right hand side (given the
  //   formula stated in the introduction) may not be the most elegant but will
  //   do for a program whose focus lies somewhere entirely different.
  template <int dim>
  void LaplaceProblem<dim>::assemble_system ()
  {
    const QGauss<dim>  quadrature_formula(3);

    FEValues<dim> fe_values (fe, quadrature_formula,
                             update_values    |  update_gradients |
                             update_quadrature_points |
                             update_JxW_values);

    const unsigned int   dofs_per_cell = fe.dofs_per_cell;
    const unsigned int   n_q_points    = quadrature_formula.size();

    FullMatrix<double>   cell_matrix (dofs_per_cell, dofs_per_cell);
    Vector<double>       cell_rhs (dofs_per_cell);

    std::vector<unsigned int> local_dof_indices (dofs_per_cell);

    typename DoFHandler<dim>::active_cell_iterator
    cell = dof_handler.begin_active(),
    endc = dof_handler.end();
    for (; cell!=endc; ++cell)
      if (cell->is_locally_owned())
        {
          cell_matrix = 0;
          cell_rhs = 0;

          fe_values.reinit (cell);

          for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
            {
              const double
              rhs_value
                = (fe_values.quadrature_point(q_point)[1]
                   >
                   0.5+0.25*std::sin(4.0 * numbers::PI *
                                     fe_values.quadrature_point(q_point)[0])
                   ? 1 : -1);

              for (unsigned int i=0; i<dofs_per_cell; ++i)
                {
                  for (unsigned int j=0; j<dofs_per_cell; ++j)
                    cell_matrix(i,j) += (fe_values.shape_grad(i,q_point) *
                                         fe_values.shape_grad(j,q_point) *
                                         fe_values.JxW(q_point));

                  cell_rhs(i) += (rhs_value *
                                  fe_values.shape_value(i,q_point) *
                                  fe_values.JxW(q_point));
                }
            }

          cell->get_dof_indices (local_dof_indices);
          constraints.distribute_local_to_global (cell_matrix,
                                                  cell_rhs,
                                                  local_dof_indices,
                                                  system_matrix,
                                                  system_rhs);
        }

    system_matrix.compress (VectorOperation::add);
    system_rhs.compress (VectorOperation::add);
  }

  // @sect4{LaplaceProblem::solve}

  // Even though solving linear systems on potentially tens of thousands of
  // processors is by far not a trivial job, the function that does this is --
  // at least at the outside -- relatively simple. Most of the parts you've
  // seen before. There are really only two things worth mentioning:
  // - Solvers and preconditioners are built on the deal.II wrappers of PETSc
  //   functionality. It is relatively well known that the primary bottleneck of
  //   massively %parallel linear solvers is not actually the communication
  //   between processors, but the fact that it is difficult to produce
  //   preconditioners that scale well to large numbers of processors. Over the
  //   second half of the first decade of the 21st century, it has become clear
  //   that algebraic multigrid (AMG) methods turn out to be extremely efficient
  //   in this context, and we will use one of them -- the BoomerAMG
  //   implementation of the Hypre package that can be interfaced to through
  //   PETSc -- for the current program. The rest of the solver itself is
  //   boilerplate and has been shown before. Since the linear system is
  //   symmetric and positive definite, we can use the CG method as the outer
  //   solver.
  // - Ultimately, we want a vector that stores not only the elements
  //   of the solution for degrees of freedom the current processor owns, but
  //   also all other locally relevant degrees of freedom. On the other hand,
  //   the solver itself needs a vector that is uniquely split between
  //   processors, without any overlap. We therefore create a vector at the
  //   beginning of this function that has these properties, use it to solve the
  //   linear system, and only assign it to the vector we want at the very
  //   end. This last step ensures that all ghost elements are also copied as
  //   necessary.
  template <int dim>
  void LaplaceProblem<dim>::solve ()
  {
    PETScWrappers::MPI::Vector
    completely_distributed_solution (mpi_communicator,
                                     dof_handler.n_dofs(),
                                     dof_handler.n_locally_owned_dofs());

    SolverControl solver_control (dof_handler.n_dofs(), 1e-12);

    PETScWrappers::SolverCG solver(solver_control, mpi_communicator);

    // Ask for a symmetric preconditioner by setting the first parameter in
    // AdditionalData to true.
    PETScWrappers::PreconditionBoomerAMG
    preconditioner(system_matrix,
                   PETScWrappers::PreconditionBoomerAMG::AdditionalData(true));

    solver.solve (system_matrix, completely_distributed_solution, system_rhs,
                  preconditioner);

    pcout << "   Solved in " << solver_control.last_step()
          << " iterations." << std::endl;

    constraints.distribute (completely_distributed_solution);

    locally_relevant_solution = completely_distributed_solution;
  }

  // @sect4{LaplaceProblem::refine_grid}

  // The function that estimates the error and refines the grid is again
  // almost exactly like the one in step-6. The only difference is that the
  // function that flags cells to be refined is now in namespace
  // parallel::distributed::GridRefinement -- a namespace that has functions
  // that can communicate between all involved processors and determine global
  // thresholds to use in deciding which cells to refine and which to coarsen.
  //
  // Note that we didn't have to do anything special about the
  // KellyErrorEstimator class: we just give it a vector with as many elements
  // as the local triangulation has cells (locally owned cells, ghost cells,
  // and artificial ones), but it only fills those entries that correspond to
  // cells that are locally owned.
  template <int dim>
  void LaplaceProblem<dim>::refine_grid ()
  {
    Vector<float> estimated_error_per_cell (triangulation.n_active_cells());
    KellyErrorEstimator<dim>::estimate (dof_handler,
                                        QGauss<dim-1>(3),
                                        typename FunctionMap<dim>::type(),
                                        locally_relevant_solution,
                                        estimated_error_per_cell);
    parallel::distributed::GridRefinement::
    refine_and_coarsen_fixed_number (triangulation,
                                     estimated_error_per_cell,
                                     0.3, 0.03);
    triangulation.execute_coarsening_and_refinement ();
  }

  // @sect4{LaplaceProblem::output_results}

  // Compared to the corresponding function in step-6, the one here is a tad
  // more complicated. There are two reasons: the first one is that we do not
  // just want to output the solution but also for each cell which processor
  // owns it (i.e. which "subdomain" it is in). Secondly, as discussed at
  // length in step-17 and step-18, generating graphical data can be a
  // bottleneck in parallelizing. In step-18, we have moved this step out of
  // the actual computation but shifted it into a separate program that later
  // combined the output from various processors into a single file. But this
  // doesn't scale: if the number of processors is large, this may mean that
  // the step of combining data on a single processor later becomes the
  // longest running part of the program, or it may produce a file that's so
  // large that it can't be visualized any more. We here follow a more
  // sensible approach, namely creating individual files for each MPI process
  // and leaving it to the visualization program to make sense of that.
  //
  // To start, the top of the function looks like always. In addition to
  // attaching the solution vector (the one that has entries for all locally
  // relevant, not only the locally owned, elements), we attach a data vector
  // that stores, for each cell, the subdomain the cell belongs to. This is
  // slightly tricky, because of course not every processor knows about every
  // cell. The vector we attach therefore has an entry for every cell that the
  // current processor has in its mesh (locally owned onces, ghost cells, and
  // artificial cells), but the DataOut class will ignore all entries that
  // correspond to cells that are not owned by the current processor. As a
  // consequence, it doesn't actually matter what values we write into these
  // vector entries: we simply fill the entire vector with the number of the
  // current MPI process (i.e. the subdomain_id of the current process); this
  // correctly sets the values we care for, i.e. the entries that correspond
  // to locally owned cells, while providing the wrong value for all other
  // elements -- but these are then ignored anyway.
  template <int dim>
  void LaplaceProblem<dim>::output_results (const unsigned int cycle) const
  {
    DataOut<dim> data_out;
    data_out.attach_dof_handler (dof_handler);
    data_out.add_data_vector (locally_relevant_solution, "u");

    Vector<float> subdomain (triangulation.n_active_cells());
    for (unsigned int i=0; i<subdomain.size(); ++i)
      subdomain(i) = triangulation.locally_owned_subdomain();
    data_out.add_data_vector (subdomain, "subdomain");

    data_out.build_patches ();

    // The next step is to write this data to disk. We choose file names of
    // the form solution-XX-PPPP.vtu where XX
    // indicates the refinement cycle, PPPP refers to the
    // processor number (enough for up to 10,000 processors, though we hope
    // that nobody ever tries to generate this much data -- you would likely
    // overflow all file system quotas), and .vtu indicates the
    // XML-based Visualization Toolkit (VTK) file format.
    const std::string filename = ("solution-" +
                                  Utilities::int_to_string (cycle, 2) +
                                  "." +
                                  Utilities::int_to_string
                                  (triangulation.locally_owned_subdomain(), 4));
    std::ofstream output ((filename + ".vtu").c_str());
    data_out.write_vtu (output);

    // The last step is to write a "master record" that lists for the
    // visualization program the names of the various files that combined
    // represents the graphical data for the entire domain. The
    // DataOutBase::write_pvtu_record does this, and it needs a list of
    // filenames that we create first. Note that only one processor needs to
    // generate this file; we arbitrarily choose processor zero to take over
    // this job.
    if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
      {
        std::vector<std::string> filenames;
        for (unsigned int i=0;
             i<Utilities::MPI::n_mpi_processes(mpi_communicator);
             ++i)
          filenames.push_back ("solution-" +
                               Utilities::int_to_string (cycle, 2) +
                               "." +
                               Utilities::int_to_string (i, 4) +
                               ".vtu");

        std::ofstream master_output ((filename + ".pvtu").c_str());
        data_out.write_pvtu_record (master_output, filenames);
      }
  }

  // @sect4{LaplaceProblem::run}

  // The function that controls the overall behavior of the program is again
  // like the one in step-6. The minor difference are the use of
  // pcout instead of std::cout for output to the
  // console (see also step-17) and that we only generate graphical output if
  // at most 32 processors are involved. Without this limit, it would be just
  // too easy for people carelessly running this program without reading it
  // first to bring down the cluster interconnect and fill any file system
  // available :-)
  //
  // A functional difference to step-6 is the use of a square domain and that
  // we start with a slightly finer mesh (5 global refinement cycles) -- there
  // just isn't much of a point showing a massively %parallel program starting
  // on 4 cells (although admittedly the point is only slightly stronger
  // starting on 1024).
  template <int dim>
  void LaplaceProblem<dim>::run ()
  {
    const unsigned int n_cycles = 8;
    for (unsigned int cycle=0; cycle<n_cycles; ++cycle)
      {
        pcout << "Cycle " << cycle << ':' << std::endl;

        if (cycle == 0)
          {
            GridGenerator::hyper_cube (triangulation);
            triangulation.refine_global (5);
          }
        else
          refine_grid ();

        setup_system ();

        pcout << "   Number of active cells:       "
              << triangulation.n_global_active_cells()
              << std::endl
              << "   Number of degrees of freedom: "
              << dof_handler.n_dofs()
              << std::endl;

        assemble_system ();
        solve ();

        if (Utilities::MPI::n_mpi_processes(mpi_communicator) <= 32)
          output_results (cycle);

        pcout << std::endl;
      }
  }
}

// @sect4{main()}

// The final function, main(), again has the same structure as in
// all other programs, in particular step-6. Like in the other programs that
// use PETSc, we have to inialize and finalize PETSc, which is done using the
// helper object MPI_InitFinalize.
//
// Note how we enclose the use the use of the LaplaceProblem class in a pair
// of braces. This makes sure that all member variables of the object are
// destroyed by the time we destroy the mpi_intialization object. Not doing
// this will lead to strange and hard to debug errors when
// PetscFinalize first deletes all PETSc vectors that are still
// around, and the destructor of the LaplaceProblem class then tries to delete
// them again.
int main(int argc, char *argv[])
{
  try
    {
      using namespace dealii;
      using namespace Step40;

      Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv);
      deallog.depth_console (0);

      {
        LaplaceProblem<2> laplace_problem_2d;
        laplace_problem_2d.run ();
      }
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Exception on processing: " << std::endl
                << exc.what() << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Unknown exception!" << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;
      return 1;
    }

  return 0;
}


/* CirKit: A circuit toolkit
 * Copyright (C) 2009-2015  University of Bremen
 * Copyright (C) 2015-2017  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @file truth_table_from_bitset.hpp
 *
 * @brief Generates a truth table from a bitset
 *
 * @author Mathias Soeken
 * @since  2.3
 */

#ifndef TRUTH_TABLE_FROM_BITSET_HPP
#define TRUTH_TABLE_FROM_BITSET_HPP

#include <boost/dynamic_bitset.hpp>

#include <reversible/truth_table.hpp>

namespace cirkit
{

/* e.g.: maps 0001 into
 *
 *  00 0
 *  01 0
 *  10 0
 *  11 1
 */
binary_truth_table truth_table_from_bitset_direct( const boost::dynamic_bitset<>& bs );

/* e.g.: maps 0001 into
 *
 *  000 0--
 *  001 0--
 *  010 0--
 *  011 1--
 *  100 ---
 *  101 ---
 *  110 ---
 *  111 ---
 *
 * requires one fewer line if bs is balanced
 */
binary_truth_table truth_table_from_bitset( const boost::dynamic_bitset<>& bs );

/* e.g.: maps 0001 into
 *
 *   00 0  00 0
 *   00 1  00 1
 *   01 0  01 0
 *   01 1  01 1
 *   10 0  10 0
 *   10 1  10 1
 *   11 0  11 1
 *   11 1  11 0
 */
binary_truth_table truth_table_from_bitset_bennett( const boost::dynamic_bitset<>& bs );

}

#endif

// Local Variables:
// c-basic-offset: 2
// eval: (c-set-offset 'substatement-open 0)
// eval: (c-set-offset 'innamespace 0)
// End:


#pragma once

#include <Eigen/Dense>
#include <cassert>
#include <cstdlib>
#include <vector>

namespace rek {

namespace sample {

class AliasSampler {

  unsigned int N;
  std::vector<unsigned int> A, B;
  std::vector<double> Y;

public:
  AliasSampler(const AliasSampler &) = delete;

  AliasSampler(const AliasSampler &&) = delete;

  ~AliasSampler() = default;

  explicit AliasSampler(const std::vector<double> &probs)
      : A(probs.size() + 2), B(probs.size() + 2), Y(probs.size() + 2) {
    double sum = 0;

    this->N = (unsigned int)probs.size();
    for (size_t j = 0; j < N; j++) {
      sum += probs[j];
    }

    sum = 1 / sum;

    // Normalize it now
    for (size_t j = 0; j < N; j++)
      Y[j + 1] = probs[j] * sum;
  };

  explicit AliasSampler(const Eigen::RowVectorXd &probs)
      : A(probs.size() + 2), B(probs.size() + 2), Y(probs.size() + 2) {

    double sum = 0;

    this->N = (unsigned int)probs.size();

    for (size_t j = 0; j < N; j++) {
      sum += probs(j);
    }

    sum = 1 / sum;

    // Normalize it now
    for (size_t j = 0; j < N; j++) {
      Y[j + 1] = probs(j) * sum;
    }
  };

  std::vector<unsigned int> sample(unsigned int numSamples) {
    std::vector<unsigned int> samples(numSamples);

    // Sample from Alias Sampler
    for (unsigned int k = 0; k < numSamples; k++) {
      samples[k] = walkerSample();
    }

    return samples;
  };

  void initSampler() {
    unsigned int i, j, k;
    assert(1 <= N);
    for (i = 1; i <= N; i++) {
      A[i] = i;
      B[i] = i; /* initial destins=stay there */
      assert(Y[i] >= 0.0);
      Y[i] = Y[i] * N; /* scale probvec */
    }
    B[0] = 0;
    Y[0] = 0.0;
    B[N + 1] = N + 1;
    Y[N + 1] = 2.0; /* sentinels */
    i = 0;
    j = N + 1;
    for (;;) {
      do {
        i++;
      } while (Y[B[i]] < 1.0); /* find i so X[B[i]] needs more */
      do {
        j--;
      } while (Y[B[j]] >= 1.0); /* find j so X[B[j]] wants less */
      if (i >= j)
        break;
      k = B[i];
      B[i] = B[j];
      B[j] = k; /* swap B[i], B[j] */
    }

    i = j;
    j++;
    while (i > 0) {
      while (Y[B[j]] <= 1.0)
        j++;
      /* find j so X[B[j]] needs more */
      assert(Y[B[i]] < 1.0); /* meanwhile X[B[i]] wants less */
      if (j > N)
        break;
      assert(j <= N);
      assert(Y[B[j]] > 1.0);
      Y[B[j]] -= 1.0 - Y[B[i]]; /* B[i] will donate to B[j] to fix up */
      A[B[i]] = B[j];
      if (Y[B[j]] < 1.0) { /* X[B[j]] now wants less so readjust ordering */
        assert(i < j);
        k = B[i];
        B[i] = B[j];
        B[j] = k; /* swap B[j], B[i] */
        j++;
      } else
        i--;
    }
  };

  unsigned int walkerSample() {
    unsigned int i;
    double r;
    /* Let i = random uniform integer from {1,2,...N};  */
    i = 1 + (unsigned int)((N - 1) * drand48());
    r = drand48();
    if (r > Y[i])
      i = A[i];

    return i - 1;
  }
};
} // namespace sample
} // namespace rek


/**
 * @author Tomas Polasek
 * @date 3.23.2020
 * @version 1.0
 * @brief Acceleration structures and query helpers.
 */

#include "TreeIOAcceleration.h"

#include <Eigen/Eigen>
#include <unsupported/Eigen/BVH>

namespace treeacc
{

void PointCloudAcceleration::fromCloud(const PointCloud &cloud, std::size_t maxLeafSize)
{ PointCloud cloudCopy{ cloud }; fromCloud(std::move(cloudCopy), maxLeafSize); }

void PointCloudAcceleration::fromCloud(PointCloud &&cloud, std::size_t maxLeafSize)
{
    mData = std::make_shared<PointCloud>(std::move(cloud));

    mIndex = std::make_shared<KdTree>(PointCloud::DATA_DIMENSIONALITY, *mData,
        nanoflann::KDTreeSingleIndexAdaptorParams(maxLeafSize));
    mIndex->buildIndex();
}

void PointCloudAcceleration::fromVertices(const std::vector<Vertex3D> &vertices, std::size_t maxLeafSize)
{ std::vector<Vertex3D> vertexCopy{ vertices }; fromVertices(std::move(vertexCopy), maxLeafSize); }

void PointCloudAcceleration::fromVertices(std::vector<Vertex3D> &&vertices, std::size_t maxLeafSize)
{
    if (!mData)
    { mData = std::make_shared<PointCloud>( ); }

    mData->points() = std::move(vertices);

    mIndex = std::make_shared<KdTree>(PointCloud::DATA_DIMENSIONALITY, *mData,
        nanoflann::KDTreeSingleIndexAdaptorParams(maxLeafSize));
    mIndex->buildIndex();
}

void PointCloudAcceleration::fromVertices(const Vertex3D *vertices, std::size_t vertexCount,
    std::size_t maxLeafSize)
{
    std::vector<Vertex3D> vertexCopy{ vertices, vertices + vertexCount };
    fromVertices(std::move(vertexCopy), maxLeafSize);
}

PointCloudAcceleration::QueryResult PointCloudAcceleration::queryRange(const Vector3D &p,
    float range, std::size_t maxNeighbors, bool sort) const
{
    QueryResult result{ };
    nanoflann::SearchParams searchParams{ };
    searchParams.sorted = sort;
    const auto found{ mIndex->radiusSearch(&p[0], range * range, result.points, searchParams) };

    if (maxNeighbors && found > maxNeighbors)
    { result.points.resize(maxNeighbors); }

    result.sorted = sort;
    return result;
}

PointCloudAcceleration::QueryResult PointCloudAcceleration::queryKNN(const Vector3D &p,
    std::size_t maxNeighbors) const
{
    QueryResult result{ };

    std::vector<QueryResult::IndexT> indices{ };
    indices.resize(maxNeighbors);
    std::vector<QueryResult::DistanceT> distances{ };
    distances.resize(maxNeighbors);
    const auto found{ mIndex->knnSearch(&p[0], maxNeighbors, indices.data(), distances.data()) };

    result.points.resize(found);
    for (std::size_t iii = 0u; iii < found; ++iii)
    { result.points[iii] = std::make_pair(indices[iii], distances[iii]); }

    // TODO - Check it is actually sorted.
    result.sorted = true;
    return result;
}

PointCloudAcceleration::QueryResult PointCloudAcceleration::queryPosition(const Vector3D &p) const
{ return queryKNN(p, 1u); }

PointCloudAcceleration::LegacyKdTreePtr PointCloudAcceleration::toLegacyKdTree() const
{
    std::vector<kd::Vector3D> positions{ };
    const auto vertexCount{ mData->points().size() };
    positions.resize(vertexCount);
    for (std::size_t iii = 0u; iii < vertexCount; ++iii)
    { const auto &v{ mData->points()[iii] }; positions[iii] = { v.p.x, v.p.y, v.p.z }; }

    return std::make_shared<LegacyKdTree>(positions.data(), positions.size(), mIndex->index_params.leaf_max_size);
}

namespace impl
{

struct TriangleIntersectorImpl
{
    /// @brief Scalar used for distances and inner operations.
    using ScalarT = TriangleIntersector::ScalarT;
    /// @brief Dimensionality of the accelerated space.
    static constexpr auto Dimensionality{ 3u };

    /// @brier Wrapper around acceleration object which includes index of the original primitive.
    class AccelerationObject : public Eigen::AlignedBox<ScalarT, Dimensionality>
    {
    public:
        /// Epsilon used when constructing loose bounding box.
        static constexpr auto EPS{ std::numeric_limits<float>::epsilon() };

        /// @brief Empty acceleration object.
        inline AccelerationObject();

        /// @brief Create the acceleration object with index to original primitive.
        inline AccelerationObject(std::size_t primitiveIdx, const Vector3D &min, const Vector3D &max);

        /// @brief Get reference to the original primitive.
        inline TriangleIntersector::PrimitiveIdxT primitiveIdx() const;
    private:
        /// Index to the original primitive.
        std::size_t mPrimitiveIdx{ };
    protected:
    }; // class AccelerationObject

    /// @brief Object used in the acceleration structure nodes.
    using AccelerationObjectT = AccelerationObject;

    /// @brief Acceleration structure used for the operations.
    using SpatialAcceleratorT = Eigen::KdBVH<ScalarT, Dimensionality, TriangleIntersector::PrimitiveT>;

    /// @brief Type used for storing the list of currently accelerated primitives.
    using PrimitiveStoreT = std::vector<TriangleIntersector::PrimitiveT>;
    /// @brief Type used for storing the list of acceleration objects.
    using AccelerationStoreT = std::vector<AccelerationObjectT>;

    /// @brief Helper used for detecting volume intersections.
    template <typename TargetT, typename VolumeT, typename AccelerationT>
    struct VolumeIntersector;

    /// @brief Helper used for detecting object intersections.
    template <typename TargetT>
    struct ObjectIntersector;

    /// @brief Aggregator used for hit queries.
    template <typename TargetT>
    struct HitQueryAggregator;

    /// @brief Aggregator used for nearest hit queries.
    template <typename TargetT>
    struct NearestQueryAggregator;

    /// @brief Functor used for intersection queries.
    template <typename TargetT, typename AggregatorT>
    class IntersectQuery
    {
    public:
        /// @brief Shortcut for the volume intersector type.
        using VolumeIntersectorT = VolumeIntersector<TargetT,
            SpatialAcceleratorT::Volume, TriangleIntersectorImpl::AccelerationObjectT>;
        /// @brief Shortcut for the object intersector type.
        using ObjectIntersectorT = ObjectIntersector<TargetT>;

        /// @brief Initialize intersection query for given target. Set limit to non-zero to end after finding set amount of hits.
        template <typename... AggCArgTs>
        IntersectQuery(const TargetT &target, AggCArgTs... aggregatorArguments);

        /// @brief Returns true if the volume intersects current query.
        bool intersectVolume(const SpatialAcceleratorT::Volume &volume);
        /// @brief Returns true if the search should end immediately.
        bool intersectObject(const SpatialAcceleratorT::Object &object);

        /// @brief Get result aggregator of the intersection query.
        const AggregatorT &aggregator() const;
        /// @brief Get queried target.
        const TriangleIntersector::PrimitiveT &target() const;
    private:
        /// Target being queried.
        TargetT mTarget{ };
        /// Acceleration object of the target.
        TriangleIntersectorImpl::AccelerationObjectT mAcceleration{ };
        /// Aggregator of results.
        AggregatorT mAggregator{ };
    protected:
    }; // class IntersectQuery

    /// @brief Create acceleration object for given primitive, which is at provided index in the primitive array.
    static AccelerationObjectT createAccelerationObject(const TriangleIntersector::PrimitiveT &primitive,
        std::size_t idx = 0u);

    /// @brief Create acceleration object for given point.
    static AccelerationObjectT createAccelerationObject(const Vector3D &point);

    /// @brief Create acceleration object for given ray.
    static AccelerationObjectT createAccelerationObject(const Ray &ray);

    /// @brief Build the acceleration structure for given list of primitives.
    void buildAccelerator(const TriangleIntersector::PrimitiveSetT &primitives);

    /// @brief Perform intersection query with given primitive against the built acceleration structure.
    TriangleIntersector::IntersectResultT queryIntersect(const TriangleIntersector::PrimitiveT &primitive,
        std::size_t limit = 0u) const;

    /// @brief Perform intersection query for primitives which contain given point.
    TriangleIntersector::IntersectResultT queryPoint(const Vector3D &point, std::size_t limit = 0u) const;

    /// @brief Perform intersection query for primitives having intersection with given ray.
    TriangleIntersector::IntersectResultT queryRay(const Ray &ray, std::size_t limit = 0u) const;

    /// @brief Find nearest primitive intersection with given ray and return its index and distance.
    TriangleIntersector::NearestIntersectResultT queryRayNearest(const Ray &ray) const;

    /// Currently used acceleration structure.
    std::unique_ptr<SpatialAcceleratorT> accelerator{ };

    /// Primitives stored in the acceleration structure.
    PrimitiveStoreT primitives{ };
    /// Acceleration objects to the corresponding primitives.
    AccelerationStoreT accelerations{ };
}; // struct TriangleIntersectorImpl

inline TriangleIntersectorImpl::AccelerationObject::AccelerationObject()
{ /* Automatic */ }

inline TriangleIntersectorImpl::AccelerationObject::AccelerationObject(
    std::size_t primitiveIdx, const Vector3D &min, const Vector3D &max) :
    AlignedBox(
        VectorType{ min.x - EPS, min.y - EPS, min.z - EPS },
        VectorType{ max.x + EPS, max.y + EPS, max.z + EPS }),
    mPrimitiveIdx{ primitiveIdx }
{ }

inline TriangleIntersector::PrimitiveIdxT TriangleIntersectorImpl::AccelerationObject::primitiveIdx() const
{ return mPrimitiveIdx; }

template <typename TargetT, typename VolumeT, typename AccelerationT>
struct TriangleIntersectorImpl::VolumeIntersector
{
    /// @brief Check intersection of given target and its acceleration agains the volume.
    static bool intersectVolume(const TargetT &target, const VolumeT &volume, const AccelerationT &acceleration);
}; // struct VolumeIntersector

template <typename TargetT, typename VolumeT, typename AccelerationT>
bool TriangleIntersectorImpl::VolumeIntersector<TargetT, VolumeT, AccelerationT>::intersectVolume(
    const TargetT &target, const VolumeT &volume, const AccelerationT &acceleration)
{ return volume.intersects(acceleration); }

template <typename VolumeT, typename AccelerationT>
struct TriangleIntersectorImpl::VolumeIntersector<Ray, VolumeT, AccelerationT>
{
    /// @brief Check intersection of given target and its acceleration agains the volume.
    static bool intersectVolume(const Ray &target, const VolumeT &volume, const AccelerationT &acceleration);
}; // struct VolumeIntersector

template <typename VolumeT, typename AccelerationT>
bool TriangleIntersectorImpl::VolumeIntersector<Ray, VolumeT, AccelerationT>::intersectVolume(
    const Ray &target, const VolumeT &volume, const AccelerationT &acceleration)
{
    // Perform ray-aabb intersection test.
    const auto min{ volume.corner(SpatialAcceleratorT::Volume::BottomLeftFloor) };
    const auto max{ volume.corner(SpatialAcceleratorT::Volume::TopRightCeil) };
    BoundingBox3D bb({ min.x(), min.y(), min.z() }, { max.x(), max.y(), max.z() });

    return bb.intersects(target);
}

template <typename TargetT>
struct TriangleIntersectorImpl::ObjectIntersector
{
    /// @brief Perform intersection test and fill members.
    ObjectIntersector(const TargetT &target, const SpatialAcceleratorT::Object &object);

    /// Distance of the intersection point.
    ScalarT distance{ TriangleIntersector::InvalidScalar };
    /// Does the object intersect target?
    bool intersects{ false };
    /// Index of the object.
    TriangleIntersector::PrimitiveIdxT objectIdx{ TriangleIntersector::InvalidPrimitiveIdx };
}; // struct ObjectIntersector

template <>
TriangleIntersectorImpl::ObjectIntersector<TriangleIntersector::PrimitiveT>::ObjectIntersector(
    const TriangleIntersector::PrimitiveT &target, const SpatialAcceleratorT::Object &object)
{ distance = 0.0f; intersects = target.intersects(object); objectIdx = object.tIdx; }

template <>
TriangleIntersectorImpl::ObjectIntersector<Vector3D>::ObjectIntersector(
    const Vector3D &target, const SpatialAcceleratorT::Object &object)
{ distance = 0.0f; intersects = object.contains(target); objectIdx = object.tIdx; }

template <>
TriangleIntersectorImpl::ObjectIntersector<Ray>::ObjectIntersector(
    const Ray &target, const SpatialAcceleratorT::Object &object)
{ distance = object.intersection(target); intersects = distance < TriangleIntersector::InvalidScalar; objectIdx = object.tIdx; }

template <typename TargetT>
struct TriangleIntersectorImpl::HitQueryAggregator
{
    /// @brief Aggregate results up to given limit. Set to zero for unlimited results.
    HitQueryAggregator(std::size_t resultLimit = 0u) :
        limit{ resultLimit }
    { }

    /// @brief Check intersection with given object and return whether to quit.
    bool checkAddFull(const ObjectIntersector<TargetT> &intersector);

    /// @brief Limiti of the number of results.
    std::size_t limit{ 0u };
    /// @brief List of results.
    std::vector<TriangleIntersector::PrimitiveIdxT> results{ };
}; // struct HitQueryAggregator

template <typename TargetT>
bool TriangleIntersectorImpl::HitQueryAggregator<TargetT>::checkAddFull(
    const ObjectIntersector<TargetT> &intersector)
{
    if (intersector.intersects)
    { // Found intersecting triangle -> Add it to the list.
        results.push_back(intersector.objectIdx);
    }

    // Returns true only when we have found requested number of hits.
    return (limit > 0u) ? (results.size() >= limit) : false;
}

/// @brief Aggregator used for nearest hit queries.
template <typename TargetT>
struct TriangleIntersectorImpl::NearestQueryAggregator
{
    /// @brief Aggregate results up to given limit. Set to zero for unlimited results.
    NearestQueryAggregator()
    { }

    /// @brief Check intersection with given object and return whether to quit.
    bool checkAddFull(const ObjectIntersector<TargetT> &intersector);

    /// @brief Distance of the currently nearest result.
    ScalarT distance{ TriangleIntersector::InvalidScalar };
    /// @brief Index of the currently nearest result.
    TriangleIntersector::PrimitiveIdxT nearestIdx{ TriangleIntersector::InvalidPrimitiveIdx };
}; // struct NearestQueryAggregator

template <typename TargetT>
bool TriangleIntersectorImpl::NearestQueryAggregator<TargetT>::checkAddFull(
    const ObjectIntersector<TargetT> &intersector)
{
    const auto intersectionDistance{ intersector.distance };
    if (intersectionDistance < distance && intersectionDistance > ScalarT(0) && intersector.intersects)
    { // Found new nearest -> remember its index and distance.
        nearestIdx = intersector.objectIdx;
        distance = intersectionDistance;
    }

    // Never full, we need to check all possibilities.
    return false;
}

template <typename TargetT, typename AggregatorT>
template <typename... AggCArgTs>
TriangleIntersectorImpl::IntersectQuery<TargetT, AggregatorT>::IntersectQuery(
    const TargetT &target, AggCArgTs... aggregatorArguments) :
    mTarget{ target }, mAcceleration{ createAccelerationObject(target) },
    mAggregator(std::forward<AggCArgTs>(aggregatorArguments)...)
{ }

template <typename TargetT, typename AggregatorT>
bool TriangleIntersectorImpl::IntersectQuery<TargetT, AggregatorT>::intersectVolume(
    const SpatialAcceleratorT::Volume &volume)
{
    // Go down to the leafs and find all potential intersections.
    return VolumeIntersectorT::intersectVolume(mTarget, volume, mAcceleration);
}

template <typename TargetT, typename AggregatorT>
bool TriangleIntersectorImpl::IntersectQuery<TargetT, AggregatorT>::intersectObject(
    const SpatialAcceleratorT::Object &object)
{ return mAggregator.checkAddFull(ObjectIntersector(mTarget, object)); }

template <typename TargetT, typename AggregatorT>
const AggregatorT &TriangleIntersectorImpl::IntersectQuery<TargetT, AggregatorT>::aggregator() const
{ return mAggregator; }
template <typename TargetT, typename AggregatorT>
const TriangleIntersector::PrimitiveT &TriangleIntersectorImpl::IntersectQuery<TargetT, AggregatorT>::target() const
{ return mTarget; }

TriangleIntersectorImpl::AccelerationObjectT TriangleIntersectorImpl::createAccelerationObject(
    const TriangleIntersector::PrimitiveT &primitive, std::size_t idx)
{
    const auto aabb{ primitive.aabb() };
    return AccelerationObjectT(idx, aabb.min, aabb.max);
}

TriangleIntersectorImpl::AccelerationObjectT TriangleIntersectorImpl::createAccelerationObject(const Vector3D &point)
{ return AccelerationObjectT(0u, point, point); }

TriangleIntersectorImpl::AccelerationObjectT TriangleIntersectorImpl::createAccelerationObject(const Ray &ray)
{
    // Create binding box extending to infinity.
    const auto firstCorner{ ray.origin };
    const auto secondCorner{ ray.direction.sgn() * Vector3D::maxVector() };
    return AccelerationObjectT(0u,
        Vector3D::elementMin(firstCorner, secondCorner),
        Vector3D::elementMax(firstCorner, secondCorner));
}

void TriangleIntersectorImpl::buildAccelerator(const TriangleIntersector::PrimitiveSetT &p)
{
    const auto primitiveCount{ p.size() };

    // Switch to new primitives.
    primitives = p;
    accelerations.resize(primitiveCount);

    // Re-calculate acceleration objects.
    for (std::size_t iii = 0u; iii < accelerations.size(); ++iii)
    { accelerations[iii] = createAccelerationObject(primitives[iii], iii); }

    // Create the accelerator.
    accelerator = std::make_unique<SpatialAcceleratorT>(
        primitives.begin(), primitives.end(), accelerations.begin(), accelerations.end());
}

TriangleIntersector::IntersectResultT TriangleIntersectorImpl::queryIntersect(
    const TriangleIntersector::PrimitiveT &primitive, std::size_t limit) const
{
    if (!accelerator)
    { return { }; }

    using TargetT = TriangleIntersector::PrimitiveT;
    IntersectQuery<TargetT, HitQueryAggregator<TargetT>> query(primitive, limit);
    Eigen::BVIntersect(*accelerator, query);

    return query.aggregator().results;
}

TriangleIntersector::IntersectResultT TriangleIntersectorImpl::queryPoint(
    const Vector3D &point, std::size_t limit) const
{
    if (!accelerator)
    { return { }; }

    using TargetT = Vector3D;
    IntersectQuery<TargetT, HitQueryAggregator<TargetT>> query(point, limit);
    Eigen::BVIntersect(*accelerator, query);

    return query.aggregator().results;
}

TriangleIntersector::IntersectResultT TriangleIntersectorImpl::queryRay(
    const Ray &ray, std::size_t limit) const
{
    if (!accelerator)
    { return { }; }

    using TargetT = Ray;
    IntersectQuery<TargetT, HitQueryAggregator<TargetT>> query(ray, limit);
    Eigen::BVIntersect(*accelerator, query);

    return query.aggregator().results;
}

TriangleIntersector::NearestIntersectResultT TriangleIntersectorImpl::queryRayNearest( const Ray &ray) const
{
    if (!accelerator)
    { return { }; }

    using TargetT = Ray;
    IntersectQuery<TargetT, NearestQueryAggregator<TargetT>> query(ray);
    Eigen::BVIntersect(*accelerator, query);

    return { query.aggregator().nearestIdx, query.aggregator().distance };
}

} // namespace impl

TriangleIntersector::TriangleIntersector() :
    TriangleIntersector(PrimitiveSetT{ })
{ }

TriangleIntersector::~TriangleIntersector()
{ /* Automatic */ }

TriangleIntersector::TriangleIntersector(const PrimitiveSetT &primitives)
{ create(primitives); }

void TriangleIntersector::create(const PrimitiveSetT &primitives)
{
    mImpl = std::make_unique<impl::TriangleIntersectorImpl>();
    mImpl->buildAccelerator(primitives);
}

const TriangleIntersector::PrimitiveSetT &TriangleIntersector::primitives() const
{ return mImpl->primitives; }

TriangleIntersector::IntersectResultT TriangleIntersector::queryIntersect(
    const PrimitiveT &primitive, std::size_t limit) const
{ return mImpl ? mImpl->queryIntersect(primitive, limit) : IntersectResultT{ }; }

TriangleIntersector::IntersectResultT TriangleIntersector::queryPoint(
    const Vector3D &point, std::size_t limit) const
{ return mImpl ? mImpl->queryPoint(point, limit) : IntersectResultT{ }; }

TriangleIntersector::IntersectResultT TriangleIntersector::queryRay(
    const Vector3D &origin, const Vector3D &direction, std::size_t limit) const
{ return mImpl ? mImpl->queryRay(Ray{ origin, direction }, limit) : IntersectResultT{ }; }

TriangleIntersector::NearestIntersectResultT TriangleIntersector::queryRayNearest(
    const Vector3D &origin, const Vector3D &direction) const
{ return mImpl ? mImpl->queryRayNearest(Ray{ origin, direction }) : InvalidIdxDistance; }

TriangleIntersector::NearestIntersectResultT TriangleIntersector::checkOcclusion(
    const Vector3D &first, const Vector3D &second) const
{
    const auto rayOrigin{ first };
    const auto rayDirection{ second - first };
    const auto rayDirectionNorm{ rayDirection.normalized() };
    const auto distance{ rayDirection.length() };
    const auto nearestQuery{ queryRayNearest(rayOrigin, rayDirectionNorm) };

    return (nearestQuery.second <= (distance + std::numeric_limits<ScalarT>::epsilon())) ? nearestQuery : InvalidIdxDistance;
}

} // namespace treeacc


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

/*
 Copyright (C) 2006 Joseph Wang
 Copyright (C) 2010 Liquidnet Holdings, Inc.

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

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

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

/*! \file timeseries.hpp
    \brief Container for historical data
*/

#ifndef quantlib_timeseries_hpp
#define quantlib_timeseries_hpp

#include <ql/time/date.hpp>
#include <ql/utilities/null.hpp>
#include <ql/errors.hpp>
#include <ql/functional.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <boost/utility.hpp>
#include <map>
#include <vector>

namespace QuantLib {

    //! Container for historical data
    /*! This class acts as a generic repository for a set of
        historical data.  Any single datum can be accessed through its
        date, while sets of consecutive data can be accessed through
        iterators.

        \pre The <c>Container</c> type must satisfy the requirements
             set by the C++ standard for associative containers.
    */
    template <class T, class Container = std::map<Date, T> >
    class TimeSeries {
      public:
        typedef Date key_type;
        typedef T value_type;
      private:
        mutable Container values_;
      public:
        /*! Default constructor */
        TimeSeries() {}
        /*! This constructor initializes the history with a set of
            values passed as two sequences, the first containing dates
            and the second containing corresponding values.
        */
        template <class DateIterator, class ValueIterator>
        TimeSeries(DateIterator dBegin, DateIterator dEnd,
                   ValueIterator vBegin) {
            while (dBegin != dEnd)
                values_[*(dBegin++)] = *(vBegin++);
        }
        /*! This constructor initializes the history with a set of
            values. Such values are assigned to a corresponding number
            of consecutive dates starting from firstDate
            included.
        */
        template <class ValueIterator>
        TimeSeries(const Date& firstDate,
                   ValueIterator begin, ValueIterator end) {
            Date d = firstDate;
            while (begin != end)
                values_[d++] = *(begin++);
        }
        //! \name Inspectors
        //@{
        //! returns the first date for which a historical datum exists
        Date firstDate() const;
        //! returns the last date for which a historical datum exists
        Date lastDate() const;
        //! returns the number of historical data including null ones
        Size size() const;
        //! returns whether the series contains any data
        bool empty() const;
        //@}
        //! \name Historical data access
        //@{
        //! returns the (possibly null) datum corresponding to the given date
        T operator[](const Date& d) const {
            if (values_.find(d) != values_.end())
                return values_[d];
            else
                return Null<T>();
        }
        T& operator[](const Date& d) {
            if (values_.find(d) == values_.end())
                values_[d] = Null<T>();
            return values_[d];
        }
        //@}

        //! \name Iterators
        //@{
        typedef typename Container::const_iterator const_iterator;
        typedef typename const_iterator::iterator_category iterator_category;

        // Reverse iterators
        // The following class makes compilation fail for the code
        // that calls rbegin or rend with a container that does not
        // support reverse iterators.  All the rest TimeSeries class
        // features should compile and work for this type of
        // containers.
        template <class container, class iterator_category>
        struct reverse {
            typedef boost::reverse_iterator<typename container::const_iterator>
                                                       const_reverse_iterator;
            reverse(const container& c) : c_(c) {}
            const_reverse_iterator rbegin() const {
                return const_reverse_iterator(c_.end());
            }
            const_reverse_iterator rend() const {
                return const_reverse_iterator(c_.begin());
            }
            const container& c_;
        };

        // This class defines reverse iterator features via
        // container's native calls.
        template <class container>
        struct reverse<container, std::bidirectional_iterator_tag> {
            typedef typename container::const_reverse_iterator
                                                       const_reverse_iterator;
            reverse(const container& c) : c_(c) {}
            const_reverse_iterator rbegin() const { return c_.rbegin(); }
            const_reverse_iterator rend() const { return c_.rend(); }
            const container& c_;
        };

        // The following typedef enables reverse iterators for
        // bidirectional_iterator_tag category.
        typedef typename boost::mpl::if_ <
            boost::mpl::or_ <
                boost::is_same<iterator_category,
                               std::bidirectional_iterator_tag>,
                boost::is_base_of<std::bidirectional_iterator_tag,
                                  iterator_category> >,
            std::bidirectional_iterator_tag,
            std::input_iterator_tag>::type enable_reverse;

        typedef typename
        reverse<Container, enable_reverse>::const_reverse_iterator
                                                       const_reverse_iterator;

        const_iterator cbegin() const;
        const_iterator cend() const;
        const_iterator begin() const { return cbegin(); }
        const_iterator end() const { return cend(); }
        const_reverse_iterator crbegin() const {
            return reverse<Container, enable_reverse>(values_).rbegin();
        }
        const_reverse_iterator crend() const {
            return reverse<Container, enable_reverse>(values_).rend();
        }
        const_reverse_iterator rbegin() const { return crbegin(); }
        const_reverse_iterator rend() const { return crend(); }
        //@}

      private:
        typedef typename Container::value_type container_value_type;
        typedef ext::function<Date(const container_value_type&)>
                                                              projection_time;
        typedef ext::function<T(const container_value_type&)>
                                                             projection_value;

      public:
        //! \name Projection iterators
        //@{

        typedef boost::transform_iterator<projection_time, const_iterator>
                                                          const_time_iterator;
        typedef boost::transform_iterator<projection_value, const_iterator>
                                                         const_value_iterator;
        typedef boost::transform_iterator<projection_time,
                                          const_reverse_iterator>
                                                  const_reverse_time_iterator;
        typedef boost::transform_iterator<projection_value,
                                          const_reverse_iterator>
                                                 const_reverse_value_iterator;

        const_value_iterator cbegin_values() const {
            return const_value_iterator(cbegin(), get_value);
        }
        const_value_iterator cend_values() const {
            return const_value_iterator(cend(), get_value);
        }
        const_reverse_value_iterator crbegin_values() const {
            return const_reverse_value_iterator(crbegin(), get_value);
        }
        const_reverse_value_iterator crend_values() const {
            return const_reverse_value_iterator(crend(), get_value);
        }

        const_time_iterator cbegin_time() const {
            return const_time_iterator(cbegin(), get_time);
        }
        const_time_iterator cend_time() const {
            return const_time_iterator(cend(), get_time);
        }
        const_reverse_time_iterator crbegin_time() const {
            return const_reverse_time_iterator(crbegin(), get_time);
        }
        const_reverse_time_iterator crend_time() const {
            return const_reverse_time_iterator(crend(), get_time);
        }

        //! \name Utilities
        //@{
        const_iterator find(const Date&);
        //! returns the dates for which historical data exist
        std::vector<Date> dates() const;
        //! returns the historical data
        std::vector<T> values() const;
        //@}

      private:
        static const Date& get_time (const container_value_type& v) {
            return v.first;
        }
        static const T& get_value (const container_value_type& v) {
            return v.second;
        }
    };

    // inline definitions

    template <class T, class C>
    inline Date TimeSeries<T,C>::firstDate() const {
        QL_REQUIRE(!values_.empty(), "empty timeseries");
        return values_.begin()->first;
    }

    template <class T, class C>
    inline Date TimeSeries<T,C>::lastDate() const {
        QL_REQUIRE(!values_.empty(), "empty timeseries");
        return rbegin()->first;
    }

    template <class T, class C>
    inline Size TimeSeries<T,C>::size() const {
        return values_.size();
    }

    template <class T, class C>
    inline bool TimeSeries<T,C>::empty() const {
        return values_.empty();
    }

    template <class T, class C>
    inline typename TimeSeries<T,C>::const_iterator
    TimeSeries<T,C>::cbegin() const {
        return values_.begin();
    }

    template <class T, class C>
    inline typename TimeSeries<T,C>::const_iterator
    TimeSeries<T,C>::cend() const {
        return values_.end();
    }

    template <class T, class C>
    inline typename TimeSeries<T,C>::const_iterator
    TimeSeries<T,C>::find(const Date& d) {
        const_iterator i = values_.find(d);
        if (i == values_.end()) {
            values_[d] = Null<T>();
            i = values_.find(d);
        }
        return i;
    }

    template <class T, class C>
    std::vector<Date> TimeSeries<T,C>::dates() const {
        std::vector<Date> v;
        v.reserve(size());
        std::transform(cbegin(), cend(), std::back_inserter(v),
                       TimeSeries<T,C>::get_time);
        return v;
    }

    template <class T, class C>
    std::vector<T> TimeSeries<T,C>::values() const {
        std::vector<T> v;
        v.reserve(size());
        std::transform(cbegin(), cend(), std::back_inserter(v),
                       TimeSeries<T,C>::get_value);
        return v;
    }

}

#endif


/*=============================================================================
    Copyright (c) 2001-2007 Joel de Guzman

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
//  A Roman Numerals Parser (demonstrating the symbol table). This is
//  discussed in the "Symbols" chapter in the Spirit User's Guide.
//
//  [ JDG August 22, 2002 ] spirit1
//  [ JDG March 13, 2007 ]  spirit2
//
///////////////////////////////////////////////////////////////////////////////

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

#include <iostream>
#include <string>

using namespace boost::spirit;
using namespace boost::spirit::qi;
using namespace boost::spirit::ascii;
using namespace boost::spirit::arg_names;
using boost::phoenix::ref;

///////////////////////////////////////////////////////////////////////////////
//  Parse roman hundreds (100..900) numerals using the symbol table.
//  Notice that the data associated with each slot is the parser's attribute
//  (which is passed to attached semantic actions).
///////////////////////////////////////////////////////////////////////////////
//[tutorial_roman_hundreds
struct hundreds_ : symbols<char, unsigned>
{
    hundreds_()
    {
        add
            ("C"    , 100)
            ("CC"   , 200)
            ("CCC"  , 300)
            ("CD"   , 400)
            ("D"    , 500)
            ("DC"   , 600)
            ("DCC"  , 700)
            ("DCCC" , 800)
            ("CM"   , 900)
        ;
    }

} hundreds;
//]

///////////////////////////////////////////////////////////////////////////////
//  Parse roman tens (10..90) numerals using the symbol table.
///////////////////////////////////////////////////////////////////////////////
//[tutorial_roman_tens
struct tens_ : symbols<char, unsigned>
{
    tens_()
    {
        add
            ("X"    , 10)
            ("XX"   , 20)
            ("XXX"  , 30)
            ("XL"   , 40)
            ("L"    , 50)
            ("LX"   , 60)
            ("LXX"  , 70)
            ("LXXX" , 80)
            ("XC"   , 90)
        ;
    }

} tens;
//]

///////////////////////////////////////////////////////////////////////////////
//  Parse roman ones (1..9) numerals using the symbol table.
///////////////////////////////////////////////////////////////////////////////
//[tutorial_roman_ones
struct ones_ : symbols<char, unsigned>
{
    ones_()
    {
        add
            ("I"    , 1)
            ("II"   , 2)
            ("III"  , 3)
            ("IV"   , 4)
            ("V"    , 5)
            ("VI"   , 6)
            ("VII"  , 7)
            ("VIII" , 8)
            ("IX"   , 9)
        ;
    }

} ones;
//]

///////////////////////////////////////////////////////////////////////////////
//  roman (numerals) grammar
//
//      Note the use of the || operator. The expression
//      a || b reads match a or b and in sequence. Try
//      defining the roman numerals grammar in YACC or
//      PCCTS. Spirit rules! :-)
///////////////////////////////////////////////////////////////////////////////
//[tutorial_roman_grammar
template <typename Iterator>
struct roman : grammar<Iterator, unsigned()>
{
    roman() : roman::base_type(start)
    {
        start = eps             [_val = 0] >>
            (
                +char_('M')     [_val += 1000]
                ||  hundreds    [_val += _1]
                ||  tens        [_val += _1]
                ||  ones        [_val += _1]
            )
        ;
    }

    rule<Iterator, unsigned()> start;
};
//]

///////////////////////////////////////////////////////////////////////////////
//  Main program
///////////////////////////////////////////////////////////////////////////////
int
main()
{
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "\t\tRoman Numerals Parser\n\n";
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Type a Roman Numeral ...or [q or Q] to quit\n\n";

    typedef std::string::const_iterator iterator_type;
    typedef roman<iterator_type> roman;

    roman roman_parser; // Our grammar

    std::string str;
    unsigned result;
    while (std::getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
        //[tutorial_roman_grammar_parse
        bool r = parse(iter, end, roman_parser, result);

        if (r && iter == end)
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing succeeded\n";
            std::cout << "result = " << result << std::endl;
            std::cout << "-------------------------\n";
        }
        else
        {
            std::string rest(iter, end);
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "stopped at: \": " << rest << "\"\n";
            std::cout << "-------------------------\n";
        }
        //]
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}


/* Boost interval/utility.hpp template implementation file
 *
 * Copyright 2000 Jens Maurer
 * Copyright 2002-2003 Herv� Br�nnimann, Guillaume Melquiond, Sylvain Pion
 *
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or
 * copy at http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_NUMERIC_INTERVAL_UTILITY_HPP
#define BOOST_NUMERIC_INTERVAL_UTILITY_HPP

#include <boost/config.hpp>
#include <boost/numeric/interval/detail/interval_prototype.hpp>
#include <boost/numeric/interval/detail/test_input.hpp>
#include <boost/numeric/interval/detail/bugs.hpp>
#include <algorithm>
#include <utility>

/*
 * Implementation of simple functions
 */

namespace boost {
namespace numeric {

/*
 * Utility Functions
 */

template<class T, class Policies> inline
const T& lower(const interval<T, Policies>& x)
{
  return x.lower();
}

template<class T, class Policies> inline
const T& upper(const interval<T, Policies>& x)
{
  return x.upper();
}

template<class T, class Policies> inline
T checked_lower(const interval<T, Policies>& x)
{
  if (empty(x)) {
    typedef typename Policies::checking checking;
    return checking::nan();
  }
  return x.lower();
}

template<class T, class Policies> inline
T checked_upper(const interval<T, Policies>& x)
{
  if (empty(x)) {
    typedef typename Policies::checking checking;
    return checking::nan();
  }
  return x.upper();
}

template<class T, class Policies> inline
T width(const interval<T, Policies>& x)
{
  if (interval_lib::detail::test_input(x)) return static_cast<T>(0);
  typename Policies::rounding rnd;
  return rnd.sub_up(x.upper(), x.lower());
}

template<class T, class Policies> inline
T median(const interval<T, Policies>& x)
{
  if (interval_lib::detail::test_input(x)) {
    typedef typename Policies::checking checking;
    return checking::nan();
  }
  typename Policies::rounding rnd;
  return rnd.median(x.lower(), x.upper());
}

template<class T, class Policies> inline
interval<T, Policies> widen(const interval<T, Policies>& x, const T& v)
{
  if (interval_lib::detail::test_input(x))
    return interval<T, Policies>::empty();
  typename Policies::rounding rnd;
  return interval<T, Policies>(rnd.sub_down(x.lower(), v),
                               rnd.add_up  (x.upper(), v), true);
}

/*
 * Set-like operations
 */

template<class T, class Policies> inline
bool empty(const interval<T, Policies>& x)
{
  return interval_lib::detail::test_input(x);
}

template<class T, class Policies> inline
bool zero_in(const interval<T, Policies>& x)
{
  if (interval_lib::detail::test_input(x)) return false;
  return (!interval_lib::user::is_pos(x.lower())) &&
         (!interval_lib::user::is_neg(x.upper()));
}

template<class T, class Policies> inline
bool in_zero(const interval<T, Policies>& x) // DEPRECATED
{
  return zero_in<T, Policies>(x);
}

template<class T, class Policies> inline
bool in(const T& x, const interval<T, Policies>& y)
{
  if (interval_lib::detail::test_input(x, y)) return false;
  return y.lower() <= x && x <= y.upper();
}

template<class T, class Policies> inline
bool subset(const interval<T, Policies>& x,
            const interval<T, Policies>& y)
{
  if (empty(x)) return true;
  return !empty(y) && y.lower() <= x.lower() && x.upper() <= y.upper();
}

template<class T, class Policies1, class Policies2> inline
bool proper_subset(const interval<T, Policies1>& x,
                   const interval<T, Policies2>& y)
{
  if (empty(y)) return false;
  if (empty(x)) return true;
  return y.lower() <= x.lower() && x.upper() <= y.upper() &&
         (y.lower() != x.lower() || x.upper() != y.upper());
}

template<class T, class Policies1, class Policies2> inline
bool overlap(const interval<T, Policies1>& x,
             const interval<T, Policies2>& y)
{
  if (interval_lib::detail::test_input(x, y)) return false;
  return (x.lower() <= y.lower() && y.lower() <= x.upper()) ||
         (y.lower() <= x.lower() && x.lower() <= y.upper());
}

template<class T, class Policies> inline
bool singleton(const interval<T, Policies>& x)
{
 return !empty(x) && x.lower() == x.upper();
}

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

template<class T, class Policies> inline
interval<T, Policies> intersect(const interval<T, Policies>& x,
                                const interval<T, Policies>& y)
{
  BOOST_USING_STD_MIN();
  BOOST_USING_STD_MAX();
  if (interval_lib::detail::test_input(x, y))
    return interval<T, Policies>::empty();
  const T& l = max BOOST_PREVENT_MACRO_SUBSTITUTION(x.lower(), y.lower());
  const T& u = min BOOST_PREVENT_MACRO_SUBSTITUTION(x.upper(), y.upper());
  if (l <= u) return interval<T, Policies>(l, u, true);
  else        return interval<T, Policies>::empty();
}

template<class T, class Policies> inline
interval<T, Policies> hull(const interval<T, Policies>& x,
                           const interval<T, Policies>& y)
{
  BOOST_USING_STD_MIN();
  BOOST_USING_STD_MAX();
  bool bad_x = interval_lib::detail::test_input(x);
  bool bad_y = interval_lib::detail::test_input(y);
  if (bad_x)
    if (bad_y) return interval<T, Policies>::empty();
    else       return y;
  else
    if (bad_y) return x;
  return interval<T, Policies>(min BOOST_PREVENT_MACRO_SUBSTITUTION(x.lower(), y.lower()),
                               max BOOST_PREVENT_MACRO_SUBSTITUTION(x.upper(), y.upper()), true);
}

template<class T, class Policies> inline
interval<T, Policies> hull(const interval<T, Policies>& x, const T& y)
{
  BOOST_USING_STD_MIN();
  BOOST_USING_STD_MAX();
  bool bad_x = interval_lib::detail::test_input(x);
  bool bad_y = interval_lib::detail::test_input<T, Policies>(y);
  if (bad_y)
    if (bad_x) return interval<T, Policies>::empty();
    else       return x;
  else
    if (bad_x) return interval<T, Policies>(y, y, true);
  return interval<T, Policies>(min BOOST_PREVENT_MACRO_SUBSTITUTION(x.lower(), y),
                               max BOOST_PREVENT_MACRO_SUBSTITUTION(x.upper(), y), true);
}

template<class T, class Policies> inline
interval<T, Policies> hull(const T& x, const interval<T, Policies>& y)
{
  BOOST_USING_STD_MIN();
  BOOST_USING_STD_MAX();
  bool bad_x = interval_lib::detail::test_input<T, Policies>(x);
  bool bad_y = interval_lib::detail::test_input(y);
  if (bad_x)
    if (bad_y) return interval<T, Policies>::empty();
    else       return y;
  else
    if (bad_y) return interval<T, Policies>(x, x, true);
  return interval<T, Policies>(min BOOST_PREVENT_MACRO_SUBSTITUTION(x, y.lower()),
                               max BOOST_PREVENT_MACRO_SUBSTITUTION(x, y.upper()), true);
}

template<class T> inline
interval<T> hull(const T& x, const T& y)
{
  return interval<T>::hull(x, y);
}

template<class T, class Policies> inline
std::pair<interval<T, Policies>, interval<T, Policies> >
bisect(const interval<T, Policies>& x)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x))
    return std::pair<I,I>(I::empty(), I::empty());
  const T m = median(x);
  return std::pair<I,I>(I(x.lower(), m, true), I(m, x.upper(), true));
}

/*
 * Elementary functions
 */

template<class T, class Policies> inline
T norm(const interval<T, Policies>& x)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x)) {
    typedef typename Policies::checking checking;
    return checking::nan();
  }
  BOOST_USING_STD_MAX();
  return max BOOST_PREVENT_MACRO_SUBSTITUTION(static_cast<T>(-x.lower()), x.upper());
}

template<class T, class Policies> inline
interval<T, Policies> abs(const interval<T, Policies>& x)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x))
    return I::empty();
  if (!interval_lib::user::is_neg(x.lower())) return x;
  if (!interval_lib::user::is_pos(x.upper())) return -x;
  BOOST_USING_STD_MAX();
  return I(static_cast<T>(0), max BOOST_PREVENT_MACRO_SUBSTITUTION(static_cast<T>(-x.lower()), x.upper()), true);
}

template<class T, class Policies> inline
interval<T, Policies> max BOOST_PREVENT_MACRO_SUBSTITUTION (const interval<T, Policies>& x,
                                                            const interval<T, Policies>& y)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x, y))
    return I::empty();
  BOOST_USING_STD_MAX();
  return I(max BOOST_PREVENT_MACRO_SUBSTITUTION(x.lower(), y.lower()), max BOOST_PREVENT_MACRO_SUBSTITUTION(x.upper(), y.upper()), true);
}

template<class T, class Policies> inline
interval<T, Policies> max BOOST_PREVENT_MACRO_SUBSTITUTION (const interval<T, Policies>& x, const T& y)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x, y))
    return I::empty();
  BOOST_USING_STD_MAX();
  return I(max BOOST_PREVENT_MACRO_SUBSTITUTION(x.lower(), y), max BOOST_PREVENT_MACRO_SUBSTITUTION(x.upper(), y), true);
}

template<class T, class Policies> inline
interval<T, Policies> max BOOST_PREVENT_MACRO_SUBSTITUTION (const T& x, const interval<T, Policies>& y)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x, y))
    return I::empty();
  BOOST_USING_STD_MAX();
  return I(max BOOST_PREVENT_MACRO_SUBSTITUTION(x, y.lower()), max BOOST_PREVENT_MACRO_SUBSTITUTION(x, y.upper()), true);
}

template<class T, class Policies> inline
interval<T, Policies> min BOOST_PREVENT_MACRO_SUBSTITUTION (const interval<T, Policies>& x,
                                                            const interval<T, Policies>& y)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x, y))
    return I::empty();
  BOOST_USING_STD_MIN();
  return I(min BOOST_PREVENT_MACRO_SUBSTITUTION(x.lower(), y.lower()), min BOOST_PREVENT_MACRO_SUBSTITUTION(x.upper(), y.upper()), true);
}

template<class T, class Policies> inline
interval<T, Policies> min BOOST_PREVENT_MACRO_SUBSTITUTION (const interval<T, Policies>& x, const T& y)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x, y))
    return I::empty();
  BOOST_USING_STD_MIN();
  return I(min BOOST_PREVENT_MACRO_SUBSTITUTION(x.lower(), y), min BOOST_PREVENT_MACRO_SUBSTITUTION(x.upper(), y), true);
}

template<class T, class Policies> inline
interval<T, Policies> min BOOST_PREVENT_MACRO_SUBSTITUTION (const T& x, const interval<T, Policies>& y)
{
  typedef interval<T, Policies> I;
  if (interval_lib::detail::test_input(x, y))
    return I::empty();
  BOOST_USING_STD_MIN();
  return I(min BOOST_PREVENT_MACRO_SUBSTITUTION(x, y.lower()), min BOOST_PREVENT_MACRO_SUBSTITUTION(x, y.upper()), true);
}

} // namespace numeric
} // namespace boost

#endif // BOOST_NUMERIC_INTERVAL_UTILITY_HPP


// Copyright (c) 2021, University of Colorado Denver. All rights reserved.
//
// This file is part of <T>LAPACK.
// <T>LAPACK is free software: you can redistribute it and/or modify it under
// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.

#ifndef __TLAPACK_EIGEN_HH__
#define __TLAPACK_EIGEN_HH__

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

namespace blas{

    // // -----------------------------------------------------------------------------
    // // is_EigenBlock

    // template< class >
    // struct is_EigenBlock : public std::false_type {};

    // template< typename T, int R, int C, bool P >
    // struct is_EigenBlock< Eigen::Block<T,R,C,P> > : public std::true_type {};

    // -----------------------------------------------------------------------------
    // Data traits for Eigen

    #ifndef TBLAS_ARRAY_TRAITS
        #define TBLAS_ARRAY_TRAITS

        // Data type
        template< class T > struct type_trait {};
        template< class T >
        using type_t = typename type_trait< T >::type;

        // Size type
        template< class T > struct sizet_trait {};
        template< class T >
        using size_type = typename sizet_trait< T >::type;

    #endif // TBLAS_ARRAY_TRAITS

    // Data type
    template<typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
    struct type_trait< Eigen::Matrix<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_> > {
        using type = Scalar_;
    };
    template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
    struct type_trait< Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel> > {
        using type = typename XprType::Scalar;
    };
    template<class T>
    struct type_trait< Eigen::VectorBlock<T> > {
        using type = typename T::Scalar;
    };
    template<class T, int idx>
    struct type_trait< Eigen::Diagonal<T,idx> > {
        using type = typename T::Scalar;
    };

    // Size type
    template<typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
    struct sizet_trait< Eigen::Matrix<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_> > {
        using type = Eigen::Index;
    };
    template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
    struct sizet_trait< Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel> > {
        using type = Eigen::Index;
    };
    template<class T>
    struct sizet_trait< Eigen::VectorBlock<T> > {
        using type = Eigen::Index;
    };
    template<class T, int idx>
    struct sizet_trait< Eigen::Diagonal<T,idx> > {
        using type = Eigen::Index;
    };

    // -----------------------------------------------------------------------------
    // blas functions to access Eigen properties

    // Size
    template<class T>
    inline constexpr auto
    size( const Eigen::EigenBase<T>& x ) {
        return x.size();
    }
    // Number of rows
    template<class T>
    inline constexpr auto
    nrows( const Eigen::EigenBase<T>& x ) {
        return x.rows();
    }
    // Number of columns
    template<class T>
    inline constexpr auto
    ncols( const Eigen::EigenBase<T>& x ) {
        return x.cols();
    }

    // -----------------------------------------------------------------------------
    // blas functions to access Eigen block operations

    // Submatrix
    template<class T, typename SliceSpecRow, typename SliceSpecCol>
    inline constexpr auto submatrix(
        const Eigen::DenseBase<T>& A, SliceSpecRow&& rows, SliceSpecCol&& cols ) noexcept
    {
        return A.block( rows.first, cols.first,
                        rows.second-rows.first, cols.second-cols.first );
    }
    template<class T, typename SliceSpecRow, typename SliceSpecCol>
    inline constexpr auto submatrix(
        Eigen::DenseBase<T>& A, SliceSpecRow&& rows, SliceSpecCol&& cols ) noexcept
    {
        return A.block( rows.first, cols.first,
                        rows.second-rows.first, cols.second-cols.first );
    }
    template< typename XprType, int BlockRows, int BlockCols, bool InnerPanel,
              typename SliceSpecRow, typename SliceSpecCol >
    inline constexpr auto submatrix(
        Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel>&& A,
        SliceSpecRow&& rows, SliceSpecCol&& cols ) noexcept
    {
        return A.block( rows.first, cols.first,
                        rows.second-rows.first, cols.second-cols.first );
    }

    // Rows
    template<class T, typename SliceSpec>
    inline constexpr auto rows(
        const Eigen::DenseBase<T>& A, SliceSpec&& rows ) noexcept
    {
        return A.middleRows( rows.first, rows.second-rows.first );
    }
    template<class T, typename SliceSpec>
    inline constexpr auto rows(
        Eigen::DenseBase<T>& A, SliceSpec&& rows ) noexcept
    {
        return A.middleRows( rows.first, rows.second-rows.first );
    }
    template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel,
             typename SliceSpec>
    inline constexpr auto rows(
        Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel>&& A, SliceSpec&& rows ) noexcept
    {
        return A.middleRows( rows.first, rows.second-rows.first );
    }

    // Row
    template<class T>
    inline constexpr auto row( const Eigen::DenseBase<T>& A, Eigen::Index rowIdx ) noexcept
    {
        return A.row( rowIdx );
    }
    template<class T>
    inline constexpr auto row( Eigen::DenseBase<T>& A, Eigen::Index rowIdx ) noexcept
    {
        return A.row( rowIdx );
    }
    template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
    inline constexpr auto row(
        Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel>&& A, Eigen::Index rowIdx ) noexcept
    {
        return A.row( rowIdx );
    }

    // Cols
    template<class T, typename SliceSpec>
    inline constexpr auto cols(
        const Eigen::DenseBase<T>& A, SliceSpec&& cols ) noexcept
    {
        return A.middleCols( cols.first, cols.second-cols.first );
    }
    template<class T, typename SliceSpec>
    inline constexpr auto cols(
        Eigen::DenseBase<T>& A, SliceSpec&& cols ) noexcept
    {
        return A.middleCols( cols.first, cols.second-cols.first );
    }
    template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel,
             typename SliceSpec>
    inline constexpr auto cols(
        Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel>&& A, SliceSpec&& cols ) noexcept
    {
        return A.middleCols( cols.first, cols.second-cols.first );
    }

    // Column
    template<class T>
    inline constexpr auto col( const Eigen::DenseBase<T>& A, Eigen::Index colIdx ) noexcept
    {
        return A.col( colIdx );
    }
    template<class T>
    inline constexpr auto col( Eigen::DenseBase<T>& A, Eigen::Index colIdx ) noexcept
    {
        return A.col( colIdx );
    }
    template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
    inline constexpr auto col( Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel>&& A, Eigen::Index colIdx ) noexcept
    {
        return A.col( colIdx );
    }

    // Subvector
    template<class T, typename SliceSpec>
    inline constexpr auto subvector( const Eigen::DenseBase<T>& v, SliceSpec&& rows ) noexcept
    {
        return v.segment( rows.first, rows.second-rows.first );
    }
    template<class T, typename SliceSpec>
    inline constexpr auto subvector( Eigen::DenseBase<T>& v, SliceSpec&& rows ) noexcept
    {
        return v.segment( rows.first, rows.second-rows.first );
    }
    template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel, typename SliceSpec>
    inline constexpr auto subvector( Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel>&& v, SliceSpec&& rows ) noexcept
    {
        return v.segment( rows.first, rows.second-rows.first );
    }

    // Diagonal
    template<class T>
    inline constexpr auto diag( const Eigen::MatrixBase<T>& A, int diagIdx = 0 ) noexcept
    {
        return A.diagonal( diagIdx );
    }
    template<class T>
    inline constexpr auto diag( Eigen::MatrixBase<T>& A, int diagIdx = 0 ) noexcept
    {
        return A.diagonal( diagIdx );
    }
    template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel, typename SliceSpec>
    inline constexpr auto diag( Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel>&& A, int diagIdx = 0 ) noexcept
    {
        return A.diagonal( diagIdx );
    }

} // namespace blas

namespace lapack {

    using blas::type_trait;
    using blas::sizet_trait;

    using blas::size;
    using blas::nrows;
    using blas::ncols;

    using blas::submatrix;
    using blas::rows;
    using blas::row;
    using blas::cols;
    using blas::col;
    using blas::subvector;
    using blas::diag;

} // namespace lapack

#endif // __TLAPACK_EIGEN_HH__