<commit_before>////////////////////////////////////////////////////////////////////////////////
///
/// \file apple.hpp
/// ---------------
///
/// (c) Copyright Domagoj Saric 2016 - 2017.
///
///  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)
///
///  See http://www.boost.org for most recent version.
///
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
#pragma once
//------------------------------------------------------------------------------
#include <boost/assert.hpp>
#include <boost/config_ex.hpp>

#include <algorithm>
#include <cstdint>
#include <future>
#include <thread>
#include <type_traits>

#include <dispatch/dispatch.h>
#include <TargetConditionals.h>
//------------------------------------------------------------------------------
namespace boost
{
//------------------------------------------------------------------------------
namespace sweater
{
//------------------------------------------------------------------------------

#ifndef BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY
#if TARGET_OS_IOS
#   ifdef __aarch64__
#       define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 3 // iPad 2 Air
#   else
#       define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 2
#   endif
#else
#   define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 0
#endif
#endif // BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY

BOOST_OVERRIDABLE_SYMBOL
auto const hardware_concurrency( static_cast<std::uint_fast8_t>( std::thread::hardware_concurrency() ) );

class impl
{
public:
    using iterations_t = std::uint32_t;

    // http://newosxbook.com/articles/GCD.html
    // http://www.idryman.org/blog/2012/08/05/grand-central-dispatch-vs-openmp
    static auto number_of_workers() noexcept
    {
        BOOST_ASSERT_MSG( hardware_concurrency == std::thread::hardware_concurrency(), "Hardware concurrency changed at runtime!?" );
    #if BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY
        BOOST_ASSUME( hardware_concurrency <= BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY );
    #endif
        return hardware_concurrency;
    }

    template <typename F>
    static void spread_the_sweat( iterations_t const iterations, F && work ) noexcept
    {
        static_assert( noexcept( work( iterations, iterations ) ), "F must be noexcept" );

        /// \note Stride the iteration count based on the number of workers
        /// (otherwise dispatch_apply will make an indirect function call for
        /// each iteration).
        /// The iterations / number_of_workers is an integer division and can
        /// thus be 'lossy' so extra steps need to be taken to account for this.
        ///                                   (04.10.2016.) (Domagoj Saric)
        auto              const number_of_workers    ( impl::number_of_workers() );
        iterations_t      const iterations_per_worker( iterations / number_of_workers );
        std::uint_fast8_t const extra_iterations     ( iterations % number_of_workers );
        auto /*const*/ worker
        (
            [
                &work, iterations_per_worker, extra_iterations
            #ifndef NDEBUG
                , iterations
            #endif // !NDEBUG
            ]
            ( std::uint_fast8_t const worker_index ) noexcept
            {
                auto const extra_iters        ( std::min( worker_index, extra_iterations ) );
                auto const plain_iters        ( worker_index - extra_iters                 );
                auto const this_has_extra_iter( worker_index < extra_iterations            );
                auto const start_iteration
                (
                    extra_iters * ( iterations_per_worker + 1 )
                        +
                    plain_iters *   iterations_per_worker
                );
                auto const stop_iteration( start_iteration + iterations_per_worker + this_has_extra_iter );
                BOOST_ASSERT( stop_iteration <= iterations );
                BOOST_ASSERT_MSG( start_iteration < stop_iteration, "Sweater internal inconsistency: worker called with no work to do." );
                work( start_iteration, stop_iteration );
            }
        );

        /// \note dispatch_apply delegates to dispatch_apply_f so we avoid the
        /// small overhead of an extra jmp and block construction (as opposed to
        /// just a trivial lambda construction).
        ///                                   (04.10.2016.) (Domagoj Saric)
        /// \note The iteration_per_worker logic above does not fully cover the
        /// cases where the number of iterations is less than the number of
        /// workers (resulting in work being called with start_iteration >
        /// stop_iteration) so we have to additionally clamp the iterations
        /// parameter passed to dispatch_apply).
        ///                                   (12.01.2017.) (Domagoj Saric)
        dispatch_apply_f
        (
            std::min<iterations_t>( number_of_workers, iterations ),
            high_priority_queue,
            &worker,
            []( void * const p_context, std::size_t const worker_index ) noexcept
            {
                auto & __restrict the_worker( *static_cast<decltype( worker ) const *>( p_context ) );
                the_worker( static_cast<std::uint_fast8_t>( worker_index ) );
            }
        );
    }

    template <typename F>
    static void fire_and_forget( F && work ) noexcept
    {
        /// \note "ObjC++ attempts to copy lambdas, preventing capture of
        /// move-only types". https://llvm.org/bugs/show_bug.cgi?id=20534
        ///                                   (14.01.2016.) (Domagoj Saric)
        __block auto moveable_work( std::forward<F>( work ) );
        dispatch_async( high_priority_queue, ^(){ moveable_work(); } );
    }

    template <typename F>
    static auto dispatch( F && work )
    {
        using result_t = typename std::result_of<F()>::type;
        std::promise<result_t> promise;
        std::future<result_t> future( promise.get_future() );
        fire_and_forget
        (
            [promise = std::move( promise ), work = std::forward<F>( work )]
            () mutable { promise.set_value( work() ); }
        );
        return future;
    }

private:
    static dispatch_queue_t const default_queue      ;
    static dispatch_queue_t const high_priority_queue;
}; // struct impl

__attribute__(( weak )) dispatch_queue_t const impl::default_queue      ( dispatch_get_global_queue( QOS_CLASS_DEFAULT       , 0 ) );
__attribute__(( weak )) dispatch_queue_t const impl::high_priority_queue( dispatch_get_global_queue( QOS_CLASS_USER_INITIATED, 0 ) );

//------------------------------------------------------------------------------
} // namespace sweater
//------------------------------------------------------------------------------
} // namespace boost
//------------------------------------------------------------------------------
<commit_msg>added implementation of fire_and_forget for Apple platforms when using GCC<commit_after>////////////////////////////////////////////////////////////////////////////////
///
/// \file apple.hpp
/// ---------------
///
/// (c) Copyright Domagoj Saric 2016 - 2017.
///
///  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)
///
///  See http://www.boost.org for most recent version.
///
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
#pragma once
//------------------------------------------------------------------------------
#include <boost/assert.hpp>
#include <boost/config_ex.hpp>

#include <algorithm>
#include <cstdint>
#include <future>
#include <thread>
#include <type_traits>

#include <dispatch/dispatch.h>
#include <TargetConditionals.h>
//------------------------------------------------------------------------------
namespace boost
{
//------------------------------------------------------------------------------
namespace sweater
{
//------------------------------------------------------------------------------

#ifndef BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY
#if TARGET_OS_IOS
#   ifdef __aarch64__
#       define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 3 // iPad 2 Air
#   else
#       define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 2
#   endif
#else
#   define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 0
#endif
#endif // BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY

BOOST_OVERRIDABLE_SYMBOL
auto const hardware_concurrency( static_cast<std::uint_fast8_t>( std::thread::hardware_concurrency() ) );

class impl
{
public:
    using iterations_t = std::uint32_t;

    // http://newosxbook.com/articles/GCD.html
    // http://www.idryman.org/blog/2012/08/05/grand-central-dispatch-vs-openmp
    static auto number_of_workers() noexcept
    {
        BOOST_ASSERT_MSG( hardware_concurrency == std::thread::hardware_concurrency(), "Hardware concurrency changed at runtime!?" );
    #if BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY
        BOOST_ASSUME( hardware_concurrency <= BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY );
    #endif
        return hardware_concurrency;
    }

    template <typename F>
    static void spread_the_sweat( iterations_t const iterations, F && work ) noexcept
    {
        static_assert( noexcept( work( iterations, iterations ) ), "F must be noexcept" );

        /// \note Stride the iteration count based on the number of workers
        /// (otherwise dispatch_apply will make an indirect function call for
        /// each iteration).
        /// The iterations / number_of_workers is an integer division and can
        /// thus be 'lossy' so extra steps need to be taken to account for this.
        ///                                   (04.10.2016.) (Domagoj Saric)
        auto              const number_of_workers    ( impl::number_of_workers() );
        iterations_t      const iterations_per_worker( iterations / number_of_workers );
        std::uint_fast8_t const extra_iterations     ( iterations % number_of_workers );
        auto /*const*/ worker
        (
            [
                &work, iterations_per_worker, extra_iterations
            #ifndef NDEBUG
                , iterations
            #endif // !NDEBUG
            ]
            ( std::uint_fast8_t const worker_index ) noexcept
            {
                auto const extra_iters        ( std::min( worker_index, extra_iterations ) );
                auto const plain_iters        ( worker_index - extra_iters                 );
                auto const this_has_extra_iter( worker_index < extra_iterations            );
                auto const start_iteration
                (
                    extra_iters * ( iterations_per_worker + 1 )
                        +
                    plain_iters *   iterations_per_worker
                );
                auto const stop_iteration( start_iteration + iterations_per_worker + this_has_extra_iter );
                BOOST_ASSERT( stop_iteration <= iterations );
                BOOST_ASSERT_MSG( start_iteration < stop_iteration, "Sweater internal inconsistency: worker called with no work to do." );
                work( start_iteration, stop_iteration );
            }
        );

        /// \note dispatch_apply delegates to dispatch_apply_f so we avoid the
        /// small overhead of an extra jmp and block construction (as opposed to
        /// just a trivial lambda construction).
        ///                                   (04.10.2016.) (Domagoj Saric)
        /// \note The iteration_per_worker logic above does not fully cover the
        /// cases where the number of iterations is less than the number of
        /// workers (resulting in work being called with start_iteration >
        /// stop_iteration) so we have to additionally clamp the iterations
        /// parameter passed to dispatch_apply).
        ///                                   (12.01.2017.) (Domagoj Saric)
        dispatch_apply_f
        (
            std::min<iterations_t>( number_of_workers, iterations ),
            high_priority_queue,
            &worker,
            []( void * const p_context, std::size_t const worker_index ) noexcept
            {
                auto & __restrict the_worker( *static_cast<decltype( worker ) const *>( p_context ) );
                the_worker( static_cast<std::uint_fast8_t>( worker_index ) );
            }
        );
    }

    template <typename F>
    static void fire_and_forget( F && work ) noexcept
    {
#       if defined( __GLIBCXX__ )
            /// \note GCC on Mac does not support blocks, so we need to emulate
            /// the support. We must ensure work lives at the moment the lambda
            /// starts processing it, so we copy/move the work to heap and
            /// clean the memory after the work is done.
            ///                                   (30.05.2017.) (Nenad Miksa)
            /// \todo Avoid the copy/move to heap if F can be reduced to simple
            /// function pointer.
            auto heap_work = new decltype( work ){ std::forward< F >( work ) };
            dispatch_async_f
            (
                high_priority_queue,
                heap_work,
                []( void * const p_context ) noexcept
                {
                    auto & __restrict the_work( *static_cast<decltype( work ) const *>( p_context ) );
                    the_work();
                    delete &the_work;
                }
            );
#       else
            /// \note "ObjC++ attempts to copy lambdas, preventing capture of
            /// move-only types". https://llvm.org/bugs/show_bug.cgi?id=20534
            ///                                   (14.01.2016.) (Domagoj Saric)
            __block auto moveable_work( std::forward<F>( work ) );
            dispatch_async( high_priority_queue, ^(){ moveable_work(); } );
#       endif
    }

    template <typename F>
    static auto dispatch( F && work )
    {
        using result_t = typename std::result_of<F()>::type;
        std::promise<result_t> promise;
        std::future<result_t> future( promise.get_future() );
        fire_and_forget
        (
            [promise = std::move( promise ), work = std::forward<F>( work )]
            () mutable { promise.set_value( work() ); }
        );
        return future;
    }

private:
    static dispatch_queue_t const default_queue      ;
    static dispatch_queue_t const high_priority_queue;
}; // struct impl

__attribute__(( weak )) dispatch_queue_t const impl::default_queue      ( dispatch_get_global_queue( QOS_CLASS_DEFAULT       , 0 ) );
__attribute__(( weak )) dispatch_queue_t const impl::high_priority_queue( dispatch_get_global_queue( QOS_CLASS_USER_INITIATED, 0 ) );

//------------------------------------------------------------------------------
} // namespace sweater
//------------------------------------------------------------------------------
} // namespace boost
//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
///
/// \file apple.hpp
/// ---------------
///
/// (c) Copyright Domagoj Saric 2016.
///
///  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)
///
///  See http://www.boost.org for most recent version.
///
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
#pragma once
//------------------------------------------------------------------------------
#include <boost/assert.hpp>

#include <algorithm>
#include <cstdint>
#include <future>
#include <thread>
#include <type_traits>

#include <dispatch/dispatch.h>
//------------------------------------------------------------------------------
namespace boost
{
//------------------------------------------------------------------------------
namespace sweater
{
//------------------------------------------------------------------------------

#ifndef BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY
#if defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
#	define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 3 // iPad 2 Air
#else
#	define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 0
#endif
#endif // BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY

BOOST_OVERRIDABLE_SYMBOL
auto const hardware_concurrency( static_cast<std::uint8_t>( std::thread::hardware_concurrency() ) );

class impl
{
public:
	// http://www.idryman.org/blog/2012/08/05/grand-central-dispatch-vs-openmp
	static auto number_of_workers() noexcept
    {
    #if BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY
        BOOST_ASSUME( hardware_concurrency <= BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY );
    #endif
        return hardware_concurrency;
    }

	template <typename F>
	static void spread_the_sweat( std::uint16_t const iterations, F && work ) noexcept
	{
		static_assert( noexcept( work( iterations, iterations ) ), "F must be noexcept" );

        /// \note Stride the iteration count based on the number of workers
        /// (otherwise dispatch_apply will make an indirect function call for
        /// each iteration).
        /// The iterations / number_of_workers is an integer division and can
        /// thus be 'lossy' so extra steps need to be taken to account for this.
        ///                                   (04.10.2016.) (Domagoj Saric)
        auto          const number_of_workers    ( impl::number_of_workers() );
        std::uint16_t const iterations_per_worker( iterations / number_of_workers );
        std::uint8_t  const extra_iterations     ( iterations % number_of_workers );
        auto /*const*/ worker
        (
            [
                &work, iterations_per_worker, extra_iterations
            #ifndef NDEBUG
                , iterations
            #endif // !NDEBUG
            ]
            ( std::uint8_t const worker_index ) noexcept
            {
                auto const extra_iters        ( std::min( worker_index, extra_iterations ) );
                auto const plain_iters        ( worker_index - extra_iters                 );
                auto const this_has_extra_iter( worker_index < extra_iterations            );
                auto const start_iteration
                (
                    extra_iters * ( iterations_per_worker + 1 )
                        +
                    plain_iters *   iterations_per_worker
                );
                auto const stop_iteration( start_iteration + iterations_per_worker + this_has_extra_iter );
                BOOST_ASSERT( stop_iteration <= iterations );
                BOOST_ASSERT_MSG( start_iteration < stop_iteration, "Sweater internal inconsistency: worker called with no work to do." );
                work( start_iteration, stop_iteration );
            }
        );

        /// \note dispatch_apply delegates to dispatch_apply_f so we avoid the
        /// small overhead of an extra jmp and block construction (as opposed to
        /// just a trivial lambda construction).
        ///                                   (04.10.2016.) (Domagoj Saric)
        /// \note The iteration_per_worker logic above does not fully cover the
        /// cases where the number of iterations is less than the number of
        /// workers (resulting in work being called with start_iteration >
        /// stop_iteration) so we have to additionally clamp the iterations
        /// parameter passed to dispatch_apply).
        ///                                   (12.01.2017.) (Domagoj Saric)
		dispatch_apply_f
		(
			std::min<std::uint16_t>( number_of_workers, iterations ),
            high_priority_queue,
            &worker,
            []( void * const p_context, std::size_t const worker_index ) noexcept
            {
                auto & __restrict the_worker( *static_cast<decltype( worker ) const *>( p_context ) );
                the_worker( static_cast<std::uint8_t>( worker_index ) );
            }
		);
	}

	template <typename F>
	static void fire_and_forget( F && work ) noexcept
	{
        /// \note "ObjC++ attempts to copy lambdas, preventing capture of
        /// move-only types". https://llvm.org/bugs/show_bug.cgi?id=20534
        ///                                   (14.01.2016.) (Domagoj Saric)
        __block auto moveable_work( std::forward<F>( work ) );
        dispatch_async( high_priority_queue, ^(){ moveable_work(); } );
	}

    template <typename F>
    static auto dispatch( F && work )
    {
        using result_t = typename std::result_of<F()>::type;
        std::promise<result_t> promise;
        std::future<result_t> future( promise.get_future() );
        fire_and_forget
        (
            [promise = std::move( promise ), work = std::forward<F>( work )]
            () mutable { promise.set_value( work() ); }
        );
        return future;
    }

private:
    static dispatch_queue_t const default_queue      ;
    static dispatch_queue_t const high_priority_queue;
}; // struct impl

__attribute__(( weak )) dispatch_queue_t const impl::default_queue      ( dispatch_get_global_queue( QOS_CLASS_DEFAULT       , 0 ) );
__attribute__(( weak )) dispatch_queue_t const impl::high_priority_queue( dispatch_get_global_queue( QOS_CLASS_USER_INITIATED, 0 ) );

//------------------------------------------------------------------------------
} // namespace sweater
//------------------------------------------------------------------------------
} // namespace boost
//------------------------------------------------------------------------------<commit_msg>Added a missing include directive.<commit_after>////////////////////////////////////////////////////////////////////////////////
///
/// \file apple.hpp
/// ---------------
///
/// (c) Copyright Domagoj Saric 2016.
///
///  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)
///
///  See http://www.boost.org for most recent version.
///
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
#pragma once
//------------------------------------------------------------------------------
#include <boost/assert.hpp>
#include <boost/config_ex.hpp>

#include <algorithm>
#include <cstdint>
#include <future>
#include <thread>
#include <type_traits>

#include <dispatch/dispatch.h>
//------------------------------------------------------------------------------
namespace boost
{
//------------------------------------------------------------------------------
namespace sweater
{
//------------------------------------------------------------------------------

#ifndef BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY
#if defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
#	define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 3 // iPad 2 Air
#else
#	define BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY 0
#endif
#endif // BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY

BOOST_OVERRIDABLE_SYMBOL
auto const hardware_concurrency( static_cast<std::uint8_t>( std::thread::hardware_concurrency() ) );

class impl
{
public:
	// http://www.idryman.org/blog/2012/08/05/grand-central-dispatch-vs-openmp
	static auto number_of_workers() noexcept
    {
    #if BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY
        BOOST_ASSUME( hardware_concurrency <= BOOST_SWEATER_MAX_HARDWARE_CONCURRENCY );
    #endif
        return hardware_concurrency;
    }

	template <typename F>
	static void spread_the_sweat( std::uint16_t const iterations, F && work ) noexcept
	{
		static_assert( noexcept( work( iterations, iterations ) ), "F must be noexcept" );

        /// \note Stride the iteration count based on the number of workers
        /// (otherwise dispatch_apply will make an indirect function call for
        /// each iteration).
        /// The iterations / number_of_workers is an integer division and can
        /// thus be 'lossy' so extra steps need to be taken to account for this.
        ///                                   (04.10.2016.) (Domagoj Saric)
        auto          const number_of_workers    ( impl::number_of_workers() );
        std::uint16_t const iterations_per_worker( iterations / number_of_workers );
        std::uint8_t  const extra_iterations     ( iterations % number_of_workers );
        auto /*const*/ worker
        (
            [
                &work, iterations_per_worker, extra_iterations
            #ifndef NDEBUG
                , iterations
            #endif // !NDEBUG
            ]
            ( std::uint8_t const worker_index ) noexcept
            {
                auto const extra_iters        ( std::min( worker_index, extra_iterations ) );
                auto const plain_iters        ( worker_index - extra_iters                 );
                auto const this_has_extra_iter( worker_index < extra_iterations            );
                auto const start_iteration
                (
                    extra_iters * ( iterations_per_worker + 1 )
                        +
                    plain_iters *   iterations_per_worker
                );
                auto const stop_iteration( start_iteration + iterations_per_worker + this_has_extra_iter );
                BOOST_ASSERT( stop_iteration <= iterations );
                BOOST_ASSERT_MSG( start_iteration < stop_iteration, "Sweater internal inconsistency: worker called with no work to do." );
                work( start_iteration, stop_iteration );
            }
        );

        /// \note dispatch_apply delegates to dispatch_apply_f so we avoid the
        /// small overhead of an extra jmp and block construction (as opposed to
        /// just a trivial lambda construction).
        ///                                   (04.10.2016.) (Domagoj Saric)
        /// \note The iteration_per_worker logic above does not fully cover the
        /// cases where the number of iterations is less than the number of
        /// workers (resulting in work being called with start_iteration >
        /// stop_iteration) so we have to additionally clamp the iterations
        /// parameter passed to dispatch_apply).
        ///                                   (12.01.2017.) (Domagoj Saric)
		dispatch_apply_f
		(
			std::min<std::uint16_t>( number_of_workers, iterations ),
            high_priority_queue,
            &worker,
            []( void * const p_context, std::size_t const worker_index ) noexcept
            {
                auto & __restrict the_worker( *static_cast<decltype( worker ) const *>( p_context ) );
                the_worker( static_cast<std::uint8_t>( worker_index ) );
            }
		);
	}

	template <typename F>
	static void fire_and_forget( F && work ) noexcept
	{
        /// \note "ObjC++ attempts to copy lambdas, preventing capture of
        /// move-only types". https://llvm.org/bugs/show_bug.cgi?id=20534
        ///                                   (14.01.2016.) (Domagoj Saric)
        __block auto moveable_work( std::forward<F>( work ) );
        dispatch_async( high_priority_queue, ^(){ moveable_work(); } );
	}

    template <typename F>
    static auto dispatch( F && work )
    {
        using result_t = typename std::result_of<F()>::type;
        std::promise<result_t> promise;
        std::future<result_t> future( promise.get_future() );
        fire_and_forget
        (
            [promise = std::move( promise ), work = std::forward<F>( work )]
            () mutable { promise.set_value( work() ); }
        );
        return future;
    }

private:
    static dispatch_queue_t const default_queue      ;
    static dispatch_queue_t const high_priority_queue;
}; // struct impl

__attribute__(( weak )) dispatch_queue_t const impl::default_queue      ( dispatch_get_global_queue( QOS_CLASS_DEFAULT       , 0 ) );
__attribute__(( weak )) dispatch_queue_t const impl::high_priority_queue( dispatch_get_global_queue( QOS_CLASS_USER_INITIATED, 0 ) );

//------------------------------------------------------------------------------
} // namespace sweater
//------------------------------------------------------------------------------
} // namespace boost
//------------------------------------------------------------------------------<|endoftext|>


<commit_before>/*
** File Name: list_operations.hpp
** Author:    Aditya Ramesh
** Date:      08/05/2015
** Contact:   _@adityaramesh.com
**
** Advanced list operations that are easier to implement using `functional.hpp`.
*/

#ifndef ZA52A5035_94F1_4F4E_9587_BD2A3D87A4E3
#define ZA52A5035_94F1_4F4E_9587_BD2A3D87A4E3

namespace cc {
namespace mpl {

/*
** Functions for subindexing.
*/

/*
** Creates a new list from the elements at the given indices in the given list.
*/
template <class List, class... Indices>
using select = fold<
	list<Indices...>,
	list<>,
	compose<
		quote<list>,
		quote<reverse>,
		uncurry<make_list<
			bind_back<quote<at>, List>,
			quote_trait<id>
		>>,
		uncurry<quote<append>>
	>
>;

template <class List, list_index... Indices>
using select_c = select<List, list_index_c<Indices>...>;

template <class Start, class End>
using range = fold<
	repeat_n<minus<End, Start>, void>,
	list<Start>,
	compose<
		quote<list>,
		bind_back<quote<select>, list_index_c<0>, list_index_c<0>>,
		uncurry<make_list<
			compose<quote<back>, quote<inc>>,
			quote_trait<id>
		>>,
		uncurry<quote<append>>
	>
>;

template <class T, T Start, T End>
using range_c = range<
	std::integral_constant<T, Start>,
	std::integral_constant<T, End>
>;

template <class Start, class End, class List>
using slice = apply_list<
	bind_front<quote<select>, List>,
	range<Start, End>
>;

template <list_index Start, list_index End, class List>
using slice_c = slice<list_index_c<Start>, list_index_c<End>, List>;

namespace detail {

template <class N, class Size, class List>
struct erase_front_n_helper
{ using type = slice<N, dec<size<List>>, List>; };

template <class N, class List>
struct erase_front_n_helper<N, N, List>
{ using type = list<>; };

template <class N, class Size, class List>
struct erase_back_n_helper
{ using type = slice<list_index_c<0>, minus<dec<size<List>>, N>, List>; };

template <class N, class List>
struct erase_back_n_helper<N, N, List>
{ using type = list<>; };

}

template <class N, class List>
using erase_front_n = _t<detail::erase_front_n_helper<N, size<List>, List>>;

template <class N, class List>
using erase_back_n = _t<detail::erase_back_n_helper<N, size<List>, List>>;

template <list_index N, class List>
using erase_front_nc = erase_front_n<list_index_c<N>, List>;

template <list_index N, class List>
using erase_back_nc = erase_back_n<list_index_c<N>, List>;

/*
** Generalizations of basic list operations.
**
** TODO:
** - erase_if
** - replace_if
** - find_all
** - sort, unique
*/

namespace detail {

template <list_index Index, class Func, class List>
struct find_if_helper;

template <list_index Index, class Func>
struct find_if_helper<Index, Func, list<>>
{ using type = no_match; };

template <list_index Index, class Func, class Head, class... Tail>
struct find_if_helper<Index, Func, list<Head, Tail...>> :
if_<
	apply<Func, Head>, id<list_index_c<Index>>,
	find_if_helper<Index + 1, Func, list<Tail...>>
> {};

}

template <class Func, class List>
using find_if = _t<detail::find_if_helper<0, Func, List>>;

/*
** List comparison.
*/

namespace detail {

template <bool LengthsEqual, class List1, class List2>
struct lists_same_helper;

template <class List1, class List2>
struct lists_same_helper<false, List1, List2>
{ using type = bool_<false>; };

template <class... Ts, class... Us>
struct lists_same_helper<true, list<Ts...>, list<Us...>>
{ using type = and_c<std::is_same<Ts, Us>::value...>; };

}

template <class List1, class List2>
using lists_same = _t<detail::lists_same_helper<
	List1::size == List2::size, List1, List2
>>;

namespace detail {

template <bool MatchPossible, class Query, class List>
struct starts_with_helper;

template <class Query, class List>
struct starts_with_helper<false, Query, List>
{ using type = bool_<false>; };

template <class Query, class List>
struct starts_with_helper<true, Query, List>
{ using type = lists_same<Query, slice_c<0, Query::size - 1, List>>; };

}

template <class Query, class List>
using starts_with = _t<detail::starts_with_helper<
	Query::size <= List::size, Query, List
>>;

}}

#endif
<commit_msg>Added step size to range operation.<commit_after>/*
** File Name: list_operations.hpp
** Author:    Aditya Ramesh
** Date:      08/05/2015
** Contact:   _@adityaramesh.com
**
** Advanced list operations that are easier to implement using `functional.hpp`.
*/

#ifndef ZA52A5035_94F1_4F4E_9587_BD2A3D87A4E3
#define ZA52A5035_94F1_4F4E_9587_BD2A3D87A4E3

namespace cc {
namespace mpl {

/*
** Functions for subindexing.
*/

/*
** Creates a new list from the elements at the given indices in the given list.
*/
template <class List, class... Indices>
using select = fold<
	list<Indices...>,
	list<>,
	compose<
		quote<list>,
		quote<reverse>,
		uncurry<make_list<
			bind_back<quote<at>, List>,
			quote_trait<id>
		>>,
		uncurry<quote<append>>
	>
>;

template <class List, list_index... Indices>
using select_c = select<List, list_index_c<Indices>...>;

template <class Start, class End, class Inc = mpl::int_<1>>
using range = fold<
	repeat_n<divides<minus<End, Start>, Inc>, void>,
	list<Start>,
	compose<
		quote<list>,
		bind_back<quote<select>, list_index_c<0>, list_index_c<0>>,
		uncurry<make_list<
			compose<quote<back>, bind_back<quote<plus>, Inc>>,
			quote_trait<id>
		>>,
		uncurry<quote<append>>
	>
>;

template <class T, T Start, T End, T Inc = 1>
using range_c = range<
	std::integral_constant<T, Start>,
	std::integral_constant<T, End>,
	std::integral_constant<T, Inc>
>;

template <class Start, class End, class List>
using slice = apply_list<
	bind_front<quote<select>, List>,
	range<Start, End>
>;

template <list_index Start, list_index End, class List>
using slice_c = slice<list_index_c<Start>, list_index_c<End>, List>;

namespace detail {

template <class N, class Size, class List>
struct erase_front_n_helper
{ using type = slice<N, dec<size<List>>, List>; };

template <class N, class List>
struct erase_front_n_helper<N, N, List>
{ using type = list<>; };

template <class N, class Size, class List>
struct erase_back_n_helper
{ using type = slice<list_index_c<0>, minus<dec<size<List>>, N>, List>; };

template <class N, class List>
struct erase_back_n_helper<N, N, List>
{ using type = list<>; };

}

template <class N, class List>
using erase_front_n = _t<detail::erase_front_n_helper<N, size<List>, List>>;

template <class N, class List>
using erase_back_n = _t<detail::erase_back_n_helper<N, size<List>, List>>;

template <list_index N, class List>
using erase_front_nc = erase_front_n<list_index_c<N>, List>;

template <list_index N, class List>
using erase_back_nc = erase_back_n<list_index_c<N>, List>;

/*
** Generalizations of basic list operations.
**
** TODO:
** - erase_if
** - replace_if
** - find_all
** - sort, unique
*/

namespace detail {

template <list_index Index, class Func, class List>
struct find_if_helper;

template <list_index Index, class Func>
struct find_if_helper<Index, Func, list<>>
{ using type = no_match; };

template <list_index Index, class Func, class Head, class... Tail>
struct find_if_helper<Index, Func, list<Head, Tail...>> :
if_<
	apply<Func, Head>, id<list_index_c<Index>>,
	find_if_helper<Index + 1, Func, list<Tail...>>
> {};

}

template <class Func, class List>
using find_if = _t<detail::find_if_helper<0, Func, List>>;

/*
** List comparison.
*/

namespace detail {

template <bool LengthsEqual, class List1, class List2>
struct lists_same_helper;

template <class List1, class List2>
struct lists_same_helper<false, List1, List2>
{ using type = bool_<false>; };

template <class... Ts, class... Us>
struct lists_same_helper<true, list<Ts...>, list<Us...>>
{ using type = and_c<std::is_same<Ts, Us>::value...>; };

}

template <class List1, class List2>
using lists_same = _t<detail::lists_same_helper<
	List1::size == List2::size, List1, List2
>>;

namespace detail {

template <bool MatchPossible, class Query, class List>
struct starts_with_helper;

template <class Query, class List>
struct starts_with_helper<false, Query, List>
{ using type = bool_<false>; };

template <class Query, class List>
struct starts_with_helper<true, Query, List>
{ using type = lists_same<Query, slice_c<0, Query::size - 1, List>>; };

}

template <class Query, class List>
using starts_with = _t<detail::starts_with_helper<
	Query::size <= List::size, Query, List
>>;

}}

#endif
<|endoftext|>


<commit_before><commit_msg>Add some limits to incoming audio stream requests to avoid allocating massive buffers.<commit_after><|endoftext|>


<commit_before>#include "PopulationNode.hpp"
#pragma once

class PopulationNodeFactory {
	private:

	protected:

	public:
	template <typename NodeType, typename... params>
	static PopulationNode * createNode(
		unsigned int populationSize,
		std::vector<Locus*> loci,
		std::vector<ObjectiveFunction*> objectives,
		ToStringFunction * populationToString,
		std::vector<EndCondition*> conditions,
		std::string nodeName,
		unsigned int accelerationFactor,
		params... as
	);

	template <typename NodeType, typename... params>
	static std::vector<PopulationNode *> createNodes(
		unsigned int numNodes,
		unsigned int populationSize,
		std::vector<Locus*> loci,
		std::vector<ObjectiveFunction*> objectives,
		ToStringFunction * populationToString,
		std::vector<EndCondition*> conditions,
		std::string nodeName,
		unsigned int accelerationFactor,
		params... as
	);
};

template<typename NodeType, typename... params>
PopulationNode * PopulationNodeFactory::createNode(
	unsigned int populationSize,
	std::vector<Locus*> loci,
	std::vector<ObjectiveFunction*> objectives,
	ToStringFunction * populationToString,
	std::vector<EndCondition*> conditions,
	std::string nodeName,
	unsigned int accelerationFactor,
	params... as
) {
	static_assert(
		std::is_base_of<PopulationNode, NodeType>::value,
		"Type provided to population factory is not a population node!"
	);
	return new NodeType(
		populationSize,
		loci,
		objectives,
		populationToString,
		conditions,
		nodeName,
		accelerationFactor,
		as...
	);
}

template <typename NodeType, typename... params>
std::vector<PopulationNode *> PopulationNodeFactory::createNodes(
	unsigned int numNodes,
	unsigned int populationSize,
	std::vector<Locus*> loci,
	std::vector<ObjectiveFunction*> objectives,
	ToStringFunction * populationToString,
	std::vector<EndCondition*> conditions,
	std::string nodeName,
	unsigned int accelerationFactor,
	params... as
) {
	std::vector<PopulationNode*> nodes;
	for (unsigned int i = 0; i < numNodes; i++)
		nodes.push_back(PopulationNodeFactory::createNode<NodeType>(
			populationSize,
			loci,
			objectives,
			populationToString,
			conditions,
			nodeName,
			accelerationFactor,
			as...
		));

	return nodes;
}
<commit_msg>[PopulationNodeFactory]: Made arguments list more logical<commit_after>#include "PopulationNode.hpp"
#pragma once

class PopulationNodeFactory {
	private:

	protected:

	public:
	template <typename NodeType, typename... params>
	static PopulationNode * createNode(
		unsigned int populationSize,
		std::vector<Locus*> loci,
		std::vector<ObjectiveFunction*> objectives,
		ToStringFunction * populationToString,
		std::vector<EndCondition*> conditions,
		std::string nodeName,
		unsigned int accelerationFactor,
		params... as
	);

	template <typename NodeType, typename... params>
	static std::vector<PopulationNode *> createNodes(
		unsigned int populationSize,
		std::vector<Locus*> loci,
		std::vector<ObjectiveFunction*> objectives,
		ToStringFunction * populationToString,
		std::vector<EndCondition*> conditions,
		std::vector<std::string> nodeNames,
		unsigned int accelerationFactor,
		params... as
	);
};

template<typename NodeType, typename... params>
PopulationNode * PopulationNodeFactory::createNode(
	unsigned int populationSize,
	std::vector<Locus*> loci,
	std::vector<ObjectiveFunction*> objectives,
	ToStringFunction * populationToString,
	std::vector<EndCondition*> conditions,
	std::string nodeName,
	unsigned int accelerationFactor,
	params... as
) {
	static_assert(
		std::is_base_of<PopulationNode, NodeType>::value,
		"Type provided to population factory is not a population node!"
	);
	return new NodeType(
		populationSize,
		loci,
		objectives,
		populationToString,
		conditions,
		nodeName,
		accelerationFactor,
		as...
	);
}

template <typename NodeType, typename... params>
std::vector<PopulationNode *> PopulationNodeFactory::createNodes(
	unsigned int populationSize,
	std::vector<Locus*> loci,
	std::vector<ObjectiveFunction*> objectives,
	ToStringFunction * populationToString,
	std::vector<EndCondition*> conditions,
	std::vector<std::string> nodeNames,
	unsigned int accelerationFactor,
	params... as
) {
	std::vector<PopulationNode*> nodes;
	for (unsigned int i = 0; i < nodeNames.size(); i++)
		nodes.push_back(PopulationNodeFactory::createNode<NodeType>(
			populationSize,
			loci,
			objectives,
			populationToString,
			conditions,
			nodeName,
			accelerationFactor,
			as...
		));

	return nodes;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DBN_CONTRASTIVE_DIVERGENCE_HPP
#define DBN_CONTRASTIVE_DIVERGENCE_HPP

#include "assert.hpp"
#include "batch.hpp"

namespace dbn {

template<typename RBM>
struct base_cd_trainer {
    typedef RBM rbm_t;

    static constexpr const auto num_hidden = rbm_t::num_hidden;
    static constexpr const auto num_visible = rbm_t::num_visible;

    static constexpr const std::size_t num_visible_mom = rbm_t::Momentum ? num_visible : 0;
    static constexpr const std::size_t num_hidden_mom = rbm_t::Momentum ? num_hidden : 0;

    typedef typename rbm_t::weight weight;

    //Gradients
    fast_matrix<weight, num_visible, num_hidden> w_grad;
    fast_vector<weight, num_visible> vbias_grad;
    fast_vector<weight, num_hidden> hbias_grad;

    //Weights and biases for momentum
    fast_matrix<weight, num_visible_mom, num_hidden_mom> w_inc;
    fast_vector<weight, num_visible_mom> a_inc;
    fast_vector<weight, num_hidden_mom> b_inc;

    template<bool M = rbm_t::Momentum, typename std::enable_if<(!M), bool>::type = false>
    base_cd_trainer(){
        static_assert(!rbm_t::Momentum, "This constructor should only be used without momentum support");
    }

    template<bool M = rbm_t::Momentum, typename std::enable_if<(M), bool>::type = false>
    base_cd_trainer() : w_inc(0.0), a_inc(0.0), b_inc(0.0) {
        static_assert(rbm_t::Momentum, "This constructor should only be used with momentum support");
    }

    void update_weights(RBM& rbm){
        auto learning_rate = rbm.learning_rate;

        //Update weights
        if(rbm_t::Momentum){
            if(rbm_t::Decay){
                w_inc = w_inc * rbm.momentum + w_grad - (rbm.w * rbm.weight_cost);
            } else {
                w_inc = w_inc * rbm.momentum + w_grad;
            }

            rbm.w += learning_rate * w_inc;
        } else {
            if(rbm_t::Decay){
                rbm.w += learning_rate * (w_grad - (rbm.w * rbm.weight_cost));
            } else {
                rbm.w += learning_rate * w_grad;
            }
        }

        //Update visible biases
        if(rbm_t::Momentum){
            a_inc = a_inc * rbm.momentum + vbias_grad;
            rbm.a += learning_rate * a_inc;
        } else {
            rbm.a += learning_rate * vbias_grad;
        }

        //Update hidden biases
        if(rbm_t::Momentum){
            b_inc = b_inc * rbm.momentum + hbias_grad;
            rbm.b += learning_rate * b_inc;
        } else {
            rbm.b += learning_rate * hbias_grad;
        }

        //Check for NaN
        nan_check_3(rbm.w, rbm.a, rbm.b);
    }
};

template<std::size_t K, typename RBM>
struct cd_trainer : base_cd_trainer<RBM> {
private:
    static_assert(K > 0, "CD-0 is not a valid training method");

    typedef RBM rbm_t;
    typedef typename rbm_t::weight weight;

    using base_cd_trainer<RBM>::num_visible;
    using base_cd_trainer<RBM>::num_hidden;

    using base_cd_trainer<RBM>::w_grad;
    using base_cd_trainer<RBM>::vbias_grad;
    using base_cd_trainer<RBM>::hbias_grad;

public:
    cd_trainer() : base_cd_trainer<RBM>() {
        //Nothing else to init here
    }

    template<typename T>
    weight train_batch(const dbn::batch<T>& batch, RBM& rbm){
        dbn_assert(batch.size() <= static_cast<typename dbn::batch<T>::size_type>(BatchSize), "Invalid size");
        dbn_assert(batch[0].size() == num_visible, "The size of the training sample must match visible units");

        //Size of a minibatch
        auto n_samples = static_cast<weight>(batch.size());

        //Clear the gradients
        vbias_grad = 0.0;
        hbias_grad = 0.0;
        w_grad = 0.0;

        for(auto& items : batch){
            rbm.v1 = items;

            //First step
            rbm.activate_hidden(rbm.h1_a, rbm.h1_s, rbm.v1, rbm.v1);

            //CD-1
            rbm.activate_visible(rbm.h1_a, rbm.h1_s, rbm.v2_a, rbm.v2_s);
            rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);

            //CD-k
            for(std::size_t k = 1; k < K; ++k){
                rbm.activate_visible(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);
                rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);
            }

            for(size_t i = 0; i < num_visible; ++i){
                for(size_t j = 0; j < num_hidden; ++j){
                    w_grad(i, j) += rbm.h1_a(j) * rbm.v1(i) - rbm.h2_a(j) * rbm.v2_a(i);
                }
            }

            vbias_grad += rbm.v1 - rbm.v2_a;
            hbias_grad += rbm.h1_a - rbm.h2_a;
        }

        //Keep only the mean of the gradients
        w_grad /= n_samples;
        vbias_grad /= n_samples;
        hbias_grad /= n_samples;

        nan_check_3(w_grad, vbias_grad, hbias_grad);

        //Update the weights and biases based on the gradients
        this->update_weights(rbm);

        //Compute the reconstruction error

        weight error = 0.0;
        for(size_t i = 0; i < num_visible; ++i){
            error += vbias_grad(i) * vbias_grad(i);
        }
        error = sqrt(error / num_visible);

        return error;
    }
};

template<std::size_t K, typename RBM>
struct persistent_cd_trainer : base_cd_trainer<RBM> {
private:
    static_assert(K > 0, "PCD-0 is not a valid training method");

    typedef RBM rbm_t;
    typedef typename rbm_t::weight weight;

    using base_cd_trainer<RBM>::num_visible;
    using base_cd_trainer<RBM>::num_hidden;

    using base_cd_trainer<RBM>::w_grad;
    using base_cd_trainer<RBM>::vbias_grad;
    using base_cd_trainer<RBM>::hbias_grad;

    std::vector<fast_vector<weight, num_hidden>> p_h_a;
    std::vector<fast_vector<weight, num_hidden>> p_h_s;

public:
    persistent_cd_trainer() : base_cd_trainer<RBM>() {
        //Nothing else to init here
    }

    template<typename T>
    weight train_batch(const dbn::batch<T>& batch, RBM& rbm){
        dbn_assert(batch.size() <= static_cast<typename dbn::batch<T>::size_type>(rbm_t::BatchSize), "Invalid size");
        dbn_assert(batch[0].size() == num_visible, "The size of the training sample must match visible units");

        //Size of a minibatch
        auto n_samples = static_cast<weight>(batch.size());

        //Clear the gradients
        vbias_grad = 0.0;
        hbias_grad = 0.0;
        w_grad = 0.0;

        bool init = p_h_a.empty();;
        if(init){
            p_h_a.resize(static_cast<typename dbn::batch<T>::size_type>(rbm_t::BatchSize));
            p_h_s.resize(static_cast<typename dbn::batch<T>::size_type>(rbm_t::BatchSize));
        }

        for(std::size_t i = 0; i < batch.size(); ++i){
            auto& items = batch[i];

            rbm.v1 = items;

            //First step
            rbm.activate_hidden(rbm.h1_a, rbm.h1_s, rbm.v1, rbm.v1);

            if(init){
                p_h_a[i] = rbm.h1_a;
                p_h_s[i] = rbm.h1_s;
            }

            //CD-1
            rbm.activate_visible(p_h_a[i], p_h_a[i], rbm.v2_a, rbm.v2_s);
            rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);

            //CD-k
            for(std::size_t k = 1; k < K; ++k){
                rbm.activate_visible(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);
                rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);
            }

            p_h_a[i] = rbm.h2_a;
            p_h_s[i] = rbm.h2_s;

            for(size_t i = 0; i < num_visible; ++i){
                for(size_t j = 0; j < num_hidden; ++j){
                    w_grad(i, j) += rbm.h1_a(j) * rbm.v1(i) - rbm.h2_a(j) * rbm.v2_a(i);
                }
            }

            vbias_grad += rbm.v1 - rbm.v2_a;
            hbias_grad += rbm.h1_a - rbm.h2_a;
        }

        //Keep only the mean of the gradients
        w_grad /= n_samples;
        vbias_grad /= n_samples;
        hbias_grad /= n_samples;

        nan_check_3(w_grad, vbias_grad, hbias_grad);

        //Update the weights and biases based on the gradients
        this->update_weights(rbm);

        //Compute the reconstruction error

        weight error = 0.0;
        for(size_t i = 0; i < num_visible; ++i){
            error += vbias_grad(i) * vbias_grad(i);
        }
        error = sqrt(error / num_visible);

        return error;
    }
};

} //end of dbn namespace

#endif<commit_msg>Do not apply weight decay on grad_old directly<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DBN_CONTRASTIVE_DIVERGENCE_HPP
#define DBN_CONTRASTIVE_DIVERGENCE_HPP

#include "assert.hpp"
#include "batch.hpp"

namespace dbn {

template<typename RBM>
struct base_cd_trainer {
    typedef RBM rbm_t;

    static constexpr const auto num_hidden = rbm_t::num_hidden;
    static constexpr const auto num_visible = rbm_t::num_visible;

    static constexpr const std::size_t num_visible_mom = rbm_t::Momentum ? num_visible : 0;
    static constexpr const std::size_t num_hidden_mom = rbm_t::Momentum ? num_hidden : 0;

    typedef typename rbm_t::weight weight;

    //Gradients
    fast_matrix<weight, num_visible, num_hidden> w_grad;
    fast_vector<weight, num_visible> vbias_grad;
    fast_vector<weight, num_hidden> hbias_grad;

    //Weights and biases for momentum
    fast_matrix<weight, num_visible_mom, num_hidden_mom> w_inc;
    fast_vector<weight, num_visible_mom> a_inc;
    fast_vector<weight, num_hidden_mom> b_inc;

    template<bool M = rbm_t::Momentum, typename std::enable_if<(!M), bool>::type = false>
    base_cd_trainer(){
        static_assert(!rbm_t::Momentum, "This constructor should only be used without momentum support");
    }

    template<bool M = rbm_t::Momentum, typename std::enable_if<(M), bool>::type = false>
    base_cd_trainer() : w_inc(0.0), a_inc(0.0), b_inc(0.0) {
        static_assert(rbm_t::Momentum, "This constructor should only be used with momentum support");
    }

    void update_weights(RBM& rbm){
        auto learning_rate = rbm.learning_rate;

        //Update momentum gradients
        if(rbm_t::Momentum){
            auto momentum = rbm.momentum;

            w_inc = momentum * w_inc + (1 - momentum) * w_grad;
            a_inc = momentum * a_inc + (1 - momentum) * vbias_grad;
            b_inc = momentum * b_inc + (1 - momentum) * hbias_grad;
        }

        //The final gradients;
        const auto& w_fgrad = rbm_t::Momentum ? w_inc : w_grad;
        const auto& a_fgrad = rbm_t::Momentum ? a_inc : vbias_grad;
        const auto& b_fgrad = rbm_t::Momentum ? b_inc : hbias_grad;

        //Weight decay is only applied to weights and not biases
        //Note: According to G. Hinton, Weight Decay should not be applied to
        //biases by default due to their limited number and therefore their weak
        //contribution to overfitting
        //TODO Perhaps this should be configurable

        //Update weights
        if(rbm_t::Decay){
            rbm.w += learning_rate * (w_fgrad - rbm.weight_cost * rbm.w);
        } else {
            rbm.w += learning_rate * w_fgrad;
        }

        //Update visible biases
        rbm.a += learning_rate * a_fgrad;

        //Update hidden biases
        rbm.b += learning_rate * b_fgrad;

        //Check for NaN
        nan_check_3(rbm.w, rbm.a, rbm.b);
    }
};

template<std::size_t K, typename RBM>
struct cd_trainer : base_cd_trainer<RBM> {
private:
    static_assert(K > 0, "CD-0 is not a valid training method");

    typedef RBM rbm_t;
    typedef typename rbm_t::weight weight;

    using base_cd_trainer<RBM>::num_visible;
    using base_cd_trainer<RBM>::num_hidden;

    using base_cd_trainer<RBM>::w_grad;
    using base_cd_trainer<RBM>::vbias_grad;
    using base_cd_trainer<RBM>::hbias_grad;

public:
    cd_trainer() : base_cd_trainer<RBM>() {
        //Nothing else to init here
    }

    template<typename T>
    weight train_batch(const dbn::batch<T>& batch, RBM& rbm){
        dbn_assert(batch.size() <= static_cast<typename dbn::batch<T>::size_type>(BatchSize), "Invalid size");
        dbn_assert(batch[0].size() == num_visible, "The size of the training sample must match visible units");

        //Size of a minibatch
        auto n_samples = static_cast<weight>(batch.size());

        //Clear the gradients
        vbias_grad = 0.0;
        hbias_grad = 0.0;
        w_grad = 0.0;

        for(auto& items : batch){
            rbm.v1 = items;

            //First step
            rbm.activate_hidden(rbm.h1_a, rbm.h1_s, rbm.v1, rbm.v1);

            //CD-1
            rbm.activate_visible(rbm.h1_a, rbm.h1_s, rbm.v2_a, rbm.v2_s);
            rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);

            //CD-k
            for(std::size_t k = 1; k < K; ++k){
                rbm.activate_visible(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);
                rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);
            }

            for(size_t i = 0; i < num_visible; ++i){
                for(size_t j = 0; j < num_hidden; ++j){
                    w_grad(i, j) += rbm.h1_a(j) * rbm.v1(i) - rbm.h2_a(j) * rbm.v2_a(i);
                }
            }

            vbias_grad += rbm.v1 - rbm.v2_a;
            hbias_grad += rbm.h1_a - rbm.h2_a;
        }

        //Keep only the mean of the gradients
        w_grad /= n_samples;
        vbias_grad /= n_samples;
        hbias_grad /= n_samples;

        nan_check_3(w_grad, vbias_grad, hbias_grad);

        //Update the weights and biases based on the gradients
        this->update_weights(rbm);

        //Compute the reconstruction error

        weight error = 0.0;
        for(size_t i = 0; i < num_visible; ++i){
            error += vbias_grad(i) * vbias_grad(i);
        }
        error = sqrt(error / num_visible);

        return error;
    }
};

template<std::size_t K, typename RBM>
struct persistent_cd_trainer : base_cd_trainer<RBM> {
private:
    static_assert(K > 0, "PCD-0 is not a valid training method");

    typedef RBM rbm_t;
    typedef typename rbm_t::weight weight;

    using base_cd_trainer<RBM>::num_visible;
    using base_cd_trainer<RBM>::num_hidden;

    using base_cd_trainer<RBM>::w_grad;
    using base_cd_trainer<RBM>::vbias_grad;
    using base_cd_trainer<RBM>::hbias_grad;

    std::vector<fast_vector<weight, num_hidden>> p_h_a;
    std::vector<fast_vector<weight, num_hidden>> p_h_s;

public:
    persistent_cd_trainer() : base_cd_trainer<RBM>() {
        //Nothing else to init here
    }

    template<typename T>
    weight train_batch(const dbn::batch<T>& batch, RBM& rbm){
        dbn_assert(batch.size() <= static_cast<typename dbn::batch<T>::size_type>(rbm_t::BatchSize), "Invalid size");
        dbn_assert(batch[0].size() == num_visible, "The size of the training sample must match visible units");

        //Size of a minibatch
        auto n_samples = static_cast<weight>(batch.size());

        //Clear the gradients
        vbias_grad = 0.0;
        hbias_grad = 0.0;
        w_grad = 0.0;

        bool init = p_h_a.empty();;
        if(init){
            p_h_a.resize(static_cast<typename dbn::batch<T>::size_type>(rbm_t::BatchSize));
            p_h_s.resize(static_cast<typename dbn::batch<T>::size_type>(rbm_t::BatchSize));
        }

        for(std::size_t i = 0; i < batch.size(); ++i){
            auto& items = batch[i];

            rbm.v1 = items;

            //First step
            rbm.activate_hidden(rbm.h1_a, rbm.h1_s, rbm.v1, rbm.v1);

            if(init){
                p_h_a[i] = rbm.h1_a;
                p_h_s[i] = rbm.h1_s;
            }

            //CD-1
            rbm.activate_visible(p_h_a[i], p_h_a[i], rbm.v2_a, rbm.v2_s);
            rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);

            //CD-k
            for(std::size_t k = 1; k < K; ++k){
                rbm.activate_visible(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);
                rbm.activate_hidden(rbm.h2_a, rbm.h2_s, rbm.v2_a, rbm.v2_s);
            }

            p_h_a[i] = rbm.h2_a;
            p_h_s[i] = rbm.h2_s;

            for(size_t i = 0; i < num_visible; ++i){
                for(size_t j = 0; j < num_hidden; ++j){
                    w_grad(i, j) += rbm.h1_a(j) * rbm.v1(i) - rbm.h2_a(j) * rbm.v2_a(i);
                }
            }

            vbias_grad += rbm.v1 - rbm.v2_a;
            hbias_grad += rbm.h1_a - rbm.h2_a;
        }

        //Keep only the mean of the gradients
        w_grad /= n_samples;
        vbias_grad /= n_samples;
        hbias_grad /= n_samples;

        nan_check_3(w_grad, vbias_grad, hbias_grad);

        //Update the weights and biases based on the gradients
        this->update_weights(rbm);

        //Compute the reconstruction error

        weight error = 0.0;
        for(size_t i = 0; i < num_visible; ++i){
            error += vbias_grad(i) * vbias_grad(i);
        }
        error = sqrt(error / num_visible);

        return error;
    }
};

} //end of dbn namespace

#endif<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: xmlfiltertabpagexslt.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2004-12-13 12:25:53 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the License); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an AS IS basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_FRAME_XCONFIGMANAGER_HPP_
#include <com/sun/star/frame/XConfigManager.hpp>
#endif

#ifndef _FILEDLGHELPER_HXX
#include <sfx2/filedlghelper.hxx>
#endif

#ifndef _UNOTOOLS_LOCALFILEHELPER_HXX
#include <unotools/localfilehelper.hxx>
#endif

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif

#ifndef SVTOOLS_URIHELPER_HXX
#include <svtools/urihelper.hxx>
#endif

#include "xmlfiltertabpagexslt.hxx"
#include "xmlfiltertabpagexslt.hrc"
#include "xmlfiltersettingsdialog.hxx"
#include "xmlfilterhelpids.hrc"

using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::lang;

XMLFilterTabPageXSLT::XMLFilterTabPageXSLT( Window* pParent, ResMgr& rResMgr, const Reference< XMultiServiceFactory >& rxMSF ) :
    TabPage( pParent, ResId( RID_XML_FILTER_TABPAGE_XSLT, &rResMgr ) ),

    maFTDocType( this, ResId( FT_XML_DOCTYPE ) ),
    maEDDocType( this, ResId( ED_XML_DOCTYPE ) ),

    maFTDTDSchema( this, ResId( FT_XML_DTD_SCHEMA ) ),
    maEDDTDSchema( this, ResId( ED_XML_DTD_SCHEMA ), INET_PROT_FILE ),
    maPBDTDSchemaBrowse( this, ResId( ED_XML_DTD_SCHEMA_BROWSE ) ),

    maFTExportXSLT( this, ResId( FT_XML_EXPORT_XSLT ) ),
    maEDExportXSLT( this, ResId( ED_XML_EXPORT_XSLT ), INET_PROT_FILE ),
    maPBExprotXSLT( this, ResId( PB_XML_EXPORT_XSLT_BROWSE ) ),

    maFTImportXSLT( this, ResId( FT_XML_IMPORT_XSLT ) ),
    maEDImportXSLT( this, ResId( ED_XML_IMPORT_XSLT ), INET_PROT_FILE ),
    maPBImportXSLT( this, ResId( PB_XML_IMPORT_XSLT_BROWSE ) ),

    maFTImportTemplate( this, ResId( FT_XML_IMPORT_TEMPLATE ) ),
    maEDImportTemplate( this, ResId( ED_XML_IMPORT_TEMPLATE ), INET_PROT_FILE ),
    maPBImportTemplate( this, ResId( PB_XML_IMPORT_TEMPLATE_BROWSE ) ),

    sHTTPSchema( RTL_CONSTASCII_USTRINGPARAM( "http://" ) ),
    sSHTTPSchema( RTL_CONSTASCII_USTRINGPARAM( "shttp://" ) ),
    sFILESchema( RTL_CONSTASCII_USTRINGPARAM( "file://" ) ),
    sFTPSchema( RTL_CONSTASCII_USTRINGPARAM( "ftp://" ) ),
    sInstPath( RTL_CONSTASCII_USTRINGPARAM( "$(prog)/" ) )
{
    FreeResource();

    try
    {
        Reference< XConfigManager > xCfgMgr( rxMSF->createInstance(OUString::createFromAscii("com.sun.star.config.SpecialConfigManager")), UNO_QUERY );
        if( xCfgMgr.is() )
            sInstPath = xCfgMgr->substituteVariables( sInstPath );
    }
    catch(Exception&)
    {
        DBG_ERROR( "XMLFilterTabPageXSLT::XMLFilterTabPageXSLT exception catched!" );
    }

    maPBDTDSchemaBrowse.SetClickHdl( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) );
    maPBExprotXSLT.SetClickHdl( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) );
    maPBImportXSLT.SetClickHdl( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) );
    maPBImportTemplate.SetClickHdl( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) );

    maEDDTDSchema.SetHelpId( HID_XML_FILTER_DTD );
    maEDExportXSLT.SetHelpId( HID_XML_FILTER_EXPORT_XSLT );
    maEDImportXSLT.SetHelpId( HID_XML_FILTER_IMPORT_XSLT );
    maEDImportTemplate.SetHelpId( HID_XML_FILTER_IMPORT_TEMPLATE );
}

XMLFilterTabPageXSLT::~XMLFilterTabPageXSLT()
{
}

bool XMLFilterTabPageXSLT::FillInfo( filter_info_impl* pInfo )
{
    if( pInfo )
    {
        pInfo->maDocType = maEDDocType.GetText();
        pInfo->maDTD = GetURL( maEDDTDSchema );
        pInfo->maExportXSLT = GetURL( maEDExportXSLT );
        pInfo->maImportXSLT = GetURL( maEDImportXSLT );
        pInfo->maImportTemplate = GetURL( maEDImportTemplate );
    }

    return true;
}

void XMLFilterTabPageXSLT::SetInfo(const filter_info_impl* pInfo)
{
    if( pInfo )
    {
        maEDDocType.SetText( pInfo->maDocType );

        SetURL( maEDDTDSchema, pInfo->maDTD );
        SetURL( maEDExportXSLT, pInfo->maExportXSLT );
        SetURL( maEDImportXSLT, pInfo->maImportXSLT );
        SetURL( maEDImportTemplate, pInfo->maImportTemplate );
    }
}

void XMLFilterTabPageXSLT::SetURL( SvtURLBox& rURLBox, const OUString& rURL )
{
    OUString aPath;

    if( rURL.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "file://" ) ) ) )
    {
        osl::FileBase::getSystemPathFromFileURL( rURL, aPath );

        rURLBox.SetBaseURL( rURL );
        rURLBox.SetText( aPath );
    }
    else if( rURL.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "http://" ) ) ) ||
             rURL.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "shttp://" ) ) ) ||
             rURL.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "ftp://" ) ) ) )
    {
        rURLBox.SetBaseURL( rURL );
        rURLBox.SetText( rURL );
    }
    else if( rURL.getLength() )
    {
        rtl::OUString aURL( rURL );
        aURL = URIHelper::SmartRel2Abs( sInstPath, aURL, Link(), false );
        osl::FileBase::getSystemPathFromFileURL( aURL, aPath );

        rURLBox.SetBaseURL( aURL );
        rURLBox.SetText( aPath );
    }
    else
    {
        rURLBox.SetBaseURL( sInstPath );
        String aEmpty;
        rURLBox.SetText( aEmpty );
    }
}

OUString XMLFilterTabPageXSLT::GetURL( SvtURLBox& rURLBox )
{
    OUString aURL;
    OUString aStrPath ( rURLBox.GetText() );
    if( aStrPath.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "http://" ) ) ) ||
        aStrPath.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "shttp://" ) ) ) ||
        aStrPath.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "ftp://" ) ) ) )
    {
        return aStrPath;
    }
    else
    {
        const String aBaseURL ( rURLBox.GetBaseURL() );
        osl::FileBase::getFileURLFromSystemPath( aStrPath, aURL );
    }

    return aURL;
}

IMPL_LINK ( XMLFilterTabPageXSLT, ClickBrowseHdl_Impl, PushButton *, pButton )
{
    SvtURLBox* pURLBox;

    if( pButton == &maPBDTDSchemaBrowse )
    {
        pURLBox = &maEDDTDSchema;
    }
    else if( pButton == &maPBExprotXSLT )
    {
        pURLBox = &maEDExportXSLT;
    }
    else if( pButton == &maPBImportXSLT )
    {
        pURLBox = &maEDImportXSLT;
    }
    else
    {
        pURLBox = &maEDImportTemplate;
    }

    // Open Fileopen-Dialog
       ::sfx2::FileDialogHelper aDlg( ::sfx2::FILEOPEN_SIMPLE, 0 );

    aDlg.SetDisplayDirectory( GetURL( *pURLBox ) );

    if ( aDlg.Execute() == ERRCODE_NONE )
    {
        OUString aURL( aDlg.GetPath() );

        SetURL( *pURLBox, aURL );
    }

    return( 0L );
}

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.188); FILE MERGED 2005/09/05 14:32:00 rt 1.3.188.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: xmlfiltertabpagexslt.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 22:22:10 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_FRAME_XCONFIGMANAGER_HPP_
#include <com/sun/star/frame/XConfigManager.hpp>
#endif

#ifndef _FILEDLGHELPER_HXX
#include <sfx2/filedlghelper.hxx>
#endif

#ifndef _UNOTOOLS_LOCALFILEHELPER_HXX
#include <unotools/localfilehelper.hxx>
#endif

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif

#ifndef SVTOOLS_URIHELPER_HXX
#include <svtools/urihelper.hxx>
#endif

#include "xmlfiltertabpagexslt.hxx"
#include "xmlfiltertabpagexslt.hrc"
#include "xmlfiltersettingsdialog.hxx"
#include "xmlfilterhelpids.hrc"

using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::lang;

XMLFilterTabPageXSLT::XMLFilterTabPageXSLT( Window* pParent, ResMgr& rResMgr, const Reference< XMultiServiceFactory >& rxMSF ) :
    TabPage( pParent, ResId( RID_XML_FILTER_TABPAGE_XSLT, &rResMgr ) ),

    maFTDocType( this, ResId( FT_XML_DOCTYPE ) ),
    maEDDocType( this, ResId( ED_XML_DOCTYPE ) ),

    maFTDTDSchema( this, ResId( FT_XML_DTD_SCHEMA ) ),
    maEDDTDSchema( this, ResId( ED_XML_DTD_SCHEMA ), INET_PROT_FILE ),
    maPBDTDSchemaBrowse( this, ResId( ED_XML_DTD_SCHEMA_BROWSE ) ),

    maFTExportXSLT( this, ResId( FT_XML_EXPORT_XSLT ) ),
    maEDExportXSLT( this, ResId( ED_XML_EXPORT_XSLT ), INET_PROT_FILE ),
    maPBExprotXSLT( this, ResId( PB_XML_EXPORT_XSLT_BROWSE ) ),

    maFTImportXSLT( this, ResId( FT_XML_IMPORT_XSLT ) ),
    maEDImportXSLT( this, ResId( ED_XML_IMPORT_XSLT ), INET_PROT_FILE ),
    maPBImportXSLT( this, ResId( PB_XML_IMPORT_XSLT_BROWSE ) ),

    maFTImportTemplate( this, ResId( FT_XML_IMPORT_TEMPLATE ) ),
    maEDImportTemplate( this, ResId( ED_XML_IMPORT_TEMPLATE ), INET_PROT_FILE ),
    maPBImportTemplate( this, ResId( PB_XML_IMPORT_TEMPLATE_BROWSE ) ),

    sHTTPSchema( RTL_CONSTASCII_USTRINGPARAM( "http://" ) ),
    sSHTTPSchema( RTL_CONSTASCII_USTRINGPARAM( "shttp://" ) ),
    sFILESchema( RTL_CONSTASCII_USTRINGPARAM( "file://" ) ),
    sFTPSchema( RTL_CONSTASCII_USTRINGPARAM( "ftp://" ) ),
    sInstPath( RTL_CONSTASCII_USTRINGPARAM( "$(prog)/" ) )
{
    FreeResource();

    try
    {
        Reference< XConfigManager > xCfgMgr( rxMSF->createInstance(OUString::createFromAscii("com.sun.star.config.SpecialConfigManager")), UNO_QUERY );
        if( xCfgMgr.is() )
            sInstPath = xCfgMgr->substituteVariables( sInstPath );
    }
    catch(Exception&)
    {
        DBG_ERROR( "XMLFilterTabPageXSLT::XMLFilterTabPageXSLT exception catched!" );
    }

    maPBDTDSchemaBrowse.SetClickHdl( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) );
    maPBExprotXSLT.SetClickHdl( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) );
    maPBImportXSLT.SetClickHdl( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) );
    maPBImportTemplate.SetClickHdl( LINK ( this, XMLFilterTabPageXSLT, ClickBrowseHdl_Impl ) );

    maEDDTDSchema.SetHelpId( HID_XML_FILTER_DTD );
    maEDExportXSLT.SetHelpId( HID_XML_FILTER_EXPORT_XSLT );
    maEDImportXSLT.SetHelpId( HID_XML_FILTER_IMPORT_XSLT );
    maEDImportTemplate.SetHelpId( HID_XML_FILTER_IMPORT_TEMPLATE );
}

XMLFilterTabPageXSLT::~XMLFilterTabPageXSLT()
{
}

bool XMLFilterTabPageXSLT::FillInfo( filter_info_impl* pInfo )
{
    if( pInfo )
    {
        pInfo->maDocType = maEDDocType.GetText();
        pInfo->maDTD = GetURL( maEDDTDSchema );
        pInfo->maExportXSLT = GetURL( maEDExportXSLT );
        pInfo->maImportXSLT = GetURL( maEDImportXSLT );
        pInfo->maImportTemplate = GetURL( maEDImportTemplate );
    }

    return true;
}

void XMLFilterTabPageXSLT::SetInfo(const filter_info_impl* pInfo)
{
    if( pInfo )
    {
        maEDDocType.SetText( pInfo->maDocType );

        SetURL( maEDDTDSchema, pInfo->maDTD );
        SetURL( maEDExportXSLT, pInfo->maExportXSLT );
        SetURL( maEDImportXSLT, pInfo->maImportXSLT );
        SetURL( maEDImportTemplate, pInfo->maImportTemplate );
    }
}

void XMLFilterTabPageXSLT::SetURL( SvtURLBox& rURLBox, const OUString& rURL )
{
    OUString aPath;

    if( rURL.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "file://" ) ) ) )
    {
        osl::FileBase::getSystemPathFromFileURL( rURL, aPath );

        rURLBox.SetBaseURL( rURL );
        rURLBox.SetText( aPath );
    }
    else if( rURL.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "http://" ) ) ) ||
             rURL.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "shttp://" ) ) ) ||
             rURL.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "ftp://" ) ) ) )
    {
        rURLBox.SetBaseURL( rURL );
        rURLBox.SetText( rURL );
    }
    else if( rURL.getLength() )
    {
        rtl::OUString aURL( rURL );
        aURL = URIHelper::SmartRel2Abs( sInstPath, aURL, Link(), false );
        osl::FileBase::getSystemPathFromFileURL( aURL, aPath );

        rURLBox.SetBaseURL( aURL );
        rURLBox.SetText( aPath );
    }
    else
    {
        rURLBox.SetBaseURL( sInstPath );
        String aEmpty;
        rURLBox.SetText( aEmpty );
    }
}

OUString XMLFilterTabPageXSLT::GetURL( SvtURLBox& rURLBox )
{
    OUString aURL;
    OUString aStrPath ( rURLBox.GetText() );
    if( aStrPath.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "http://" ) ) ) ||
        aStrPath.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "shttp://" ) ) ) ||
        aStrPath.matchIgnoreAsciiCase( OUString( RTL_CONSTASCII_USTRINGPARAM( "ftp://" ) ) ) )
    {
        return aStrPath;
    }
    else
    {
        const String aBaseURL ( rURLBox.GetBaseURL() );
        osl::FileBase::getFileURLFromSystemPath( aStrPath, aURL );
    }

    return aURL;
}

IMPL_LINK ( XMLFilterTabPageXSLT, ClickBrowseHdl_Impl, PushButton *, pButton )
{
    SvtURLBox* pURLBox;

    if( pButton == &maPBDTDSchemaBrowse )
    {
        pURLBox = &maEDDTDSchema;
    }
    else if( pButton == &maPBExprotXSLT )
    {
        pURLBox = &maEDExportXSLT;
    }
    else if( pButton == &maPBImportXSLT )
    {
        pURLBox = &maEDImportXSLT;
    }
    else
    {
        pURLBox = &maEDImportTemplate;
    }

    // Open Fileopen-Dialog
       ::sfx2::FileDialogHelper aDlg( ::sfx2::FILEOPEN_SIMPLE, 0 );

    aDlg.SetDisplayDirectory( GetURL( *pURLBox ) );

    if ( aDlg.Execute() == ERRCODE_NONE )
    {
        OUString aURL( aDlg.GetPath() );

        SetURL( *pURLBox, aURL );
    }

    return( 0L );
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can 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.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_IMAGE_FILITER_PARSER_HPP
#define MAPNIK_IMAGE_FILITER_PARSER_HPP

#include <mapnik/image_filter.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <vector>

namespace mapnik {

namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;

template <typename Iterator, typename ContType>
struct image_filter_grammar :
        qi::grammar<Iterator, ContType(), qi::ascii::space_type>
{
    image_filter_grammar()
        : image_filter_grammar::base_type(start)
    {
        using qi::lit;
        using qi::_val;
        using qi::_1;
        using qi::_a;
        using qi::_b;
        using qi::eps;
        using qi::char_;
        using qi::no_skip;
        using phoenix::push_back;
        using phoenix::construct;

        start = -(filter % no_skip[*char_("; ")])
            ;
        filter =
            lit("emboss")[push_back(_val,construct<mapnik::filter::emboss>())]
            |
            lit("blur")[push_back(_val,construct<mapnik::filter::blur>())]
            |
            lit("gray")[push_back(_val,construct<mapnik::filter::gray>())]
            |
            lit("edge-detect")[push_back(_val,construct<mapnik::filter::edge_detect>())]
            |
            lit("sobel")[push_back(_val,construct<mapnik::filter::sobel>())]
            |
            lit("sharpen")[push_back(_val,construct<mapnik::filter::sharpen>())]
            |
            lit("x-gradient")[push_back(_val,construct<mapnik::filter::x_gradient>())]
            |
            lit("y-gradient")[push_back(_val,construct<mapnik::filter::y_gradient>())]
            |
            (lit("agg-stack-blur")[_a = 1, _b = 1]
             >> -( lit(':') >> lit("rx") >> lit('=') >> radius_[_a = _1]
                   >> lit(',')
                   >> lit("ry") >> lit('=') >> radius_[_b = _1])
             [push_back(_val,construct<mapnik::filter::agg_stack_blur>(_a,_b))])
            |
            lit("invert")[push_back(_val,construct<mapnik::filter::invert>())]
            ;
    }
    //
    qi::rule<Iterator, ContType(), qi::ascii::space_type> start;
    qi::rule<Iterator, ContType(), qi::locals<int,int>, qi::ascii::space_type> filter;
    qi::uint_parser< unsigned, 10, 1, 3 > radius_;
};

}

#endif // MAPNIK_IMAGE_FILITER_PARSER_HPP
<commit_msg>restore compile with boost < 1.47 - disables stacked image filters for now<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can 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.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_IMAGE_FILITER_PARSER_HPP
#define MAPNIK_IMAGE_FILITER_PARSER_HPP

#include <mapnik/image_filter.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <vector>

namespace mapnik {

namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;

template <typename Iterator, typename ContType>
struct image_filter_grammar :
        qi::grammar<Iterator, ContType(), qi::ascii::space_type>
{
    image_filter_grammar()
        : image_filter_grammar::base_type(start)
    {
        using qi::lit;
        using qi::_val;
        using qi::_1;
        using qi::_a;
        using qi::_b;
        using qi::eps;
        using qi::char_;
        using phoenix::push_back;
        using phoenix::construct;

#if BOOST_VERSION > 104600
        using qi::no_skip;
        start = -(filter % no_skip[*char_("; ")])
            ;
#else
        start = -(filter)
            ;
#endif

        filter =
            lit("emboss")[push_back(_val,construct<mapnik::filter::emboss>())]
            |
            lit("blur")[push_back(_val,construct<mapnik::filter::blur>())]
            |
            lit("gray")[push_back(_val,construct<mapnik::filter::gray>())]
            |
            lit("edge-detect")[push_back(_val,construct<mapnik::filter::edge_detect>())]
            |
            lit("sobel")[push_back(_val,construct<mapnik::filter::sobel>())]
            |
            lit("sharpen")[push_back(_val,construct<mapnik::filter::sharpen>())]
            |
            lit("x-gradient")[push_back(_val,construct<mapnik::filter::x_gradient>())]
            |
            lit("y-gradient")[push_back(_val,construct<mapnik::filter::y_gradient>())]
            |
            (lit("agg-stack-blur")[_a = 1, _b = 1]
             >> -( lit(':') >> lit("rx") >> lit('=') >> radius_[_a = _1]
                   >> lit(',')
                   >> lit("ry") >> lit('=') >> radius_[_b = _1])
             [push_back(_val,construct<mapnik::filter::agg_stack_blur>(_a,_b))])
            |
            lit("invert")[push_back(_val,construct<mapnik::filter::invert>())]
            ;
    }
    //
    qi::rule<Iterator, ContType(), qi::ascii::space_type> start;
    qi::rule<Iterator, ContType(), qi::locals<int,int>, qi::ascii::space_type> filter;
    qi::uint_parser< unsigned, 10, 1, 3 > radius_;
};

}

#endif // MAPNIK_IMAGE_FILITER_PARSER_HPP
<|endoftext|>


<commit_before>#include "sam.h"
#include "samSz.h"
#include <apfField.h>
#include <cassert>
#include <apfField.h>

namespace sam {

apf::Field* errorThreshold(apf::Mesh* m, const char* fieldName,
    const unsigned idx, const double limit, const double factor)
{
  apf::Field* f = m->findField(fieldName);
  assert(f);
  apf::synchronize(f);
  apf::Field* newSz = apf::createFieldOn(m,"specifiedIso",apf::SCALAR);
  apf::Field* curSz = samSz::isoSize(m);
  double* vals = new double[f->countComponents()];
  apf::MeshEntity* vtx;
  apf::MeshIterator* itr = m->begin(0);
  while( (vtx = m->iterate(itr)) ) {
    apf::getComponents(f, vtx, 0, vals);
    double h = apf::getScalar(curSz,vtx,0);
    if ( vals[idx] > limit )
      h *= factor;
    apf::setScalar(newSz,vtx,0,h);
  }
  m->end(itr);
  apf::destroyField(curSz);
  delete [] vals;
  return newSz;
}

apf::Field* specifiedIso(apf::Mesh* m, const char* fieldName, const unsigned idx)
{
  apf::Field* f = m->findField(fieldName);
  assert(f);
  apf::synchronize(f);
  apf::Field* newSz = apf::createFieldOn(m,"specifiedIso",apf::SCALAR);
  double* vals = new double[f->countComponents()];
  apf::MeshEntity* vtx;
  apf::MeshIterator* itr = m->begin(0);
  while( (vtx = m->iterate(itr)) ) {
    apf::getComponents(f, vtx, 0, vals);
    double h = vals[idx];
    apf::setScalar(newSz,vtx,0,h);
  }
  m->end(itr);
  delete [] vals;
  return newSz;
}

}
<commit_msg>backport sam.cc includes from core-sim<commit_after>#include "sam.h"
#include "samSz.h"
#include <apfField.h>
#include <cassert>
#include <stdio.h>

namespace sam {

apf::Field* errorThreshold(apf::Mesh* m, const char* fieldName,
    const unsigned idx, const double limit, const double factor)
{
  apf::Field* f = m->findField(fieldName);
  assert(f);
  apf::synchronize(f);
  apf::Field* newSz = apf::createFieldOn(m,"specifiedIso",apf::SCALAR);
  apf::Field* curSz = samSz::isoSize(m);
  double* vals = new double[f->countComponents()];
  apf::MeshEntity* vtx;
  apf::MeshIterator* itr = m->begin(0);
  while( (vtx = m->iterate(itr)) ) {
    apf::getComponents(f, vtx, 0, vals);
    double h = apf::getScalar(curSz,vtx,0);
    if ( vals[idx] > limit )
      h *= factor;
    apf::setScalar(newSz,vtx,0,h);
  }
  m->end(itr);
  apf::destroyField(curSz);
  delete [] vals;
  return newSz;
}

apf::Field* specifiedIso(apf::Mesh* m, const char* fieldName, const unsigned idx)
{
  apf::Field* f = m->findField(fieldName);
  assert(f);
  apf::synchronize(f);
  apf::Field* newSz = apf::createFieldOn(m,"specifiedIso",apf::SCALAR);
  double* vals = new double[f->countComponents()];
  apf::MeshEntity* vtx;
  apf::MeshIterator* itr = m->begin(0);
  while( (vtx = m->iterate(itr)) ) {
    apf::getComponents(f, vtx, 0, vals);
    double h = vals[idx];
    apf::setScalar(newSz,vtx,0,h);
  }
  m->end(itr);
  delete [] vals;
  return newSz;
}

}
<|endoftext|>


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

/*!
  \file topo_view.hpp
  \brief Reimplements foreach_node to guarantee topological order

  \author Mathias Soeken
*/

#pragma once

#include <vector>

#include "../traits.hpp"
#include "../networks/detail/foreach.hpp"
#include "immutable_view.hpp"

namespace mockturtle
{

/*! \brief Ensures topological order for the `foreach_node` interface method.
 *
 * This class computes *on construction* a topological order of the nodes which
 * are reachable from the outputs.  Constant nodes and primary inputs will also
 * be considered even if they are not reachable from the outputs.  Further,
 * constant nodes and primary inputs will be visited first before any gate node
 * is visited.  Constant nodes precede primary inputs, and primary inputs are
 * visited in the same order in which they were created.
 *
 * Since the topological order is computed only once when creating an instance,
 * this view disables changes to the networ interface.  Also, since only
 * reachable nodes are traversed, not all network nodes may be called in
 * `foreach_node`.
 *
 * **Required network functions:**
 * - `get_constant`
 * - `foreach_pi`
 * - `foreach_po`
 * - `foreach_fanin`
 * - `clear_values`
 * - `value`
 * - `set_value`
 *
 * Example
 *
   \verbatim embed:rst

   .. code-block:: c++

      // create network somehow; aig may not be in topological order
      aig_network aig = ...;

      // create a topological view on the network
      topo_view aig_topo{aig};

      // call algorithm that requires topological order
      cut_enumeration( aig_topo );
   \endverbatim
 */
template<typename Ntk>
class topo_view : public immutable_view<Ntk>
{
public:
  using storage = typename Ntk::storage;
  using node = typename Ntk::node;
  using signal = typename Ntk::signal;

  /*! \brief Default constructor.
   *
   * Constructs topological view on another network.
   */
  topo_view( Ntk const& ntk ) : immutable_view<Ntk>( ntk )
  {
    static_assert( is_network_type_v<Ntk>, "Ntk is not a network type" );
    static_assert( has_get_constant_v<Ntk>, "Ntk does not implement the get_constant method" );
    static_assert( has_foreach_pi_v<Ntk>, "Ntk does not implement the foreach_pi method" );
    static_assert( has_foreach_po_v<Ntk>, "Ntk does not implement the foreach_po method" );
    static_assert( has_foreach_fanin_v<Ntk>, "Ntk does not implement the foreach_fanin method" );
    static_assert( has_clear_values_v<Ntk>, "Ntk does not implement the clear_values method" );
    static_assert( has_value_v<Ntk>, "Ntk does not implement the value method" );
    static_assert( has_set_value_v<Ntk>, "Ntk does not implement the set_value method" );

    ntk.clear_values();
    topo_order.reserve( ntk.size() );

    /* constants and PIs */
    const auto c0 = ntk.get_node( ntk.get_constant( false ) );
    topo_order.push_back( c0 );
    ntk.set_value( c0, 2 );

    if ( const auto c1 = ntk.get_node( ntk.get_constant( true ) ); ntk.value( c1 ) != 2 )
    {
      topo_order.push_back( c1 );
      ntk.set_value( c1, 2 );
    }

    ntk.foreach_pi( [this, &ntk]( auto n ) {
      if ( ntk.value( n ) != 2 )
      {
        topo_order.push_back( n );
        ntk.set_value( n, 2 );
      }
    } );

    ntk.foreach_po( [this, &ntk]( auto f, auto ) {
      /* node was already visited */
      if ( ntk.value( ntk.get_node( f ) ) == 2 )
        return;

      create_topo_rec( ntk.get_node( f ) );
    } );
  }

  /*! \brief Reimplementation of `foreach_node`. */
  template<typename Fn>
  void foreach_node( Fn&& fn ) const
  {
    detail::foreach_element( topo_order.begin(),
                             topo_order.end(),
                             fn );
  }

private:
  void create_topo_rec( node const& n )
  {
    /* is permanently marked? */
    if ( this->value( n ) == 2 )
      return;

    /* is temporarily marked? */
    assert( this->value( n ) != 1 );

    /* mark node temporarily */
    this->set_value( n, 1 );

    /* mark children */
    this->foreach_fanin( n, [this]( auto f, auto ) {
      create_topo_rec( this->get_node( f ) );
    } );

    /* mark node n permanently */
    this->set_value( n, 2 );

    /* visit node */
    topo_order.push_back( n );
  }

private:
  std::vector<node> topo_order;
};

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

/*!
  \file topo_view.hpp
  \brief Reimplements foreach_node to guarantee topological order

  \author Mathias Soeken
*/

#pragma once

#include <vector>

#include "../traits.hpp"
#include "../networks/detail/foreach.hpp"
#include "immutable_view.hpp"

namespace mockturtle
{

/*! \brief Ensures topological order for the `foreach_node` interface method.
 *
 * This class computes *on construction* a topological order of the nodes which
 * are reachable from the outputs.  Constant nodes and primary inputs will also
 * be considered even if they are not reachable from the outputs.  Further,
 * constant nodes and primary inputs will be visited first before any gate node
 * is visited.  Constant nodes precede primary inputs, and primary inputs are
 * visited in the same order in which they were created.
 *
 * Since the topological order is computed only once when creating an instance,
 * this view disables changes to the networ interface.  Also, since only
 * reachable nodes are traversed, not all network nodes may be called in
 * `foreach_node`.
 *
 * **Required network functions:**
 * - `get_constant`
 * - `foreach_pi`
 * - `foreach_po`
 * - `foreach_fanin`
 * - `clear_values`
 * - `value`
 * - `set_value`
 *
 * Example
 *
   \verbatim embed:rst

   .. code-block:: c++

      // create network somehow; aig may not be in topological order
      aig_network aig = ...;

      // create a topological view on the network
      topo_view aig_topo{aig};

      // call algorithm that requires topological order
      cut_enumeration( aig_topo );
   \endverbatim
 */
template<typename Ntk>
class topo_view : public immutable_view<Ntk>
{
public:
  using storage = typename Ntk::storage;
  using node = typename Ntk::node;
  using signal = typename Ntk::signal;

  /*! \brief Default constructor.
   *
   * Constructs topological view on another network.
   */
  topo_view( Ntk const& ntk ) : immutable_view<Ntk>( ntk )
  {
    static_assert( is_network_type_v<Ntk>, "Ntk is not a network type" );
    static_assert( has_size_v<Ntk>, "Ntk does not implement the size method" );
    static_assert( has_get_constant_v<Ntk>, "Ntk does not implement the get_constant method" );
    static_assert( has_foreach_pi_v<Ntk>, "Ntk does not implement the foreach_pi method" );
    static_assert( has_foreach_po_v<Ntk>, "Ntk does not implement the foreach_po method" );
    static_assert( has_foreach_fanin_v<Ntk>, "Ntk does not implement the foreach_fanin method" );
    static_assert( has_clear_values_v<Ntk>, "Ntk does not implement the clear_values method" );
    static_assert( has_value_v<Ntk>, "Ntk does not implement the value method" );
    static_assert( has_set_value_v<Ntk>, "Ntk does not implement the set_value method" );

    ntk.clear_values();
    topo_order.reserve( ntk.size() );

    /* constants and PIs */
    const auto c0 = ntk.get_node( ntk.get_constant( false ) );
    topo_order.push_back( c0 );
    ntk.set_value( c0, 2 );

    if ( const auto c1 = ntk.get_node( ntk.get_constant( true ) ); ntk.value( c1 ) != 2 )
    {
      topo_order.push_back( c1 );
      ntk.set_value( c1, 2 );
    }

    ntk.foreach_pi( [this, &ntk]( auto n ) {
      if ( ntk.value( n ) != 2 )
      {
        topo_order.push_back( n );
        ntk.set_value( n, 2 );
      }
    } );

    ntk.foreach_po( [this, &ntk]( auto f, auto ) {
      /* node was already visited */
      if ( ntk.value( ntk.get_node( f ) ) == 2 )
        return;

      create_topo_rec( ntk.get_node( f ) );
    } );
  }

  /*! \brief Reimplementation of `foreach_node`. */
  template<typename Fn>
  void foreach_node( Fn&& fn ) const
  {
    detail::foreach_element( topo_order.begin(),
                             topo_order.end(),
                             fn );
  }

private:
  void create_topo_rec( node const& n )
  {
    /* is permanently marked? */
    if ( this->value( n ) == 2 )
      return;

    /* is temporarily marked? */
    assert( this->value( n ) != 1 );

    /* mark node temporarily */
    this->set_value( n, 1 );

    /* mark children */
    this->foreach_fanin( n, [this]( auto f, auto ) {
      create_topo_rec( this->get_node( f ) );
    } );

    /* mark node n permanently */
    this->set_value( n, 2 );

    /* visit node */
    topo_order.push_back( n );
  }

private:
  std::vector<node> topo_order;
};

} // namespace mockturtle
<|endoftext|>