/* $Id: step-1.cc 27657 2012-11-21 13:19:08Z bangerth $
 *
 * Copyright (C) 1999-2003, 2005-2007, 2009, 2011-2012 by 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}

// The most fundamental class in the library is the Triangulation class, which
// is declared here:
#include <deal.II/grid/tria.h>
// We need the following two includes for loops over cells and/or faces:
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
// Here are some functions to generate standard grids:
#include <deal.II/grid/grid_generator.h>
// We would like to use boundaries which are not straight lines, so we import
// some classes which predefine some boundary descriptions:
#include <deal.II/grid/tria_boundary_lib.h>
// Output of grids in various graphics formats:
#include <deal.II/grid/grid_out.h>

// This is needed for C++ output:
#include <fstream>
// And this for the declarations of the `sqrt' and `fabs' functions:
#include <cmath>

// The final step in importing deal.II is this: All deal.II functions and
// classes are in a namespace dealii, to make sure they don't
// clash with symbols from other libraries you may want to use in conjunction
// with deal.II. One could use these functions and classes by prefixing every
// use of these names by dealii::, but that would quickly become
// cumbersome and annoying. Rather, we simply import the entire deal.II
// namespace for general use:
using namespace dealii;

// @sect3{Creating the first mesh}

// In the following, first function, we simply use the unit square as domain
// and produce a globally refined grid from it.
void first_grid ()
{
  // The first thing to do is to define an object for a triangulation of a
  // two-dimensional domain:
  Triangulation<2> triangulation;
  // Here and in many following cases, the string "<2>" after a class name
  // indicates that this is an object that shall work in two space
  // dimensions. Likewise, there are versions of the triangulation class that
  // are working in one ("<1>") and three ("<3>") space dimensions. The way
  // this works is through some template magic that we will investigate in
  // some more detail in later example programs; there, we will also see how
  // to write programs in an essentially dimension independent way.

  // Next, we want to fill the triangulation with a single cell for a square
  // domain. The triangulation is the refined four times, to yield 4^4=256
  // cells in total:
  GridGenerator::hyper_cube (triangulation);
  triangulation.refine_global (4);

  // Now we want to write a graphical representation of the mesh to an output
  // file. The GridOut class of deal.II can do that in a number of different
  // output formats; here, we choose encapsulated postscript (eps) format:
  std::ofstream out ("grid-1.eps");
  GridOut grid_out;
  grid_out.write_eps (triangulation, out);
}

// @sect3{Creating the second mesh}

// The grid in the following, second function is slightly more complicated in
// that we use a ring domain and refine the result once globally.
void second_grid ()
{
  // We start again by defining an object for a triangulation of a
  // two-dimensional domain:
  Triangulation<2> triangulation;

  // We then fill it with a ring domain. The center of the ring shall be the
  // point (1,0), and inner and outer radius shall be 0.5 and 1. The number of
  // circumferential cells could be adjusted automatically by this function,
  // but we choose to set it explicitely to 10 as the last argument:
  const Point<2> center (1,0);
  const double inner_radius = 0.5,
               outer_radius = 1.0;
  GridGenerator::hyper_shell (triangulation,
                              center, inner_radius, outer_radius,
                              10);
  // By default, the triangulation assumes that all boundaries are straight
  // and given by the cells of the coarse grid (which we just created). It
  // uses this information when cells at the boundary are refined and new
  // points need to be introduced on the boundary; if the boundary is assumed
  // to be straight, then new points will simply be in the middle of the
  // surrounding ones.
  //
  // Here, however, we would like to have a curved boundary. Fortunately, some
  // good soul implemented an object which describes the boundary of a ring
  // domain; it only needs the center of the ring and automatically figures
  // out the inner and outer radius when needed. Note that we associate this
  // boundary object with that part of the boundary that has the "boundary
  // indicator" zero. By default (at least in 2d and 3d, the 1d case is
  // slightly different), all boundary parts have this number, but you can
  // change this number for some parts of the boundary. In that case, the
  // curved boundary thus associated with number zero will not apply on those
  // parts with a non-zero boundary indicator, but other boundary description
  // objects can be associated with those non-zero indicators. If no boundary
  // description is associated with a particular boundary indicator, a
  // straight boundary is implied.
  const HyperShellBoundary<2> boundary_description(center);
  triangulation.set_boundary (0, boundary_description);

  // In order to demonstrate how to write a loop over all cells, we will
  // refine the grid in five steps towards the inner circle of the domain:
  for (unsigned int step=0; step<5; ++step)
    {
      // Next, we need an iterator which points to a cell and which we will
      // move over all active cells one by one (active cells are those that
      // are not further refined, and the only ones that can be marked for
      // further refinement, obviously). By convention, we almost always use
      // the names cell and endc for the iterator
      // pointing to the present cell and to the one-past-the-end
      // iterator:
      Triangulation<2>::active_cell_iterator
      cell = triangulation.begin_active(),
      endc = triangulation.end();

      // The loop over all cells is then rather trivial, and looks like any
      // loop involving pointers instead of iterators:
      for (; cell!=endc; ++cell)
        // Next, we want to loop over all vertices of the cells. Since we are
        // in 2d, we know that each cell has exactly four vertices. However,
        // instead of penning down a 4 in the loop bound, we make a first
        // attempt at writing it in a dimension-independent way by which we
        // find out about the number of vertices of a cell. Using the
        // GeometryInfo class, we will later have an easier time getting the
        // program to also run in 3d: we only have to change all occurrences
        // of <2> to <3>, and do not
        // have to audit our code for the hidden appearance of magic numbers
        // like a 4 that needs to be replaced by an 8:
        for (unsigned int v=0;
             v < GeometryInfo<2>::vertices_per_cell;
             ++v)
          {
            // If this cell is at the inner boundary, then at least one of its
            // vertices must sit on the inner ring and therefore have a radial
            // distance from the center of exactly 0.5, up to floating point
            // accuracy. Compute this distance, and if we have found a vertex
            // with this property flag this cell for later refinement. We can
            // then also break the loop over all vertices and move on to the
            // next cell.
            const double distance_from_center
              = center.distance (cell->vertex(v));

            if (std::fabs(distance_from_center - inner_radius) < 1e-10)
              {
                cell->set_refine_flag ();
                break;
              }
          }

      // Now that we have marked all the cells that we want refined, we let
      // the triangulation actually do this refinement. The function that does
      // so owes its long name to the fact that one can also mark cells for
      // coarsening, and the function does coarsening and refinement all at
      // once:
      triangulation.execute_coarsening_and_refinement ();
    }

  // Finally, after these five iterations of refinement, we want to again
  // write the resulting mesh to a file, again in eps format. This works just
  // as above:
  std::ofstream out ("grid-2.eps");
  GridOut grid_out;
  grid_out.write_eps (triangulation, out);

  // At this point, all objects created in this function will be destroyed in
  // reverse order. Unfortunately, we defined the boundary object after the
  // triangulation, which still has a pointer to it and the library will
  // produce an error if the boundary object is destroyed before the
  // triangulation. We therefore have to release it, which can be done as
  // follows. Note that this sets the boundary object used for part "0" of the
  // boundary back to a default object, over which the triangulation has full
  // control.
  triangulation.set_boundary (0);
  // An alternative to doing so, and one that is frequently more convenient,
  // would have been to declare the boundary object before the triangulation
  // object. In that case, the triangulation would have let lose of the
  // boundary object upon its destruction, and everything would have been
  // fine.
}

// @sect3{The main function}

// Finally, the main function. There isn't much to do here, only to call the
// two subfunctions, which produce the two grids.
int main ()
{
  first_grid ();
  second_grid ();
}


#include <boost/numeric/ublas/assignment.hpp>
#include <boost/numeric/ublas/banded.hpp>
#include <boost/numeric/ublas/blas.hpp>
#include <boost/numeric/ublas/doxydoc.hpp>
#include <boost/numeric/ublas/exception.hpp>
#include <boost/numeric/ublas/expression_types.hpp>
#include <boost/numeric/ublas/functional.hpp>
#include <boost/numeric/ublas/fwd.hpp>
#include <boost/numeric/ublas/hermitian.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/matrix_expression.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <boost/numeric/ublas/matrix_vector.hpp>
#include <boost/numeric/ublas/operation_blocked.hpp>
#include <boost/numeric/ublas/operation.hpp>
#include <boost/numeric/ublas/operations.hpp>
#include <boost/numeric/ublas/operation_sparse.hpp>
#include <boost/numeric/ublas/storage.hpp>
#include <boost/numeric/ublas/storage_sparse.hpp>
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/numeric/ublas/tags.hpp>
#include <boost/numeric/ublas/tensor.hpp>
#include <boost/numeric/ublas/traits.hpp>
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/vector_expression.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_of_vector.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <boost/numeric/ublas/vector_sparse.hpp>

int
main ()
{
  return 0;
}


#ifndef VIENNACL_TRAITS_SIZE_HPP_
#define VIENNACL_TRAITS_SIZE_HPP_

/* =========================================================================
   Copyright (c) 2010-2013, Institute for Microelectronics,
                            Institute for Analysis and Scientific Computing,
                            TU Wien.
   Portions of this software are copyright by UChicago Argonne, LLC.

                            -----------------
                  ViennaCL - The Vienna Computing Library
                            -----------------

   Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at

   (A list of authors and contributors can be found in the PDF manual)

   License:         MIT (X11), see file LICENSE in the base directory
============================================================================= */

/** @file viennacl/traits/size.hpp
    @brief Generic size and resize functionality for different vector and matrix types
*/

#include <string>
#include <fstream>
#include <sstream>
#include "viennacl/forwards.h"
#include "viennacl/meta/result_of.hpp"
#include "viennacl/meta/predicate.hpp"

#ifdef VIENNACL_WITH_UBLAS
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#endif

#ifdef VIENNACL_WITH_EIGEN
#include <Eigen/Core>
#include <Eigen/Sparse>
#endif

#ifdef VIENNACL_WITH_MTL4
#include <boost/numeric/mtl/mtl.hpp>
#endif

#include <vector>
#include <map>

namespace viennacl
{

  namespace traits
  {
    //
    // Resize: Change the size of vectors and matrices
    //
    /** @brief Generic resize routine for resizing a matrix (ViennaCL, uBLAS, etc.) to a new size/dimension */
    template <typename MatrixType>
    void resize(MatrixType & matrix, std::size_t rows, std::size_t cols)
    {
      matrix.resize(rows, cols);
    }

    /** @brief Generic resize routine for resizing a vector (ViennaCL, uBLAS, etc.) to a new size */
    template <typename VectorType>
    void resize(VectorType & vec, std::size_t new_size)
    {
      vec.resize(new_size);
    }

    /** \cond */
    #ifdef VIENNACL_WITH_UBLAS
    //ublas needs separate treatment:
    template <typename ScalarType>
    void resize(boost::numeric::ublas::compressed_matrix<ScalarType> & matrix,
                std::size_t rows,
                std::size_t cols)
    {
      matrix.resize(rows, cols, false); //Note: omitting third parameter leads to compile time error (not implemented in ublas <= 1.42)
    }
    #endif

    #ifdef VIENNACL_WITH_MTL4
    template <typename ScalarType>
    void resize(mtl::compressed2D<ScalarType> & matrix,
                std::size_t rows,
                std::size_t cols)
    {
      matrix.change_dim(rows, cols);
    }

    template <typename ScalarType>
    void resize(mtl::dense_vector<ScalarType> & vec,
                std::size_t new_size)
    {
      vec.change_dim(new_size);
    }
    #endif

    #ifdef VIENNACL_WITH_EIGEN
    inline void resize(Eigen::MatrixXf & m,
                       std::size_t new_rows,
                       std::size_t new_cols)
    {
      m.resize(new_rows, new_cols);
    }

    inline void resize(Eigen::MatrixXd & m,
                       std::size_t new_rows,
                       std::size_t new_cols)
    {
      m.resize(new_rows, new_cols);
    }

    template <typename T, int options>
    inline void resize(Eigen::SparseMatrix<T, options> & m,
                       std::size_t new_rows,
                       std::size_t new_cols)
    {
      m.resize(new_rows, new_cols);
    }

    inline void resize(Eigen::VectorXf & v,
                       std::size_t new_size)
    {
      v.resize(new_size);
    }

    inline void resize(Eigen::VectorXd & v,
                       std::size_t new_size)
    {
      v.resize(new_size);
    }
    #endif
    /** \endcond */

    //
    // size: Returns the length of vectors
    //
    /** @brief Generic routine for obtaining the size of a vector (ViennaCL, uBLAS, etc.) */
    template <typename VectorType>
    vcl_size_t size(VectorType const & vec)
    {
      return vec.size();
    }

    /** \cond */
    template <typename LHS, typename RHS, typename OP>
    vcl_size_t size(vector_expression<LHS, RHS, OP> const & proxy)
    {
      return size(proxy.lhs());
    }

    template <typename SparseMatrixType, typename VectorType>
    typename viennacl::enable_if< viennacl::is_any_sparse_matrix<SparseMatrixType>::value,
                                  vcl_size_t >::type
    size(vector_expression<const SparseMatrixType, const VectorType, op_prod> const & proxy)
    {
      return proxy.lhs().size1();
    }

    template <typename NumericT, typename F>
    vcl_size_t size(vector_expression<const matrix_base<NumericT, F>, const vector_base<NumericT>, op_prod> const & proxy)  //matrix-vector product
    {
      return proxy.lhs().size1();
    }

    template <typename NumericT, typename F>
    vcl_size_t size(vector_expression<const matrix_expression<const matrix_base<NumericT, F>, const matrix_base<NumericT, F>, op_trans>,
                                      const vector_base<NumericT>,
                                      op_prod> const & proxy)  //transposed matrix-vector product
    {
      return proxy.lhs().lhs().size2();
    }

    #ifdef VIENNACL_WITH_MTL4
    template <typename ScalarType>
    vcl_size_t size(mtl::dense_vector<ScalarType> const & vec) { return vec.used_memory(); }
    #endif

    #ifdef VIENNACL_WITH_EIGEN
    inline vcl_size_t size(Eigen::VectorXf const & v) { return v.rows(); }
    inline vcl_size_t size(Eigen::VectorXd const & v) { return v.rows(); }
    #endif
    /** \endcond */

    //
    // size1: No. of rows for matrices
    //
    /** @brief Generic routine for obtaining the number of rows of a matrix (ViennaCL, uBLAS, etc.) */
    template <typename MatrixType>
    vcl_size_t
    size1(MatrixType const & mat) { return mat.size1(); }

    /** \cond */
    template <typename RowType>
    vcl_size_t
    size1(std::vector< RowType > const & mat) { return mat.size(); }

    #ifdef VIENNACL_WITH_EIGEN
    inline vcl_size_t size1(Eigen::MatrixXf const & m) { return m.rows(); }
    inline vcl_size_t size1(Eigen::MatrixXd const & m) { return m.rows(); }
    template <typename T, int options>
    inline vcl_size_t size1(Eigen::SparseMatrix<T, options> & m) { return m.rows(); }
    #endif
    /** \endcond */

    //
    // size2: No. of columns for matrices
    //
    /** @brief Generic routine for obtaining the number of columns of a matrix (ViennaCL, uBLAS, etc.) */
    template <typename MatrixType>
    typename result_of::size_type<MatrixType>::type
    size2(MatrixType const & mat) { return mat.size2(); }

    /** \cond */
    #ifdef VIENNACL_WITH_EIGEN
    inline vcl_size_t size2(Eigen::MatrixXf const & m) { return m.cols(); }
    inline vcl_size_t size2(Eigen::MatrixXd const & m) { return m.cols(); }
    template <typename T, int options>
    inline vcl_size_t size2(Eigen::SparseMatrix<T, options> & m) { return m.cols(); }
    #endif
    /** \endcond */

    //
    // internal_size: Returns the internal (padded) length of vectors
    //
    /** @brief Helper routine for obtaining the buffer length of a ViennaCL vector  */
    template <typename NumericT>
    vcl_size_t internal_size(vector_base<NumericT> const & vec)
    {
      return vec.internal_size();
    }

    //
    // internal_size1: No. of internal (padded) rows for matrices
    //
    /** @brief Helper routine for obtaining the internal number of entries per row of a ViennaCL matrix  */
    template <typename NumericT, typename F>
    vcl_size_t internal_size1(matrix_base<NumericT, F> const & mat) { return mat.internal_size1(); }

    //
    // internal_size2: No. of internal (padded) columns for matrices
    //
    /** @brief Helper routine for obtaining the internal number of entries per column of a ViennaCL matrix  */
    template <typename NumericT, typename F>
    vcl_size_t internal_size2(matrix_base<NumericT, F> const & mat) { return mat.internal_size2(); }

  } //namespace traits
} //namespace viennacl

#endif


//------------------------------------------------------------------------------
/// \file PointersArraysReferences_tests.cpp
/// \ref Bjarne Stroustrup. The C++ Programming Language, 4th Edition.
/// Addison-Wesley Professional. May 19, 2013. ISBN-13: 978-0321563842
//------------------------------------------------------------------------------
#include <boost/test/unit_test.hpp>
#include <cstring>
#include <iostream>
#include <string>

BOOST_AUTO_TEST_SUITE(Cpp)
BOOST_AUTO_TEST_SUITE(PointersArraysReferences)
BOOST_AUTO_TEST_SUITE(PointersArraysReferences_tests)

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(PointerDeclarations)
{
  // cf. Stroustrup (2013). 6.3.1, pp. 153. Definition of an array of C-style
  // strings.

  // Postfix declarator, e.g. [], bind tighter than prefix ones, e.g. *
  // array of pointers to char
  const char* kings[] = {"Antigonus", "Seleucus", "Ptolemy"};

  BOOST_TEST(kings[0] == "Antigonus");
  BOOST_TEST(kings[1] == "Seleucus");
  BOOST_TEST(kings[2] == "Ptolemy");

  // Pointer to an array of `char`
  char(*one_king)[5];

  char a_king[] = {'L', 'o', 'u', 'i', 's'};

  one_king = &a_king;

  BOOST_TEST((*one_king)[0] == 'L');
  BOOST_TEST((*one_king)[1] == 'o');
  BOOST_TEST((*one_king)[2] == 'u');
  BOOST_TEST((*one_king)[3] == 'i');
  BOOST_TEST((*one_king)[4] == 's');

  int* pi; // pointer to int
  char** ppc; // pointer to pointer to char
  int* ap[15]; // array of 15 pointers to ints
  int (*fp)(char*); // pointer to function taking a char* argument; returns an
  // int
  int* f(char*); // function taking a char* argument; returns a pointer to int

  BOOST_TEST(true);
}

void void_pointer_points(int* pi)
{
  void* pv = pi; // OK: implicit conversion of int* to void*
  // *pv; // error: can't deference void*
  // ++pv; // error: can't increment void* (the size of the object pointed to is
  // unknown)

  int* pi2 = static_cast<int*>(pv); // explicit conversion back to int*

  // double* pd1 = pv; // error
  // double* pd2 = pi; // error
  // double* pd3 = static_cast<double*>(pv); // unsafe (Sec. 11.5.2)
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(VoidPointerExplicitlyConvertsToAnotherPointer)
{
  {
    const int pi_value {42};
    const int* pi = &pi_value;
    BOOST_TEST(true);
  }
  int pi_value {42};
  int* pi = &pi_value;

  void_pointer_points(pi);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(NullptrAssignedToAnyPointerType)
{
  int* pi = nullptr;
  int* pi2 {nullptr};
  double* pd = nullptr;
  //int i = nullptr; // error: i is not a pointer.
  BOOST_TEST(true);
}

// cf. 7.3 Arrays, pp. 174, Stroustrup (2013)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(DeclareAndAssignToArrays)
{
  float v[3]; // array of 3 floats
  char* a[32]; // array of 32 pointers to char

  int aa[10];
  aa[6] = 9; // assign to aa's 7th element

  BOOST_TEST(true);
}

// cf. 7.3.1 Array Initializers, pp. 175, Stroustrup (2013)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ArraysCanBeInitialized)
{
  int v1[] = {1, 2, 3, 4};
  char v2[] = {'a', 'b', 'c', 0};

  // char v3[2]= {'a', 'b', 0}; // error: too many initializers
  char v4[3] = {'a', 'b', 0};

  // If initializer supplies too few elements for an array, 0 used for the rest
  int v5[8] = {1, 2, 3, 4};
  BOOST_TEST(v5[0] == 1);
  BOOST_TEST(v5[1] == 2);
  BOOST_TEST(v5[2] == 3);
  BOOST_TEST(v5[3] == 4);
  BOOST_TEST(v5[4] == 0);
  BOOST_TEST(v5[5] == 0);
  BOOST_TEST(v5[6] == 0);
  BOOST_TEST(v5[7] == 0);
}

const char* error_message_returning_str_literal(int i)
{
  i + 1;
  return "range error";
}
// cf. 7.3.2 String Literals, pp. 176, Stroustrup (2013)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(StringLiteralsInitializeArrays)
{
  "this is a string";

  // A string literal contains 1 more character than it appears to have; it's
  // terminated by null character, '\0', with value 0

  BOOST_TEST(sizeof("Bohr") == 5);

  // char* p ="Plato"; // error, C++ forbids converting string constant to char*

  // If we want a string we are guranteed to be able to modify, we must place
  // characters in a non-const array

  char p[] = "Zeno"; // p is an array of 5 char
  BOOST_TEST(sizeof(p) == 5);
  p[0] = 'R'; // OK
  BOOST_TEST(std::string {p} == "Reno");

  BOOST_TEST(std::string{error_message_returning_str_literal(5)} ==
    "range error");

  // Long strings can be broken by whitespace to make the program text neater.
  char alpha[] = "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  BOOST_TEST(std::string{alpha} ==
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
}

// cf. 7.3.2.1 Raw Character Strings, pp. 177, Stroustrup (2013)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(RawCharacterStrings)
{
  std::string s {R"(\w\\w)"};

  BOOST_TEST(s == R"(\w\\w)");

  // "( and )" is the only default delimiter pair.

  s = R"***("quoted string containing the usual terminator ("))")***";
  BOOST_TEST(s == "\"quoted string containing the usual terminator (\"))\"");

  std::string counts {R"(1
22
333)"};

  std::string x {"1\n22\n333"};

  BOOST_TEST(counts == x);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ImplicitConversionFromArrayToPointer)
{
  int v[] = {1, 2, 3, 4};
  int* p1 = v; // pointer to initial element (implicit conversion)
  int* p2 = &v[0]; // pointer to initial element
  int* p3 = v + 4; // pointer to one beyond-last element

  BOOST_TEST(*p1 == 1);
  BOOST_TEST(*p2 == 1);

  {
    char v[] = "Annemarie";
    char* p = v; // implicit conversion of char[] to char*
    BOOST_TEST(strlen(p) == 9);
    BOOST_TEST(strlen(v) == 9); // implicit conversion of char[] to char*
  }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(NavigateArraysByPointerArithmetic)
{
  char v[] {"123456789"};
  BOOST_TEST_REQUIRE(sizeof(v) == 10);
  for (int i {0}; v[i] != 0; ++i)
  {
    BOOST_TEST(v[i] == static_cast<char>(i + '1'));
  }

  char p[] {"abcdefghijklmnopqrstuvwxyz"};
  BOOST_TEST_REQUIRE(sizeof(p) == 27);
  int i {0};
  for (char* ptr = p; *ptr != 0; ++ptr)
  {
    BOOST_TEST(*ptr == static_cast<char>('a' + i));
    ++i;
  }

  // The prefix * operator dereferences a pointer so that *p is the character
  // pointed to by p, and ++ increments the pointer so that it refers to the
  // next element of the array.

  const char a[] {"ABCDEFGH"} ;

  constexpr int j {2};

  BOOST_TEST(a[j] == *(&a[0] + j));
  BOOST_TEST(*(&a[0] + j) == *(a+j));
  BOOST_TEST(*(a+j) == *(j + a));
  BOOST_TEST(*(j + a) == j[a]);
  BOOST_TEST(3["Texas"] == "Texas"[3]);
  BOOST_TEST("Texas"[3] == 'a');
}

// Remember, reinterpret_cast is resolved at compile-time; it's nothing more
// than "look to a pointer that's pointing to type A with eyes of who is
// looking for type B".
// https://stackoverflow.com/questions/27309604/do-constant-and-reinterpret-cast-happen-at-compile-time/27309763
template <typename T>
int byte_diff(T* p, T* q)
{
  return reinterpret_cast<char*>(q) - reinterpret_cast<char*>(p);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ApplySubtractionForPointerArithmetic)
{
  std::cout << "\n ApplySubtractionForPointerArithmetic \n";

  int vi[10];
  short vs[10];

  // Pointer values printed using default hexadecimal notation.
  // e.g.
  // 0x7ffe36969950 0x7ffe36969954
  // 0x7ffe36969930 0x7ffe36969932
  std::cout << vi << ' ' << &vi[1] << '\n';
  std::cout << vs << ' ' << &vs[1] << '\n';

  // Result is number of array elements in the sequence [p:q) (an integer).
  BOOST_TEST((&vi[1] - vi) == 1);
  BOOST_TEST((&vs[1] - vs) == 1);
  BOOST_TEST((&vi[1] - &vi[0]) == 1);
  BOOST_TEST((&vs[1] - &vs[0]) == 1);

  BOOST_TEST(byte_diff(&vi[0], &vi[1]) == 4);
  BOOST_TEST(byte_diff(&vs[0], &vs[1]) == 2);

  int v1[10];
  int v2[10];

  int i1 = &v1[5] - &v1[3];
  BOOST_TEST(i1 == 2);
  // int i2 = &v1[5] - &v2[3]; // result undefined

  int* p1 = v2 + 2; // p1 - &v2[2]
  // int*p2 = v2 - 2 // *p2 undefined
}

void fp(char v[], int size)
{
  for (int i {0}; i != size; ++i)
  {
    BOOST_TEST(v[i] == i + 'a');
  }

  // for (int x : v)
  //  use(x); // error: range-for does not work for pointers

  constexpr int N {7};
  char v2[N];
  for (int i {0}; i != N; ++i)
  {
    v2[i];
  }
  for (int x : v2)
  {
    x; // range-for works for arrays of known size.
  }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ArrayTraverseRequiresExplicitlyStatedSize)
{
  char v[] {"abcdefgh"};
  int size {8};
  fp(v, size);
  BOOST_TEST(true);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(DeclareMultidimensionalArrays)
{
  int ma[3][5]; // 3 arrays with 5 ints each

  BOOST_TEST(true);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(InitializeMultidimensionalArrays)
{
  int ma[3][5]; // 3 arrays with 5 ints each

  for (int i {0}; i != 3; ++i)
  {
    for (int j {0}; j != 5; ++j)
    {
      ma[i][j] = 10 * i + j;
    }
  }

  for (int k {0}; k < 15; ++k)
  {
    BOOST_TEST(
      ma[ k / 5][ k - 5 * (k / 5)] == 10 * (k / 5) + (k - 5 * (k / 5)));
  }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(MultidimensionalArraysAreRowMajor)
{
  int ma[3][5]; // 3 arrays with 5 ints each

  // Initialize array.
  for (int i {0}; i != 3; ++i)
  {
    for (int j {0}; j != 5; ++j)
    {
      ma[i][j] = 10 * i + j;
    }
  }

  for (int i {0}; i < 2; ++i)
  {
    // size of int (4 bytes) * 5 elements in a "row"
    BOOST_TEST(byte_diff(&ma[i], &ma[i + 1]) == 20);
  }

  for (int i {0}; i < 3; ++i)
  {
    for (int j {0}; j < 4; ++j)
    {
      BOOST_TEST(byte_diff(&ma[i][j], &ma[i][j + 1]) == 4);
    }
  }

  // Need 2nd. dimension to locate actual first element.
  int* ptr {&ma[0][0]};

  for (int k {0}; k < 15; ++k)
  {
    BOOST_TEST(*(ptr + k) == 10 * (k / 5) + (k - 5 * (k / 5)));
  }
}

// cf. 7.4.3 Passing Arrays, pp. 184, Stroustrup (2013)

void comp(double arg[10]) // arg is a double*
{
  for (int i {0}; i != 10; ++i)
  {
    arg[i] += 99;
  }
}

// This function is equivalent to comp.
void comp2(double* arg) // arg is a double*
{
  for (int i {0}; i != 10; ++i)
  {
    arg[i] += 99;
  }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(PassArraysAsPointerToFirstElement)
{
  double a1[10];
  double a2[5];
  double a3[100];

  comp(a1);
  // The following line comp(a2) compiles
  // comp(a2); // disaster!
  comp(a3); // uses only the first 10 elements

  for (int i {0}; i < 10; ++i)
  {
    a1[i] == 99;
    a3[i] == 99;
  }

  comp2(a1);
  comp2(a3);

  for (int i {0}; i < 10; ++i)
  {
    a1[i] == 189;
    a3[i] == 189;
  }
}

// cf. 7.4.3 Passing Arrays, pp. 184-185, Stroustrup (2013)
// If dimensions are known at compile time, passing arrays as pointer.

int expected_v[3][5] {
  {0, 1, 2, 3, 4},
  {10, 11, 12, 13, 14},
  {20, 21, 22, 23, 24}
};

void print_m35(int m[3][5])
{
  for (int i {0}; i != 3; ++i)
  {
    for (int j {0}; j != 5; ++j)
    {
      BOOST_TEST(m[i][j] == expected_v[i][j]);
    }
  }
}

void print_mi5(int m[][5], int dim1)
{
  for (int i {0}; i != dim1; ++i)
  {
    for (int j {0}; j != 5; ++j)
    {
      BOOST_TEST(m[i][j] == expected_v[i][j]);
    }
  }
}

// argument declaration m[][] is illegal because 2nd. dimension of a
// multidimensional array must be known in order to find location of an element.
//void print_mij(int m[][], int dim1, int dim2)
// To call this function, we pass a matrix as an ordinary pointer.
void print_mij(int* m, int dim1, int dim2)
{
  for (int i {0}; i != dim1; ++i)
  {
    for (int j {0}; j != dim2; ++j)
    {
      BOOST_TEST(m[i * dim2 + j] == expected_v[i][j]);
    }
  }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(PassArraysAsPointerIfDimensionsKnown)
{
  int v[3][5] {
    {0, 1, 2, 3, 4},
    {10, 11, 12, 13, 14},
    {20, 21, 22, 23, 24}
  };

  print_m35(v);
  print_mi5(v, 3);

  print_mij(&v[0][0], 3, 5);
}

// cf. Sec. 7.5, Pointers and const, Stroustrup (2013), pp. 186

void f1(char* p)
{
  char s[] = "Gorm";
  const char* pc = s; // pointer to constant

  const char* pc2 {s};
  // pc[3] = 'g'; // error: pc points to constant

  pc = p; // OK

  char* const cp = s; // constant pointer
  cp[3] = 'a'; // OK
  // cp = p; // error: cp is constant

  const char* const cpc = s; // const pointer to const
  //cpc[3] = 'a'; // error: cpc points to constant
  //cpc = p; // error: cpc is constant

}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(DeclareWithConst)
{
  const int model = 90; // mode is a const
  const int v[] = {1, 2, 3, 4}; // v[i] is a const
  //const int x; // error; no initializer

  char* p;

  f1(p);

  // error: uninitalized const
  //char* const cp; // const pointer to char
  char* const cp {p};

  char const* pc; // pointer to const char
  const char* pc2; // pointer to const char

  BOOST_TEST(true);
}

// This 1st version is used for strings where elements mustn't be modified and
// returns a pointer to const that does not allow modification.
const char* strchr(const char* p, char c); // find first occurrence of c in p

// 2nd version used for mutable strings
char* strchr(char* p, char c);

BOOST_AUTO_TEST_SUITE(References)

void f(std::vector<double>& v)
{
  double d1 = v[1]; // copy the value of the double referred to by
  // v.operator[](1) into d1
  v[2] = 7;

  v.push_back(d1); // give push_back() a reference to d1 to work with
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ReferenceUsedToSpecifyArguments)
{
  std::vector<double> v {0.0, 1.2, 1.3};
  BOOST_TEST_REQUIRE(v.size() == 3);
  f(v);
  BOOST_TEST(v[0] == 0.0);
  BOOST_TEST(v[1] == 1.2);
  BOOST_TEST(v[2] == 7);
  BOOST_TEST(v[3] == 1.2);
  BOOST_TEST(v.size() == 4);
}

BOOST_AUTO_TEST_SUITE_END() // References

BOOST_AUTO_TEST_SUITE_END() // PointersArraysReferences_tests
BOOST_AUTO_TEST_SUITE_END() // PointersArraysReferences
BOOST_AUTO_TEST_SUITE_END() // Cpp


/**
 * @file stabrk3.cc
 * @brief NPDE homework StabRK3 code
 * @author Unknown, Oliver Rietmann
 * @date 04.04.2021
 * @copyright Developed at ETH Zurich
 */

#include "stabrk3.h"

#include <Eigen/Core>
#include <vector>

#include "rkintegrator.h"

namespace StabRK3 {

/* SAM_LISTING_BEGIN_0 */
Eigen::Vector2d predPrey(Eigen::Vector2d y0, double T, unsigned int N) {
  double h = T / N;
  Eigen::Vector2d y = y0;

  //====================
  // Your code goes here
  //====================

  return y;
}
/* SAM_LISTING_END_0 */

/* SAM_LISTING_BEGIN_1 */
std::vector<Eigen::Vector2d> simulatePredPrey(
    const std::vector<unsigned int> &N_list) {
  int M = N_list.size();
  std::vector<Eigen::Vector2d> yT_list(M);

  //====================
  // Your code goes here
  //====================

  return yT_list;
}
/* SAM_LISTING_END_1 */

}  // namespace StabRK3


/* ---------------------------------------------------------------------
 *
 * Copyright (C) 2009 - 2021 by the deal.II authors
 *
 * This file is part of the deal.II library.
 *
 * The deal.II library is free software; you can use it, redistribute
 * it, and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * The full text of the license can be found in the file LICENSE.md at
 * the top level directory of deal.II.
 *
 * ---------------------------------------------------------------------
 *
 * Author: Wolfgang Bangerth, Texas A&M University, 2009, 2010
 *         Timo Heister, University of Goettingen, 2009, 2010
 */

// @sect3{Include files}

// 我们在这个程序中需要的大部分包含文件已经在以前的程序中讨论过了。特别是，以下所有的文件都应该已经是熟悉的朋友了。

#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/base/timer.h>

#include <deal.II/lac/generic_linear_algebra.h>

// 这个程序可以使用PETSc或Trilinos来满足其并行代数的需要。默认情况下，如果deal.II已经被配置为PETSc，它将使用PETSc。否则，下面几行将检查deal.II是否已被配置为Trilinos，并采用它。

// 但是在某些情况下，即使deal.II也被配置为PETSc，你还是想使用Trilinos，例如，比较这两个库的性能。要做到这一点，请在源代码中添加以下的\#define。
// @code
//  #define FORCE_USE_OF_TRILINOS
//  @endcode

// 使用这个逻辑，下面几行将导入PETSc或Trilinos包装器到命名空间`LA`（代表 "线性代数"）。在前一种情况下，我们还要定义宏 `USE_PETSC_LA`，这样我们就可以检测到我们是否在使用PETSc（参见solve()中需要用到的例子）。

namespace LA
{
#if defined(DEAL_II_WITH_PETSC) && !defined(DEAL_II_PETSC_WITH_COMPLEX) && \
  !(defined(DEAL_II_WITH_TRILINOS) && defined(FORCE_USE_OF_TRILINOS))
  using namespace dealii::LinearAlgebraPETSc;
#  define USE_PETSC_LA
#elif defined(DEAL_II_WITH_TRILINOS)
  using namespace dealii::LinearAlgebraTrilinos;
#else
#  error DEAL_II_WITH_PETSC or DEAL_II_WITH_TRILINOS required
#endif
} // namespace LA

#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/affine_constraints.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>

#include <deal.II/grid/grid_generator.h>
#include <deal.II/dofs/dof_handler.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>

// 然而，下面这些将是新的，或在新的角色中使用。让我们来看看它们。其中第一个将提供 Utilities::System 命名空间的工具，我们将用它来查询诸如与当前MPI宇宙相关的处理器数量，或者这个作业运行的处理器在这个宇宙中的编号。

#include <deal.II/base/utilities.h>

// 下一个提供了一个类，ConditionOStream，它允许我们编写代码，将东西输出到一个流中（例如在每个处理器上的 std::cout ，但在除了一个处理器以外的所有处理器上都将文本扔掉。我们可以通过简单地在每个可能产生输出的地方前面放一个 if 语句来实现同样的目的，但这并不能使代码更漂亮。此外，这个处理器是否应该向屏幕输出的条件每次都是一样的--因此，把它放在产生输出的语句中应该是很简单的。

#include <deal.II/base/conditional_ostream.h>

// 在这些预演之后，这里变得更加有趣。正如在 @ref distributed 模块中提到的，在大量处理器上解决问题的一个基本事实是，任何处理器都不可能存储所有的东西（例如，关于网格中所有单元的信息，所有的自由度，或者解向量中所有元素的值）。相反，每个处理器都会own其中的几个，如果有必要，还可能know另外几个，例如，位于与该处理器自己拥有的单元相邻的那些单元。我们通常称后者为ghost cells、ghost nodes或ghost elements of a vector。这里讨论的重点是，我们需要有一种方法来表明一个特定的处理器拥有或需要知道哪些元素。这就是IndexSet类的领域：如果总共有 $N$ 个单元、自由度或向量元素，与（非负）积分指数 $[0,N)$ 相关，那么当前处理器拥有的元素集以及它需要了解的（可能更大）指数集都是集合 $[0,N)$ 的子集。IndexSet是一个类，它以一种有效的格式存储这个集合的子集。

#include <deal.II/base/index_set.h>

// 下一个头文件是一个单一的函数所必需的，  SparsityTools::distribute_sparsity_pattern.  这个函数的作用将在下面解释。

#include <deal.II/lac/sparsity_tools.h>

// 最后两个新的头文件提供了类 parallel::distributed::Triangulation ，它提供了分布在可能非常多的处理器上的网格，而第二个文件提供了命名空间 parallel::distributed::GridRefinement ，它提供了可以自适应细化这种分布式网格的函数。

#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}

// 接下来我们来声明这个程序的主类。它的结构几乎与 step-6 的教程程序一模一样。唯一显著的区别是。

// --  mpi_communicator 变量，它描述了我们希望这段代码运行在哪一组处理器上。在实践中，这将是MPI_COMM_WORLD，即批处理调度系统分配给这个特定作业的所有处理器。

// - ConditionOStream类型的 pcout 变量的存在。

// - 明显使用 parallel::distributed::Triangulation 而不是Triangulation。

// - 两个IndexSet对象的存在，表示我们在当前处理器上拥有哪些自由度集（以及解和右手向量的相关元素），以及我们需要哪些（作为幽灵元素）来使本程序中的算法工作。

// - 现在所有的矩阵和向量都是分布式的。我们使用PETSc或Trilinos包装类，这样我们就可以使用Hypre（使用PETSc）或ML（使用Trilinos）提供的复杂的预处理器之一。请注意，作为这个类的一部分，我们存储的解向量不仅包含当前处理器拥有的自由度，还包括（作为鬼魂元素）所有对应于 "本地相关 "自由度的向量元素（即所有生活在本地拥有的单元或围绕它的鬼魂单元层的自由度）。

  template <int dim>
  class LaplaceProblem
  {
  public:
    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;

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

    IndexSet locally_owned_dofs;
    IndexSet locally_relevant_dofs;

    AffineConstraints<double> constraints;

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

    ConditionalOStream pcout;
    TimerOutput        computing_timer;
  };
// @sect3{The LaplaceProblem class implementation}
// @sect4{Constructor}

// 构造函数和析构函数是相当微不足道的。除了我们在 step-6 中所做的，我们将我们想要工作的处理器集合设置为所有可用的机器（MPI_COMM_WORLD）；要求三角化以确保网格保持平滑并自由精炼岛屿，例如；并初始化 pcout 变量，只允许处理器0输出任何东西。最后一块是初始化一个定时器，我们用它来决定程序的不同部分需要多少计算时间。

  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))
    , fe(2)
    , dof_handler(triangulation)
    , pcout(std::cout,
            (Utilities::MPI::this_mpi_process(mpi_communicator) == 0))
    , computing_timer(mpi_communicator,
                      pcout,
                      TimerOutput::summary,
                      TimerOutput::wall_times)
  {}

//  @sect4{LaplaceProblem::setup_system}

// 下面这个函数可以说是整个程序中最有趣的一个，因为它涉及到了%并行  step-40  和顺序  step-6  的核心区别。

// 在顶部我们做了我们一直在做的事情：告诉DoFHandler对象来分配自由度。由于我们在这里使用的三角测量是分布式的，DoFHandler对象足够聪明，它认识到在每个处理器上只能在它所拥有的单元上分配自由度；接下来是一个交换步骤，处理器互相告诉对方关于ghost单元的自由度。结果是DoFHandler知道本地拥有的单元和幽灵单元（即与本地拥有的单元相邻的单元）的自由度，但对更远的单元则一无所知，这与分布式计算的基本理念一致，即没有处理器可以知道所有的事情。

  template <int dim>
  void LaplaceProblem<dim>::setup_system()
  {
    TimerOutput::Scope t(computing_timer, "setup");

    dof_handler.distribute_dofs(fe);

// 接下来的两行提取了一些我们以后需要的信息，即两个索引集，提供了关于哪些自由度为当前处理器所拥有的信息（这些信息将被用来初始化解和右手向量以及系统矩阵，表明哪些元素要存储在当前处理器上，哪些要期望存储在其他地方）；以及一个索引集，表明哪些自由度是本地相关的（即生活在当前处理器所拥有的单元上或本地所拥有的单元周围的鬼魂单元上；我们将把这些自由度存储在当前处理器上。 例如，生活在当前处理器拥有的单元上或本地拥有的单元周围的幽灵单元层上；例如，我们需要所有这些自由度来估计本地单元的误差）。)

    locally_owned_dofs = dof_handler.locally_owned_dofs();
    DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);

// 接下来，让我们初始化解和右手边的向量。如上所述，我们寻求的解向量不仅存储了我们自己的元素，还存储了幽灵条目；另一方面，右手向量只需要有当前处理器拥有的条目，因为我们所做的只是向其中写入，而不是从其中读取本地拥有的单元（当然，线性求解器会从其中读取，但它们并不关心自由度的几何位置）。

    locally_relevant_solution.reinit(locally_owned_dofs,
                                     locally_relevant_dofs,
                                     mpi_communicator);
    system_rhs.reinit(locally_owned_dofs, mpi_communicator);

// 下一步是计算悬挂节点和边界值约束，我们将其合并为一个存储所有约束的对象。

// 就像在%parallel中的所有其他事情一样，口头禅必须是：没有一个处理器可以存储整个宇宙的所有信息。因此，我们需要告诉AffineConstraints对象哪些自由度可以存储约束条件，哪些可以不期望存储任何信息。在我们的例子中，正如 @ref distributed 模块所解释的，我们需要在每个处理器上关心的自由度是本地相关的自由度，所以我们把这个传递给 AffineConstraints::reinit 函数。顺便提一下，如果你忘记传递这个参数，AffineConstraints类将分配一个长度等于它目前看到的最大自由度索引的数组。对于MPI进程数很高的处理器来说，这可能是非常大的 -- 也许是数十亿的数量级。然后，程序将为这个单一的数组分配比其他所有操作加起来还要多的内存。

    constraints.clear();
    constraints.reinit(locally_relevant_dofs);
    DoFTools::make_hanging_node_constraints(dof_handler, constraints);
    VectorTools::interpolate_boundary_values(dof_handler,
                                             0,
                                             Functions::ZeroFunction<dim>(),
                                             constraints);
    constraints.close();

// 这个函数的最后一部分涉及到用伴随的稀疏模式初始化矩阵。和以前的教程程序一样，我们使用DynamicSparsityPattern作为一个中介，然后用它来初始化系统矩阵。为了做到这一点，我们必须告诉稀疏模式它的大小，但如上所述，所产生的对象不可能为每个全局自由度存储哪怕一个指针；我们最好的希望是它能存储每个局部相关自由度的信息，即所有我们在组装矩阵的过程中可能接触到的自由度（ @ref distributed_paper "分布式计算论文 "有很长的讨论，为什么我们真的需要局部相关自由度，而不是在此背景下的小的局部活动自由度集）。

// 所以我们告诉稀疏模式它的大小和要存储什么自由度，然后要求 DoFTools::make_sparsity_pattern 来填充它（这个函数忽略了所有不属于本地的单元，模仿我们下面在装配过程中的做法）。在这之后，我们调用一个函数，在处理器之间交换这些稀疏模式的条目，以便最后每个处理器真正知道它将拥有的那部分有限元矩阵中的所有条目。最后一步是用稀疏模式初始化矩阵。

    DynamicSparsityPattern dsp(locally_relevant_dofs);

    DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints, false);
    SparsityTools::distribute_sparsity_pattern(dsp,
                                               dof_handler.locally_owned_dofs(),
                                               mpi_communicator,
                                               locally_relevant_dofs);

    system_matrix.reinit(locally_owned_dofs,
                         locally_owned_dofs,
                         dsp,
                         mpi_communicator);
  }

//  @sect4{LaplaceProblem::assemble_system}

// 然后组装线性系统的函数相对来说比较无聊，几乎和我们之前看到的一模一样。需要注意的地方是。

// - 装配必须只在本地拥有的单元上循环。有多种方法来测试；例如，我们可以将一个单元的subdomain_id与三角形的信息进行比较，如cell->subdomain_id() == triangulation.local_owned_subdomain()，或者跳过所有条件cell->is_ghost() || cell->is_artificial()为真的单元。然而，最简单的方法是简单地询问单元格是否为本地处理器所拥有。

// - 将本地贡献复制到全局矩阵中必须包括分配约束和边界值。换句话说，我们不能（就像我们在 step-6 中所做的那样）首先将每个本地贡献复制到全局矩阵中，然后在后面的步骤中才处理悬挂节点的约束和边界值。原因是，正如在 step-17 中所讨论的那样，一旦矩阵中的任意元素被组装到矩阵中，并行矢量类就不能提供对这些元素的访问--部分原因是它们可能不再存在于当前的处理器中，而是被运到了不同的机器上。

// - 我们计算右手边的方式（考虑到介绍中的公式）可能不是最优雅的，但对于重点在某个完全不同的地方的程序来说是可以的。

  template <int dim>
  void LaplaceProblem<dim>::assemble_system()
  {
    TimerOutput::Scope t(computing_timer, "assembly");

    const QGauss<dim> quadrature_formula(fe.degree + 1);

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

    const unsigned int dofs_per_cell = fe.n_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<types::global_dof_index> local_dof_indices(dofs_per_cell);

    for (const auto &cell : dof_handler.active_cell_iterators())
      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);
        }

// 注意，上面的装配只是一个局部操作。因此，为了形成 "全局 "线性系统，需要在所有处理器之间进行同步。这可以通过调用函数compress()来实现。参见 @ref GlossCompress "压缩分布式对象"，以了解更多关于compress()的设计目的的信息。

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

//  @sect4{LaplaceProblem::solve}

// 尽管在可能是数以万计的处理器上求解线性系统到目前为止并不是一项微不足道的工作，但完成这项工作的函数--至少在外表上--相对简单。大部分的部分你都见过了。真正值得一提的只有两件事。

// - 解算器和预处理器是建立在PETSc和Trilinos功能的deal.II包装上的。众所周知，大规模并行线性求解器的主要瓶颈实际上不是处理器之间的通信，而是很难产生能够很好地扩展到大量处理器的预处理程序。在21世纪前十年的后半段，代数多网格（AMG）方法在这种情况下显然是非常有效的，我们将使用其中的一种方法--要么是可以通过PETSc接口的Hypre软件包的BoomerAMG实现，要么是由ML提供的预处理程序，它是Trilinos的一部分--用于当前的程序。解算器本身的其余部分是模板，之前已经展示过了。由于线性系统是对称和正定的，我们可以使用CG方法作为外解器。

// - 最终，我们想要一个向量，它不仅存储了当前处理器拥有的自由度的解的元素，而且还存储了所有其他本地相关的自由度。另一方面，求解器本身需要一个在处理器之间唯一分割的向量，没有任何重叠。因此，我们在这个函数的开头创建一个具有这些特性的向量，用它来求解线性系统，并在最后才把它分配给我们想要的向量。这最后一步确保所有的鬼魂元素也在必要时被复制。

  template <int dim>
  void LaplaceProblem<dim>::solve()
  {
    TimerOutput::Scope t(computing_timer, "solve");
    LA::MPI::Vector    completely_distributed_solution(locally_owned_dofs,
                                                    mpi_communicator);

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

#ifdef USE_PETSC_LA
    LA::SolverCG solver(solver_control, mpi_communicator);
#else
    LA::SolverCG solver(solver_control);
#endif

    LA::MPI::PreconditionAMG preconditioner;

    LA::MPI::PreconditionAMG::AdditionalData data;

#ifdef USE_PETSC_LA
    data.symmetric_operator = true;
#else
/* Trilinos的默认值是好的  */
#endif
    preconditioner.initialize(system_matrix, data);

    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}

// 估计误差和细化网格的函数又与  step-6  中的函数几乎完全一样。唯一不同的是，标志着要细化的单元格的函数现在在命名空间  parallel::distributed::GridRefinement  中 -- 这个命名空间的函数可以在所有参与的处理器之间进行通信，并确定全局阈值，用于决定哪些单元格要细化，哪些要粗化。

// 注意，我们不需要对KellyErrorEstimator类做任何特殊处理：我们只是给它一个向量，其元素数量与本地三角形的单元（本地拥有的单元、幽灵单元和人工单元）一样多，但它只填入那些对应于本地拥有的单元的条目。

  template <int dim>
  void LaplaceProblem<dim>::refine_grid()
  {
    TimerOutput::Scope t(computing_timer, "refine");

    Vector<float> estimated_error_per_cell(triangulation.n_active_cells());
    KellyErrorEstimator<dim>::estimate(
      dof_handler,
      QGauss<dim - 1>(fe.degree + 1),
      std::map<types::boundary_id, const Function<dim> *>(),
      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}

// 与 step-6 中的相应函数相比，这里的函数要复杂一点。有两个原因：第一个原因是，我们不只是想输出解决方案，还想输出每个单元的处理器（即它在哪个 "子域"）。其次，正如在 step-17 和 step-18 中详细讨论的那样，生成图形数据可能是并行化的一个瓶颈。在 step-18 中，我们将这一步骤从实际计算中移出，而是将其转移到一个单独的程序中，随后将各个处理器的输出合并到一个文件中。但这并不具规模：如果处理器的数量很大，这可能意味着在单个处理器上合并数据的步骤后来成为程序中运行时间最长的部分，或者它可能产生一个大到无法再可视化的文件。我们在这里遵循一个更合理的方法，即为每个MPI进程创建单独的文件，并将其留给可视化程序来理解。

// 首先，函数的顶部看起来和平时一样。除了附加解决方案向量（包含所有本地相关元素的条目，而不仅仅是本地拥有的元素）外，我们还附加一个数据向量，为每个单元存储该单元所属的子域。这稍微有点棘手，因为当然不是每个处理器都知道每个单元。因此，我们附加的向量有一个当前处理器在其网格中拥有的每个单元的条目（本地拥有的单元、幽灵单元和人造单元），但DataOut类将忽略所有对应于不属于当前处理器的单元的条目。因此，我们在这些向量条目中写入什么值实际上并不重要：我们只需用当前MPI进程的编号（即当前进程的子域_id）来填充整个向量；这就正确地设置了我们关心的值，即对应于本地拥有的单元的条目，而为所有其他元素提供了错误的值--但无论如何这些都会被忽略。

  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();

// 下一步是把这些数据写到磁盘上。在MPI-IO的帮助下，我们最多可以并行写入8个VTU文件。此外，还产生了一个PVTU记录，它将写入的VTU文件分组。

    data_out.write_vtu_with_pvtu_record(
      "./", "solution", cycle, mpi_communicator, 2, 8);
  }

//  @sect4{LaplaceProblem::run}

// 控制程序整体行为的函数又和  step-6  中的一样。小的区别是使用 pcout instead of std::cout 来输出到控制台（也见 step-17 ），而且我们只在最多涉及32个处理器的情况下产生图形输出。如果没有这个限制，人们很容易在没有阅读这个程序的情况下粗心大意地运行这个程序，从而导致集群互连中断，并填满任何可用的文件系统 :-)

// 与 step-6 的一个功能上的区别是使用了一个正方形域，并且我们从一个稍细的网格开始（5个全局细化周期）--在4个单元上开始显示一个大规模的%并行程序没有什么意义（尽管承认在1024单元上开始显示的意义只是稍强）。

  template <int dim>
  void LaplaceProblem<dim>::run()
  {
    pcout << "Running with "
#ifdef USE_PETSC_LA
          << "PETSc"
#else
          << "Trilinos"
#endif
          << " on " << Utilities::MPI::n_mpi_processes(mpi_communicator)
          << " MPI rank(s)..." << std::endl;

    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)
          {
            TimerOutput::Scope t(computing_timer, "output");
            output_results(cycle);
          }

        computing_timer.print_summary();
        computing_timer.reset();

        pcout << std::endl;
      }
  }
} // namespace Step40

//  @sect4{main()}

// 最后一个函数，  main()  ，同样具有与所有其他程序相同的结构，特别是  step-6  。像其他使用MPI的程序一样，我们必须初始化和最终确定MPI，这是用辅助对象  Utilities::MPI::MPI_InitFinalize.  完成的。该类的构造函数也初始化了依赖MPI的库，如p4est、PETSc、SLEPc和Zoltan（尽管最后两个在本教程中没有使用）。这里的顺序很重要：在这些库被初始化之前，我们不能使用它们，所以在创建  Utilities::MPI::MPI_InitFinalize.  的实例之前做任何事情都没有意义。

// 在求解器完成后，LaplaceProblem解构器将运行，然后是 Utilities::MPI::MPI_InitFinalize::~MPI_InitFinalize().  这个顺序也很重要： Utilities::MPI::MPI_InitFinalize::~MPI_InitFinalize() 调用 PetscFinalize （以及其他库的最终确定函数），这将删除任何正在使用的PETSc对象。这必须在我们解构拉普拉斯求解器之后进行，以避免双重删除错误。幸运的是，由于C++的析构器调用顺序规则，我们不需要担心这些：一切都以正确的顺序发生（即，与构造顺序相反）。由 Utilities::MPI::MPI_InitFinalize::~MPI_InitFinalize() 调用的最后一个函数是 MPI_Finalize ：也就是说，一旦这个对象被析构，程序应该退出，因为MPI将不再可用。

int main(int argc, char *argv[])
{
  try
    {
      using namespace dealii;
      using namespace Step40;

      Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);

      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;
}


/*! \file demo_point_markers.cpp
  \brief Demonstration of some marking data-point options.
  \details Includes Quickbook markup.
  \author Paul A Bristow
*/

// Copyright Jacob Voytko 2007
// Copyright Paul A Bristow 2008, 2020

// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

// An example to demonstrate some of the point plot markers available.

// This file is written to be included from a Quickbook .qbk document.
// It can be compiled by the C++ compiler, and run. Any output can
// also be added here as comment or included or pasted in elsewhere.

// Caution: this file contains Quickbook markup as well as code
// and comments: don't change any of the special comment markups!

//[demo_point_markers_1

/*`As ever, we need a few includes to use Boost.Plot
*/

#include <boost/svg_plot/svg_1d_plot.hpp>
  //using namespace boost::svg;
  //using boost::svg::svg_1d_plot;

#include <iostream>
  //using std::cout;
  //using std::endl;

#include <vector>
 // using std::vector;

#include <limits>
 // using std::numeric_limits;

#include <boost/svg_plot/show_1d_settings.hpp>  // Only required for diagnostics display of all settings.

//] [demo_point_markers_1]

int main()
{
  // Construct two data-sets as std::vectors.
  std::vector<double> my_data_1;
  my_data_1.push_back(-10.0);
  my_data_1.push_back(-9.0);
  my_data_1.push_back(-1.0);
  my_data_1.push_back(1.23456); // Data value-label will be rounded to 1.23 with my_1d_plot.x_values_precision(3);
  my_data_1.push_back(2.0);
  my_data_1.push_back(8.0987); // Rounded to 8.1
  my_data_1.push_back(99.0); // Finite value that is too big to fit into the plot window (shows as a point-right triangle in green).

  // Add some not-normal values to show how they are displayed.
  my_data_1.push_back(-std::numeric_limits<double>::infinity()); // Minus infinity shows as a point-left triangle or cone.
  my_data_1.push_back(+std::numeric_limits<double>::infinity()); // Plus infinity shows as a point-right triangle or cone.
  my_data_1.push_back(std::numeric_limits<double>::quiet_NaN()); // NaN (NotANumber) shows as a point-down triangle, at the origin (0, 0).

  // Second data-set.
  std::vector<double> my_data_2;
  my_data_2.push_back(-6.0);
  my_data_2.push_back(-4.0);
  my_data_2.push_back(+4.0);
  my_data_2.push_back(+6.0);

  using namespace boost::svg; // Convenient to ensure all color are available as CSS words, for example: red, blue, green, pink, purple...
  using boost::svg::svg_1d_plot;

//[demo_point_markers_2

  try
  { // try'n'catch blocks are needed to ensure error messages from any exceptions are shown.

    svg_1d_plot my_1d_plot; // Construct a plot with all the default constructor values.

    my_1d_plot.title("Demo point markers 1D") // Add a string title of the plot.
      .x_label("length (m)"); // Add a label for the X-axis, including a unit.

/*`Add the one data-series, `my_data` and a description, and how the data-points are to be marked,
here a blue diamond shape with a size of 10 pixels.
*/
    my_1d_plot.plot(my_data_1, "1D Values").shape(diamond).size(10).stroke_color(red).fill_color(blue);

    my_1d_plot.plot(my_data_2, "More 1D Values").shape(circlet).size(10).stroke_color(blue).fill_color(red);

/*`To put a decimal digit value-label against each data point, switch on the option:
*/
    my_1d_plot.x_values_on(true); // Add data decimal digit values as labels above the X-axis.

    my_1d_plot.x_values_precision(3); // Decimal digits precision for the X-axis value-label, for example "1.23".
    // if data-point value = 1.23456, then Data value-label will be 1.23 with my_1d_plot.x_values_precision(3);
    my_1d_plot.x_values_rotation(steepup); // Orientation for the X-axis value-labels.
    my_1d_plot.x_values_font_size(7); // Font Size for the X-axis value-labels.

    my_1d_plot.x_values_alignment(align_style::right_align); // has no effect
    // And we can show these settings:
    std::cout << "alignment is " << my_1d_plot.x_values_alignment() << std::endl; // alignment is left
    std::cout << "rotation is " << show_rotation(my_1d_plot.x_values_rotation()) << std::endl; // rotation is steepup (-60)

/*`If the default size and color are not to your taste, set more options, like:
*/
    my_1d_plot.x_values_font_size(14) // Change font size for the X-axis value-labels.
      .x_values_font_family("Times New Roman") // Change font for the X-axis value-labels.
      .x_values_color(red); // Change x-values font-color from default black to red.

 /*` The 'at limit' values (+/- infinity or NaN) markers can be customised, for example:
    my_1d_plot.nan_limit_color(purple);
    my_1d_plot.nan_limit_fill_color(green); // No effect on fill color?
    my_1d_plot.nan_limit_size(20);
    // But this currently makes + and - infinity and NaN all solid purple.
  NaN limit points stroke color RGB(128,0,128)  purple
  NaN limit points fill color RGB(0,128,0) green
  NaN limit points size 20

  +infinity limit points stroke color RGB(255,0,0)    red
  +infinity limit points fill color RGB(255,255,255)  white
  +infinity limit points size 10

  -infinity limit points stroke color RGB(0,0,255)  blue
  -infinity limit points fill color  RGB(255,255,255)  white
 */

    /*`To use all these settings, finally write the plot to file.
*/
    my_1d_plot.write("demo_point_markers.svg");

//`If chosen settings do not have the expected effect, is may be helpful to show them.

    std::cout << "my_1d_plot.x_values_font_size() " << my_1d_plot.x_values_font_size() << std::endl;
    std::cout << "my_1d_plot.x_values_font_family() " << my_1d_plot.x_values_font_family() << std::endl;
    std::cout << "my_1d_plot.x_values_color() " << my_1d_plot.x_values_color() << std::endl;
    std::cout << "my_1d_plot.x_values_precision() " << my_1d_plot.x_values_precision() << std::endl;
    std::cout << "my_1d_plot.x_values_ioflags() " << std::hex << my_1d_plot.x_values_ioflags() << std::dec << std::endl;

    std::cout << "NaN limit points stroke color " << my_1d_plot.nan_limit_color() << std::endl;
    std::cout << "NaN limit points fill color " << my_1d_plot.nan_limit_fill_color() << std::endl;
    std::cout << "NaN limit points size " << my_1d_plot.nan_limit_size() << std::endl;
    std::cout << "+infinity limit points stroke color " << my_1d_plot.plus_inf_limit_color() << std::endl;
    std::cout << "+infinity limit points fill color " << my_1d_plot.plus_inf_limit_fill_color() << std::endl;
    std::cout << "+infinity limit points size " << my_1d_plot.plus_inf_limit_size() << std::endl;
    std::cout << "-infinity limit points stroke color " << my_1d_plot.minus_inf_limit_color() << std::endl;
    std::cout << "-infinity limit points fill color " << my_1d_plot.minus_inf_limit_fill_color() << std::endl;
    std::cout << "-infinity limit points size " << my_1d_plot.minus_inf_limit_size() << std::endl;

//] [demo_point_markers_2]

// (Or all (over one hundred) settings can be displayed with `show_1d_plot_settings(my_1d_plot)`, commented out below.
   // show_1d_plot_settings(my_1d_plot);

  }
  catch(const std::exception& e)
  {
    std::cout <<
      "\n""Message from thrown exception was:\n   " << e.what() << std::endl;
  }
  return 0;
} // int main()

/*

//[demo_point_markers_output

Output:

Compiling...
demo_point_markers.cpp
Linking...
Embedding manifest...
Autorun "j:\Cpp\SVG\debug\demo_point_markers.exe"
my_1d_plot.x_values_font_size() 14
my_1d_plot.x_values_font_family() Times New Roman
my_1d_plot.x_values_color() RGB(255,0,0)
my_1d_plot.x_values_precision() 3
my_1d_plot.x_values_ioflags() 200
Build Time 0:02
*/


/*
 [auto_generated]
 libs/numeric/odeint/test_external/eigen/resize.cpp

 [begin_description]
 tba.
 [end_description]

 Copyright 2013 Karsten Ahnert
 Copyright 2013 Mario Mulansky

 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)
 */

#include <boost/config.hpp>
#ifdef BOOST_MSVC
    #pragma warning(disable:4996)
#endif

#define BOOST_TEST_MODULE odeint_eigen_resize

#include <boost/test/unit_test.hpp>
#include <boost/numeric/odeint/external/eigen/eigen_resize.hpp>

using namespace boost::unit_test;
using namespace boost::numeric::odeint;

BOOST_AUTO_TEST_SUITE( eigen_resize )

BOOST_AUTO_TEST_CASE( test_compile_time_matrix )
{
    typedef Eigen::Matrix< double , 1 , 1 > matrix_type;
    matrix_type a , b;
    boost::numeric::odeint::resize( a , b );
    BOOST_CHECK( boost::numeric::odeint::same_size( a , b ) );
    BOOST_CHECK_EQUAL( a.rows() , 1 );
    BOOST_CHECK_EQUAL( a.cols() , 1 );
}

BOOST_AUTO_TEST_CASE( test_rumtime_matrix )
{
    typedef Eigen::Matrix< double , Eigen::Dynamic , Eigen::Dynamic > matrix_type;
    matrix_type a( 5 , 2 ) , b;

    BOOST_CHECK_EQUAL( a.rows() , 5 );
    BOOST_CHECK_EQUAL( a.cols() , 2 );
    BOOST_CHECK_EQUAL( b.rows() , 0 );
    BOOST_CHECK_EQUAL( b.cols() , 0 );
    BOOST_CHECK( !boost::numeric::odeint::same_size( a , b ) );

    boost::numeric::odeint::resize( b , a );

    BOOST_CHECK_EQUAL( a.rows() , 5 );
    BOOST_CHECK_EQUAL( a.cols() , 2 );
    BOOST_CHECK_EQUAL( b.rows() , 5 );
    BOOST_CHECK_EQUAL( b.cols() , 2 );

    BOOST_CHECK( boost::numeric::odeint::same_size( a , b ) );
}

BOOST_AUTO_TEST_CASE( test_rumtime_matrix2 )
{
    typedef Eigen::Matrix< double , Eigen::Dynamic , Eigen::Dynamic > matrix_type;
    matrix_type a( 5 , 2 ) , b( 2 , 3 );

    BOOST_CHECK_EQUAL( a.rows() , 5 );
    BOOST_CHECK_EQUAL( a.cols() , 2 );
    BOOST_CHECK_EQUAL( b.rows() , 2 );
    BOOST_CHECK_EQUAL( b.cols() , 3 );
    BOOST_CHECK( !boost::numeric::odeint::same_size( a , b ) );

    boost::numeric::odeint::resize( b , a );

    BOOST_CHECK_EQUAL( a.rows() , 5 );
    BOOST_CHECK_EQUAL( a.cols() , 2 );
    BOOST_CHECK_EQUAL( b.rows() , 5 );
    BOOST_CHECK_EQUAL( b.cols() , 2 );

    BOOST_CHECK( boost::numeric::odeint::same_size( a , b ) );
}

BOOST_AUTO_TEST_CASE( test_compile_time_array )
{
    typedef Eigen::Array< double , 1 , 1 > array_type;
    array_type a , b;
    boost::numeric::odeint::resize( a , b );
    BOOST_CHECK( boost::numeric::odeint::same_size( a , b ) );
    BOOST_CHECK_EQUAL( a.rows() , 1 );
    BOOST_CHECK_EQUAL( a.cols() , 1 );
}

BOOST_AUTO_TEST_CASE( test_rumtime_array )
{
    typedef Eigen::Array< double , Eigen::Dynamic , Eigen::Dynamic > array_type;
    array_type a( 5 , 2 ) , b;

    BOOST_CHECK_EQUAL( a.rows() , 5 );
    BOOST_CHECK_EQUAL( a.cols() , 2 );
    BOOST_CHECK_EQUAL( b.rows() , 0 );
    BOOST_CHECK_EQUAL( b.cols() , 0 );
    BOOST_CHECK( !boost::numeric::odeint::same_size( a , b ) );

    boost::numeric::odeint::resize( b , a );

    BOOST_CHECK_EQUAL( a.rows() , 5 );
    BOOST_CHECK_EQUAL( a.cols() , 2 );
    BOOST_CHECK_EQUAL( b.rows() , 5 );
    BOOST_CHECK_EQUAL( b.cols() , 2 );

    BOOST_CHECK( boost::numeric::odeint::same_size( a , b ) );
}

BOOST_AUTO_TEST_CASE( test_rumtime_array2 )
{
    typedef Eigen::Array< double , Eigen::Dynamic , Eigen::Dynamic > array_type;
    array_type a( 5 , 2 ) , b( 2 , 3 );

    BOOST_CHECK_EQUAL( a.rows() , 5 );
    BOOST_CHECK_EQUAL( a.cols() , 2 );
    BOOST_CHECK_EQUAL( b.rows() , 2 );
    BOOST_CHECK_EQUAL( b.cols() , 3 );
    BOOST_CHECK( !boost::numeric::odeint::same_size( a , b ) );

    boost::numeric::odeint::resize( b , a );

    BOOST_CHECK_EQUAL( a.rows() , 5 );
    BOOST_CHECK_EQUAL( a.cols() , 2 );
    BOOST_CHECK_EQUAL( b.rows() , 5 );
    BOOST_CHECK_EQUAL( b.cols() , 2 );

    BOOST_CHECK( boost::numeric::odeint::same_size( a , b ) );
}

BOOST_AUTO_TEST_SUITE_END()


//  (C) Copyright John Maddock 2006.
//  Use, modification and distribution are subject to the
//  Boost Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <pch.hpp>

#include <boost/math/concepts/real_concept.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/test/test_exec_monitor.hpp>
#include <boost/test/results_collector.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/math/tools/stats.hpp>
#include <boost/math/tools/test.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/array.hpp>
#include "functor.hpp"

#include "test_gamma_hooks.hpp"
#include "handle_test_result.hpp"

#if !defined(TEST_FLOAT) && !defined(TEST_DOUBLE) && !defined(TEST_LDOUBLE) && !defined(TEST_REAL_CONCEPT)
#  define TEST_FLOAT
#  define TEST_DOUBLE
#  define TEST_LDOUBLE
#  define TEST_REAL_CONCEPT
#endif

//
// DESCRIPTION:
// ~~~~~~~~~~~~
//
// This file tests the incomplete gamma function inverses
// gamma_p_inv and gamma_q_inv. There are three sets of tests:
// 1) Spot tests which compare our results with selected values
// computed using the online special function calculator at
// functions.wolfram.com,
// 2) Accuracy tests use values generated with NTL::RR at
// 1000-bit precision and our generic versions of these functions.
// 3) Round trip sanity checks, use the test data for the forward
// functions, and verify that we can get (approximately) back
// where we started.
//
// Note that when this file is first run on a new platform many of
// these tests will fail: the default accuracy is 1 epsilon which
// is too tight for most platforms.  In this situation you will
// need to cast a human eye over the error rates reported and make
// a judgement as to whether they are acceptable.  Either way please
// report the results to the Boost mailing list.  Acceptable rates of
// error are marked up below as a series of regular expressions that
// identify the compiler/stdlib/platform/data-type/test-data/test-function
// along with the maximum expected peek and RMS mean errors for that
// test.
//

void expected_results()
{
   //
   // Define the max and mean errors expected for
   // various compilers and platforms.
   //
   const char* largest_type;
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
   if(boost::math::policies::digits<double, boost::math::policies::policy<> >() == boost::math::policies::digits<long double, boost::math::policies::policy<> >())
   {
      largest_type = "(long\\s+)?double";
   }
   else
   {
      largest_type = "long double";
   }
#else
   largest_type = "(long\\s+)?double";
#endif
   //
   // Large exponent range causes more extreme test cases to be evaluated:
   //
   if(std::numeric_limits<long double>::max_exponent > std::numeric_limits<double>::max_exponent)
   {
      add_expected_result(
         "[^|]*",                          // compiler
         "[^|]*",                          // stdlib
         "[^|]*",                          // platform
         largest_type,                     // test type(s)
         "[^|]*small[^|]*",                    // test data group
         "[^|]*", 200000, 10000);              // test function
      add_expected_result(
         "[^|]*",                          // compiler
         "[^|]*",                          // stdlib
         "[^|]*",                          // platform
         "real_concept",                     // test type(s)
         "[^|]*small[^|]*",                   // test data group
         "[^|]*", 70000, 8000);                  // test function
   }
   //
   // These high error rates are seen on on some Linux
   // architectures:
   //
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "linux.*",                          // platform
      largest_type,                     // test type(s)
      "[^|]*medium[^|]*",                   // test data group
      "[^|]*", 350, 5);                  // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "linux.*",                          // platform
      largest_type,                     // test type(s)
      "[^|]*large[^|]*",                   // test data group
      "[^|]*", 150, 5);                  // test function

   //
   // Catch all cases come last:
   //
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      largest_type,                     // test type(s)
      "[^|]*medium[^|]*",                   // test data group
      "[^|]*", 20, 5);                  // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      largest_type,                     // test type(s)
      "[^|]*large[^|]*",                    // test data group
      "[^|]*", 5, 2);                   // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      largest_type,                     // test type(s)
      "[^|]*small[^|]*",                    // test data group
      "[^|]*", 2100, 500);              // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      "float|double",                   // test type(s)
      "[^|]*small[^|]*",                    // test data group
      "boost::math::gamma_p_inv", 500, 60);   // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      "float|double",                   // test type(s)
      "[^|]*",                          // test data group
      "boost::math::gamma_q_inv", 350, 60);   // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      "float|double",                   // test type(s)
      "[^|]*",                          // test data group
      "[^|]*", 4, 2);                   // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      "real_concept",                     // test type(s)
      "[^|]*medium[^|]*",                   // test data group
      "[^|]*", 20, 5);                  // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      "real_concept",                     // test type(s)
      "[^|]*large[^|]*",                   // test data group
      "[^|]*", 1000, 500);                  // test function
   add_expected_result(
      "[^|]*",                          // compiler
      "[^|]*",                          // stdlib
      "[^|]*",                          // platform
      "real_concept",                     // test type(s)
      "[^|]*small[^|]*",                   // test data group
      "[^|]*", 3700, 500);                  // test function

   //
   // Finish off by printing out the compiler/stdlib/platform names,
   // we do this to make it easier to mark up expected error rates.
   //
   std::cout << "Tests run with " << BOOST_COMPILER << ", "
      << BOOST_STDLIB << ", " << BOOST_PLATFORM << std::endl;
}

#define BOOST_CHECK_CLOSE_EX(a, b, prec, i) \
   {\
      unsigned int failures = boost::unit_test::results_collector.results( boost::unit_test::framework::current_test_case().p_id ).p_assertions_failed;\
      BOOST_CHECK_CLOSE(a, b, prec); \
      if(failures != boost::unit_test::results_collector.results( boost::unit_test::framework::current_test_case().p_id ).p_assertions_failed)\
      {\
         std::cerr << "Failure was at row " << i << std::endl;\
         std::cerr << std::setprecision(35); \
         std::cerr << "{ " << data[i][0] << " , " << data[i][1] << " , " << data[i][2];\
         std::cerr << " , " << data[i][3] << " , " << data[i][4] << " , " << data[i][5] << " } " << std::endl;\
      }\
   }

template <class T>
void do_test_gamma_2(const T& data, const char* type_name, const char* test_name)
{
   //
   // test gamma_p_inv(T, T) against data:
   //
   using namespace std;
   typedef typename T::value_type row_type;
   typedef typename row_type::value_type value_type;

   std::cout << test_name << " with type " << type_name << std::endl;

   //
   // These sanity checks test for a round trip accuracy of one half
   // of the bits in T, unless T is type float, in which case we check
   // for just one decimal digit.  The problem here is the sensitivity
   // of the functions, not their accuracy.  This test data was generated
   // for the forward functions, which means that when it is used as
   // the input to the inverses then it is necessarily inexact.  This rounding
   // of the input is what makes the data unsuitable for use as an accuracy check,
   // and also demonstrates that you can't in general round-trip these functions.
   // It is however a useful sanity check.
   //
   value_type precision = static_cast<value_type>(ldexp(1.0, 1-boost::math::policies::digits<value_type, boost::math::policies::policy<> >()/2)) * 100;
   if(boost::math::policies::digits<value_type, boost::math::policies::policy<> >() < 50)
      precision = 1;   // 1% or two decimal digits, all we can hope for when the input is truncated to float

   for(unsigned i = 0; i < data.size(); ++i)
   {
      //
      // These inverse tests are thrown off if the output of the
      // incomplete gamma is too close to 1: basically there is insuffient
      // information left in the value we're using as input to the inverse
      // to be able to get back to the original value.
      //
      if(data[i][5] == 0)
         BOOST_CHECK_EQUAL(boost::math::gamma_p_inv(data[i][0], data[i][5]), value_type(0));
      else if((1 - data[i][5] > 0.001)
         && (fabs(data[i][5]) > 2 * boost::math::tools::min_value<value_type>())
         && (fabs(data[i][5]) > 2 * boost::math::tools::min_value<double>()))
      {
         value_type inv = boost::math::gamma_p_inv(data[i][0], data[i][5]);
         BOOST_CHECK_CLOSE_EX(data[i][1], inv, precision, i);
      }
      else if(1 == data[i][5])
         BOOST_CHECK_EQUAL(boost::math::gamma_p_inv(data[i][0], data[i][5]), boost::math::tools::max_value<value_type>());
      else
      {
         // not enough bits in our input to get back to x, but we should be in
         // the same ball park:
         value_type inv = boost::math::gamma_p_inv(data[i][0], data[i][5]);
         BOOST_CHECK_CLOSE_EX(data[i][1], inv, 100000, i);
      }

      if(data[i][3] == 0)
         BOOST_CHECK_EQUAL(boost::math::gamma_q_inv(data[i][0], data[i][3]), boost::math::tools::max_value<value_type>());
      else if((1 - data[i][3] > 0.001) && (fabs(data[i][3]) > 2 * boost::math::tools::min_value<value_type>()))
      {
         value_type inv = boost::math::gamma_q_inv(data[i][0], data[i][3]);
         BOOST_CHECK_CLOSE_EX(data[i][1], inv, precision, i);
      }
      else if(1 == data[i][3])
         BOOST_CHECK_EQUAL(boost::math::gamma_q_inv(data[i][0], data[i][3]), value_type(0));
      else if(fabs(data[i][3]) > 2 * boost::math::tools::min_value<value_type>())
      {
         // not enough bits in our input to get back to x, but we should be in
         // the same ball park:
         value_type inv = boost::math::gamma_q_inv(data[i][0], data[i][3]);
         BOOST_CHECK_CLOSE_EX(data[i][1], inv, 100, i);
      }
   }
   std::cout << std::endl;
}

template <class T>
void do_test_gamma_inv(const T& data, const char* type_name, const char* test_name)
{
   typedef typename T::value_type row_type;
   typedef typename row_type::value_type value_type;

   typedef value_type (*pg)(value_type, value_type);
#if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS)
   pg funcp = boost::math::gamma_p_inv<value_type, value_type>;
#else
   pg funcp = boost::math::gamma_p_inv;
#endif

   boost::math::tools::test_result<value_type> result;

   std::cout << "Testing " << test_name << " with type " << type_name
      << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";

   //
   // test gamma_p_inv(T, T) against data:
   //
   result = boost::math::tools::test(
      data,
      bind_func(funcp, 0, 1),
      extract_result(2));
   handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::gamma_p_inv", test_name);
   //
   // test gamma_q_inv(T, T) against data:
   //
#if defined(BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS)
   funcp = boost::math::gamma_q_inv<value_type, value_type>;
#else
   funcp = boost::math::gamma_q_inv;
#endif
   result = boost::math::tools::test(
      data,
      bind_func(funcp, 0, 1),
      extract_result(3));
   handle_test_result(result, data[result.worst()], result.worst(), type_name, "boost::math::gamma_q_inv", test_name);
}

template <class T>
void test_gamma(T, const char* name)
{
   //
   // The actual test data is rather verbose, so it's in a separate file
   //
   // First the data for the incomplete gamma function, each
   // row has the following 6 entries:
   // Parameter a, parameter z,
   // Expected tgamma(a, z), Expected gamma_q(a, z)
   // Expected tgamma_lower(a, z), Expected gamma_p(a, z)
   //
#  include "igamma_med_data.ipp"

   do_test_gamma_2(igamma_med_data, name, "Running round trip sanity checks on incomplete gamma medium sized values");

#  include "igamma_small_data.ipp"

   do_test_gamma_2(igamma_small_data, name, "Running round trip sanity checks on incomplete gamma small values");

#  include "igamma_big_data.ipp"

   do_test_gamma_2(igamma_big_data, name, "Running round trip sanity checks on incomplete gamma large values");

#  include "gamma_inv_data.ipp"

   do_test_gamma_inv(gamma_inv_data, name, "incomplete gamma inverse(a, z) medium values");

#  include "gamma_inv_big_data.ipp"

   do_test_gamma_inv(gamma_inv_big_data, name, "incomplete gamma inverse(a, z) large values");

#  include "gamma_inv_small_data.ipp"

   do_test_gamma_inv(gamma_inv_small_data, name, "incomplete gamma inverse(a, z) small values");
}

template <class T>
void test_spots(T, const char* type_name)
{
   std::cout << "Running spot checks for type " << type_name << std::endl;
   //
   // basic sanity checks, tolerance is 150 epsilon expressed as a percentage:
   //
   T tolerance = boost::math::tools::epsilon<T>() * 15000;
   if(tolerance < 1e-25f)
      tolerance = 1e-25f;  // limit of test data?
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(1)/100, static_cast<T>(1.0/128)), static_cast<T>(0.35767144525455121503672919307647515332256996883787L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(1)/100, static_cast<T>(0.5)), static_cast<T>(4.4655350189103486773248562646452806745879516124613e-31L), tolerance*10);
   //
   // We can't test in this region against Mathworld's data as the results produced
   // by functions.wolfram.com appear to be in error, and do *not* round trip with
   // their own version of gamma_q.  Using our output from the inverse as input to
   // their version of gamma_q *does* round trip however.  It should be pointed out
   // that the functions in this area are very sensitive with nearly infinite
   // first derivatives, it's also questionable how useful these functions are
   // in this part of the domain.
   //
   //BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(1e-2), static_cast<T>(1.0-1.0/128)), static_cast<T>(3.8106736649978161389878528903698068142257930575497e-181L), tolerance);
   //
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(0.5), static_cast<T>(1.0/128)), static_cast<T>(3.5379794687984498627918583429482809311448951189097L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(0.5), static_cast<T>(1.0/2)), static_cast<T>(0.22746821155978637597125832348982469815821055329511L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(0.5), static_cast<T>(1.0-1.0/128)), static_cast<T>(0.000047938431649305382237483273209405461203600840052182L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(10), static_cast<T>(1.0/128)), static_cast<T>(19.221865946801723949866005318845155649972164294057L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(10), static_cast<T>(1.0/2)), static_cast<T>(9.6687146147141311517500637401166726067778162022664L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(10), static_cast<T>(1.0-1.0/128)), static_cast<T>(3.9754602513640844712089002210120603689809432130520L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(10000), static_cast<T>(1.0/128)), static_cast<T>(10243.369973939134157953734588122880006091919872879L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(10000), static_cast<T>(1.0/2)), static_cast<T>(9999.6666686420474237369661574633153551436435884101L), tolerance);
   BOOST_CHECK_CLOSE(::boost::math::gamma_q_inv(static_cast<T>(10000), static_cast<T>(1.0-1.0/128)), static_cast<T>(9759.8597223369324083191194574874497413261589080204L), tolerance);
}

int test_main(int, char* [])
{
   expected_results();
   BOOST_MATH_CONTROL_FP;

#ifndef BOOST_MATH_BUGGY_LARGE_FLOAT_CONSTANTS
#ifdef TEST_FLOAT
   test_spots(0.0F, "float");
#endif
#endif
#ifdef TEST_DOUBLE
   test_spots(0.0, "double");
#endif
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
#ifdef TEST_LDOUBLE
   test_spots(0.0L, "long double");
#endif
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
#ifdef TEST_REAL_CONCEPT
   test_spots(boost::math::concepts::real_concept(0.1), "real_concept");
#endif
#endif
#endif

#ifndef BOOST_MATH_BUGGY_LARGE_FLOAT_CONSTANTS
#ifdef TEST_FLOAT
   test_gamma(0.1F, "float");
#endif
#endif
#ifdef TEST_DOUBLE
   test_gamma(0.1, "double");
#endif
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
#ifdef TEST_LDOUBLE
   test_gamma(0.1L, "long double");
#endif
#ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
#ifdef TEST_REAL_CONCEPT
   test_gamma(boost::math::concepts::real_concept(0.1), "real_concept");
#endif
#endif
#endif
#else
   std::cout << "<note>The long double tests have been disabled on this platform "
      "either because the long double overloads of the usual math functions are "
      "not available at all, or because they are too inaccurate for these tests "
      "to pass.</note>" << std::cout;
#endif
   return 0;
}


// Test for sorting procedures in sort.h

#define CATCH_CONFIG_MAIN
#include <test/catch.hpp>

// File to test
#include <alglib/sort/sort.h>

#include <vector>

using namespace alglib::sort;

/* All the sorting procedures are differentially tested against
 * the std::sort function. The following cases are tested for
 * each sorting function:
 * 	1. Empty containers
 *  2. Randomly filled containers
 *  3. Several different types - float, strings
 *  4. Invalid inputs - non-containers, non-iterable
 *  5. For each valid iterator category.
 */

template<typename Container>
Container random_int_list (int sz)
{
	Container C;
	auto it = std::back_inserter (C);

	/* fill up the container */
	srand (time (0));
	std::generate_n (it, sz, rand);

	return C;
}

/* A test is performed as follows:
 * 	1. Create two identical containers filled randomly.
 *  2. Sort one of them - call it std_sorted - using std::sort.
 *  3. Sort the other, test_sorted, using the procedure under test.
 *  4. Assert their equality.
 */

TEST_CASE ("Merge sort", "[merge_sort]")
{
	std::vector<int> test_sorted, std_sorted;

	std::vector<int> sizes = {0, 1000, 1000000};

	for (int size : sizes)
    {
		test_sorted = std_sorted = std::move(random_int_list<decltype(std_sorted)> (size));

		merge_sort (test_sorted.begin(), test_sorted.end());
		std::sort (std_sorted.begin(), std_sorted.end());

		REQUIRE (test_sorted == std_sorted);
	}

    // const_iterators are invalid.
    // REQUIRE_THROWS (merge_sort (test_sorted.cbegin (), test_sorted.cend ()));

    // Check if it works for non-random access iterators.
}


/**
 * @file newproblem_test.cc
 * @brief NPDE homework NewProblem code
 * @author Oliver Rietmann, Erick Schulz
 * @date 01.01.2020
 * @copyright Developed at ETH Zurich
 */

#include <Eigen/Core>

#include <gtest/gtest.h>

#include "../newproblem.h"

namespace NewProblem::test {

TEST(NewProblem, dummyFunction) {
  double x = 0.0;
  int n = 0;

  Eigen::Vector2d v = NewProblem::dummyFunction(x, n);

  Eigen::Vector2d v_ref = {1.0, 1.0};

  double tol = 1.0e-8;
  ASSERT_NEAR(0.0, (v - v_ref).lpNorm<Eigen::Infinity>(), tol);
}

}  // namespace NewProblem::test


//------------------------------------------------------------------------------
/// \file Max_tests.cpp
/// \ref Vandevoorde, Josuttis, Gregor. C++ Templates: The Complete Guide. 2nd
/// Ed. Addison-Wesley Professional. 2017.
//------------------------------------------------------------------------------
#include "Cpp/Templates/FunctionT/Max.h"

#include <boost/test/unit_test.hpp>
#include <complex>
#include <string>

using Cpp::Templates::FunctionTemplates::max;
using Cpp::Templates::FunctionTemplates::max_with_const;

BOOST_AUTO_TEST_SUITE(Cpp)
BOOST_AUTO_TEST_SUITE(Templates)
BOOST_AUTO_TEST_SUITE(FunctionTemplates)
BOOST_AUTO_TEST_SUITE(Max_tests)

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(DemonstrateMax)
{
	{
		// Works for ints
		const int a {4};
		const int b {5};
		BOOST_TEST(::max(a, b) == b);
	}
}

// cf. VJG (2017), pp. 4, 1.1.2 Using the Template
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ShowHowToUseMax)
{
  constexpr int i {42};

  // Note that each call of max() template qualified with ::. This is to ensure
  // that our max() template is found in the global namespace. There is also a
  // std::max() template in standard library.
  BOOST_TEST(::max(7, i) == i);

  constexpr double f1 {3.4};
  constexpr double f2 {-6.7};

  BOOST_TEST(::max(f1, f2) == f1);

  const std::string s1 {"mathematics"};
  const std::string s2 {"math"};

  // The process of replacing template parameters by concrete types is called
  // instantiation. It results in an instance of a template.
  BOOST_TEST(::max(s1, s2) == s1);

  // Templates aren't compiled into single entities that can handle any type.
  // Instead, different entities are generated from template for every type for
  // which template is used. Thus, max() compiled for each of these 3 types.
}

// void is a valid template argument.
template <typename T>
T foo(T*)
{
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(VoidIsAValidTemplateArgument)
{
  void* vp = nullptr;

  foo(vp); // OK: deduces void foo(void*)

  BOOST_TEST(true);
}

// cf. pp. 6, 1.1.3 Two-Phase Translation, VJG (2017)
// An attempt to instantiate a template for type that doesn't support all the
// operations used within it will result in compile-time error.

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(InstantiateWithTypeThatDoesNotSupportAllOperations)
{
  std::complex<float> c1, c2;
  c1 = {3.0, -5.0};
  c2 = {42.0, -69.0};

  //::max(c1, c2); // ERROR at compile time.

  BOOST_TEST(true);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(TemplateArgumentDeducedAsPartOfConstReferenceType)
{
  std::complex<float> c1, c2;
  c1 = {3.0, -5.0};
  c2 = {42.0, -69.0};

  //::max(c1, c2); // ERROR at compile time.

  BOOST_TEST(true);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(TypeConversionsDuringTypeDeductionByValueDecay)
{
  constexpr int c {42};
  int i {64};
  BOOST_TEST_REQUIRE(max(i, c) == i); // OK: T is deduced as int
  BOOST_TEST_REQUIRE(max(i, c) == i); // OK: T is deduced as int

  int& ir {i};
  BOOST_TEST_REQUIRE(max(i, ir) == i); // OK: T is deduced as int
  //int arr[4];
  //BOOST_TEST(max(&i, arr) == &i);

  // ERROR: T can be deduced as int or double.
  //max(4, 7.2);

  std::string s;

  // ERROR: T can be deduced as char const[6] or std::string
  //max("hello", s);

  // 3 ways to handle such errors:

  // 1. Cast the arguments so that they both match:
  BOOST_TEST(max(static_cast<double>(4), 7.2) == 7.2); // OK

  // 2. Specify (or qualify) explicitly the type of T to prevent from attempting
  // type deduction:
  BOOST_TEST(max<double>(4, 7.2) == 7.2);

  // 3. Specify that parameters may have different types.

  BOOST_TEST(true);
}

template <typename T>
void f(T ="")
{
  return;
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(TypeDeductionForDefaultArguments)
{
  f(1); // OK: deduced T to be int, so that it calls f<int>(1)
  //  error: no matching function for call to ‘f()’
  //f(); // ERROR: cannot deduce T
  BOOST_TEST(true);
}

// Declare argument for the template parameter.
template <typename T = std::string>
void f1(T ="")
{
  return;
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(TypeDeductionForDefaultTemplateArgument)
{
  f1(); // OK
  BOOST_TEST(true);
}

// pp. 15, Sec. 1.5 Overloaindg Function Templates
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(OverloadingFunctionTemplates)
{
  BOOST_TEST(max(7, 42) == 42); // calls nontemplate for 2 ints.
  BOOST_TEST(max(7.0, 42.0) == 42.0); // call max <double> (by argument
    //deduction)
  BOOST_TEST(max('a', 'b') == 'b'); // calls max<char> (by argument deduction)
  BOOST_TEST(max<>(7, 42) == 42); // call max<int> (by argument deduction)
  BOOST_TEST(max<double>(7, 42) == 42.0); // calls max<double> (no argument
  // deduction)
  BOOST_TEST(max('a', 42.7) == 97); // call the nontemplate for two ints
}

BOOST_AUTO_TEST_SUITE_END() // Max_tests

BOOST_AUTO_TEST_SUITE_END() // FunctionTemplates
BOOST_AUTO_TEST_SUITE_END() // Templates
BOOST_AUTO_TEST_SUITE_END() // Cpp