//=======================================================================
// Copyright 2001 Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee,
//
// 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/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/range/irange.hpp>
#include <boost/pending/indirect_cmp.hpp>

#include <iostream>

using namespace boost;
template < typename TimeMap >
class dfs_time_visitor : public default_dfs_visitor
{
    typedef typename property_traits< TimeMap >::value_type T;

public:
    dfs_time_visitor(TimeMap dmap, TimeMap fmap, T& t)
    : m_dtimemap(dmap), m_ftimemap(fmap), m_time(t)
    {
    }
    template < typename Vertex, typename Graph >
    void discover_vertex(Vertex u, const Graph& g) const
    {
        put(m_dtimemap, u, m_time++);
    }
    template < typename Vertex, typename Graph >
    void finish_vertex(Vertex u, const Graph& g) const
    {
        put(m_ftimemap, u, m_time++);
    }
    TimeMap m_dtimemap;
    TimeMap m_ftimemap;
    T& m_time;
};

int main()
{
    // Select the graph type we wish to use
    typedef adjacency_list< vecS, vecS, directedS > graph_t;
    typedef graph_traits< graph_t >::vertices_size_type size_type;
    // Set up the vertex names
    enum
    {
        u,
        v,
        w,
        x,
        y,
        z,
        N
    };
    char name[] = { 'u', 'v', 'w', 'x', 'y', 'z' };
    // Specify the edges in the graph
    typedef std::pair< int, int > E;
    E edge_array[] = { E(u, v), E(u, x), E(x, v), E(y, x), E(v, y), E(w, y),
        E(w, z), E(z, z) };
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
    graph_t g(N);
    for (std::size_t j = 0; j < sizeof(edge_array) / sizeof(E); ++j)
        add_edge(edge_array[j].first, edge_array[j].second, g);
#else
    graph_t g(edge_array, edge_array + sizeof(edge_array) / sizeof(E), N);
#endif

    // discover time and finish time properties
    std::vector< size_type > dtime(num_vertices(g));
    std::vector< size_type > ftime(num_vertices(g));
    typedef iterator_property_map< std::vector< size_type >::iterator,
        property_map< graph_t, vertex_index_t >::const_type >
        time_pm_type;
    time_pm_type dtime_pm(dtime.begin(), get(vertex_index, g));
    time_pm_type ftime_pm(ftime.begin(), get(vertex_index, g));
    size_type t = 0;
    dfs_time_visitor< time_pm_type > vis(dtime_pm, ftime_pm, t);

    depth_first_search(g, visitor(vis));

    // use std::sort to order the vertices by their discover time
    std::vector< size_type > discover_order(N);
    integer_range< size_type > r(0, N);
    std::copy(r.begin(), r.end(), discover_order.begin());
    std::sort(discover_order.begin(), discover_order.end(),
        indirect_cmp< time_pm_type, std::less< size_type > >(dtime_pm));
    std::cout << "order of discovery: ";
    int i;
    for (i = 0; i < N; ++i)
        std::cout << name[discover_order[i]] << " ";

    std::vector< size_type > finish_order(N);
    std::copy(r.begin(), r.end(), finish_order.begin());
    std::sort(finish_order.begin(), finish_order.end(),
        indirect_cmp< time_pm_type, std::less< size_type > >(ftime_pm));
    std::cout << std::endl << "order of finish: ";
    for (i = 0; i < N; ++i)
        std::cout << name[finish_order[i]] << " ";
    std::cout << std::endl;

    return EXIT_SUCCESS;
}


//          Copyright John McFarlane 2015 - 2016.
// 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 <sg14/cstdint>

#include <gtest/gtest.h>

#if defined(SG14_BOOST_ENABLED)
#include <boost/integer.hpp>
#endif

using std::declval;
using std::is_same;

namespace sample1 {
    // range of a*b is UCHAR_MAX*UCHAR_MAX but range of return value is UCHAR_MAX
    uint8_t multiply(uint8_t a, uint8_t b)
    {
        return a*b;
    }

    // sample 1 tests
    using single_width = uint8_t;

    static_assert(UCHAR_MAX==255, "incorrect assumption about value of UCHAR_MAX");
    static_assert(UCHAR_MAX*UCHAR_MAX==65025, "incorrect assumption about value of UCHAR_MAX");

    TEST(p0381, multiply_uint8_ok)
    {
        ASSERT_EQ(100, multiply(10, 10));
    }

    TEST(p0381, multiply_uint8_overflow)
    {
        ASSERT_NE(400, multiply(20, 20));
    }
}

#if (__cplusplus>=201402L)
namespace sample2 {
    // range of a*b is UINT_MAX*UINT_MAX but range of return value is UINT_MAX
    auto multiply(unsigned a, unsigned b)
    {
        return a*b;
    }

    // sample 2 tests
    using wide_type = unsigned long long;

    static_assert(sizeof(wide_type)>=sizeof(unsigned)*2,
            "the following tests assume unsigned long long is twice the size of unsigned");
    static_assert(is_same<decltype(declval<unsigned>()*declval<unsigned>()), unsigned>::value,
            "incorrect assumption about type of result of unsigned * unsigned");

    TEST(p0381, multiply_unsigned_ok)
    {
        ASSERT_EQ(400u, multiply(20u, 20u));
    }

    TEST(p0381, multiply_unsigned_overflow)
    {
        ASSERT_NE(static_cast<wide_type>(UINT_MAX)*static_cast<wide_type>(UINT_MAX),
                static_cast<wide_type>(multiply(UINT_MAX, UINT_MAX)));
    }
}

namespace sample3 {
    auto multiply(uint32_t a, uint32_t b)
    {
        using result_type = uint64_t;
        return result_type{a}*result_type{b};
    }

    // sample 3 tests
    static_assert(is_same<uint64_t, decltype(multiply(declval<uint32_t>(), declval<uint32_t>()))>::value,
            "incorrect assumption about result of multiply function");

    TEST(p0381, multiply_unsigned_ok)
    {
        ASSERT_EQ(400u, multiply(20u, 20u));
    }

    TEST(p0381, multiply_unsigned_still_ok)
    {
        ASSERT_EQ(static_cast<uint64_t>(UINT_MAX)*static_cast<uint64_t>(UINT_MAX),
                static_cast<uint64_t>(multiply(UINT_MAX, UINT_MAX)));
    }
}

namespace sample4 {
    // Sample 4 intentionally does not exist. If it did, there would be no need for P0381!
}

#if defined(SG14_BOOST_ENABLED)
namespace sample5 {
    template<class Operand>
    auto multiply(Operand a, Operand b)
    {
        constexpr auto operand_width = sizeof(Operand)*CHAR_BIT*2;
        using result_type = typename boost::uint_t<operand_width>::fast;
        return result_type{a}*result_type{b};
    }

    // sample 5 tests are a lot like sample 3 tests

    // they are more generic
#if ! defined(__APPLE__)    // uint64_t is a different type depending on the version of XCode
    static_assert(is_same<uint64_t, decltype(multiply(declval<uint32_t>(), declval<uint32_t>()))>::value,
            "incorrect assumption about result of multiply function");
#endif
    static_assert(is_same<uint32_t, decltype(multiply(declval<uint16_t>(), declval<uint16_t>()))>::value,
            "incorrect assumption about result of multiply function");

    // but don't do so well with signed types
//    static_assert(is_same<int64_t, decltype(multiply(declval<int32_t>(), declval<int32_t>()))>::value,
//            "incorrect assumption about result of multiply function");
//    static_assert(is_same<int32_t, decltype(multiply(declval<int16_t>(), declval<int16_t>()))>::value,
//            "incorrect assumption about result of multiply function");

    TEST(p0381, multiply_unsigned_ok)
    {
        ASSERT_EQ(400u, multiply(20u, 20u));
    }

    TEST(p0381, multiply_unsigned_still_ok)
    {
        ASSERT_EQ(static_cast<uint64_t>(UINT_MAX)*static_cast<uint64_t>(UINT_MAX),
                static_cast<uint64_t>(multiply(UINT_MAX, UINT_MAX)));
    }
}
#endif  // defined(SG14_BOOST_ENABLED)
#endif  // C++14

namespace determining {
    using sg14::width;

    static_assert(width<uint16_t>::value == 16, "the width of uint16_t is exactly 16 bits");
    static_assert(width<long long>::value >= 64, "long long has a width of at least 64 bits");
    static_assert(width<long>::value >= width<short>::value, "short is no longer than long");
    static_assert(width<wchar_t>::value >= width<char>::value, "a wide character is at least as wide as a character");
}

namespace specifiying {
    using sg14::set_width_t;
    using sg14::width;
    static_assert(is_same<set_width_t<signed, 8>, int8_t>::value, "int8_t is a signed 8-bit integer");
    static_assert(is_same<set_width_t<unsigned, 32>, uint32_t>::value, "uint32_t is an unsigned 32-bit integer");
    static_assert(is_same<set_width_t<uint64_t, 16>, uint16_t>::value, "a 64-bit unsigned integer was narrowed to 16-bits");
    static_assert(is_same<set_width_t<char, 64>, int64_t>::value || is_same<set_width_t<char, 64>, uint64_t>::value, "char may or may not be signed so the result may be uint64_t or int64_t");
    static_assert(width<set_width_t<int, 10>>::value >= 10, "result must be at least 10 bits wide");
}


/*    Copyright (c) 2010-2015, Delft University of Technology
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without modification, are
 *    permitted provided that the following conditions are met:
 *      - Redistributions of source code must retain the above copyright notice, this list of
 *        conditions and the following disclaimer.
 *      - Redistributions in binary form must reproduce the above copyright notice, this list of
 *        conditions and the following disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *      - Neither the name of the Delft University of Technology nor the names of its contributors
 *        may be used to endorse or promote products derived from this software without specific
 *        prior written permission.
 *
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 *    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *    AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *    OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110207    B. Romgens        File created.
 *      110215    K. Kumar          Minor modifications to layout, comments
 *                                  and variable-naming.
 *      110411    K. Kumar          Added unit test for
 *                                  convertCartesianToSpherical( ) function.
 *      110701    K. Kumar          Updated failing tests with relative errors.
 *      110708    K. Kumar          Added unit tests for computeSampleMean( )
 *                                  and computeSampleVariance( ) functions.
 *      110905    S. Billemont      Reorganized includes.
 *                                  Moved (con/de)structors and getter/setters to header.
 *      111111    K. Kumar          Strange error with convertCylindricalToCartesian function;
 *                                  achieved precision of results is less than machine precision,
 *                                  fixed by using slightly larger precision tolerance.
 *      120202    K. Kumar          Moved unit tests from unitTestBasicMathematicsFunctions.h/.cpp;
 *                                  rewrote unit tests using Boost unit test framework.
 *
 *    References
 *
 *    Notes
 *
 */

#define BOOST_TEST_MAIN

#include <limits>

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

#include "Tudat/Mathematics/Statistics/basicStatistics.h"

namespace tudat
{
namespace unit_tests
{

BOOST_AUTO_TEST_SUITE( test_basic_statistics )

//! Test if sample mean is computed correctly.
BOOST_AUTO_TEST_CASE( testSampleMean )
{
    // Test computation of sample mean on finite population using unbiased estimators.
    // The expected values are computed using the Microsoft Excel the AVERAGE( ) function.

    // Declare vector of sample data.
    std::vector< double > sampleData;

    // Populate vector with sample data.
    sampleData.push_back( 2.5 );
    sampleData.push_back( 6.4 );
    sampleData.push_back( 8.9 );
    sampleData.push_back( 12.7 );
    sampleData.push_back( 15.0 );

    // Set expected sample mean.
    double expectedSampleMean = 9.1;

    // Compute sample mean.
    double computedSampleMean = statistics::computeSampleMean( sampleData );

    // Check if computed sample mean matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( computedSampleMean, expectedSampleMean,
                                std::numeric_limits< double >::epsilon( ) );
}

//! Test if sample variance is computed correctly.
BOOST_AUTO_TEST_CASE( testSampleVariance )
{
    // Test computation of sample variance on finite population using unbiased estimators.
    // The expected values are computed using the Microsoft Excel the VAR( ) function.

    // Declare vector of sample data.
    std::vector< double > sampleData;

    // Populate vector with sample data.
    sampleData.push_back( 2.5 );
    sampleData.push_back( 6.4 );
    sampleData.push_back( 8.9 );
    sampleData.push_back( 12.7 );
    sampleData.push_back( 15.0 );

    // Declare expected sample variance.
    double expectedSampleVariance = 24.665;

    // Compute sample variance.
    double computedSampleVariance = statistics::computeSampleVariance( sampleData );

    // Check if computed sample variance matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( computedSampleVariance, expectedSampleVariance,
                                std::numeric_limits< double >::epsilon( ) );
}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat