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

#pragma once

namespace etl {

//Check an expression containing a generator expression

template <typename LE, typename RE, cpp_enable_if(etl_traits<LE>::is_generator || etl_traits<RE>::is_generator)>
void validate_expression(const LE& /*unused*/, const RE& /*unused*/) noexcept {
    //Nothing to test, generators are of infinite size
}

//Check a dynamic expression

template <typename LE, typename RE, cpp_enable_if(!(etl_traits<LE>::is_generator || etl_traits<RE>::is_generator) && all_etl_expr<LE, RE>::value && !all_fast<LE, RE>::value)>
void validate_expression(const LE& lhs, const RE& rhs) {
    cpp_assert(size(lhs) == size(rhs), "Cannot perform element-wise operations on collections of different size");
    cpp_unused(lhs);
    cpp_unused(rhs);
}

//Check a fast expression

template <typename LE, typename RE, cpp_enable_if(!(etl_traits<LE>::is_generator || etl_traits<RE>::is_generator) && all_etl_expr<LE, RE>::value && all_fast<LE, RE>::value)>
void validate_expression(const LE& /*unused*/, const RE& /*unused*/) {
    static_assert(etl_traits<LE>::size() == etl_traits<RE>::size(), "Cannot perform element-wise operations on collections of different size");
}

// Assign a gnerator expression

template <typename LE, typename RE, cpp_enable_if(etl_traits<RE>::is_generator)>
void validate_assign(const LE& /*unused*/, const RE& /*unused*/) noexcept {
    static_assert(is_etl_expr<LE>::value, "Assign can only work on ETL expressions");
    //Nothing to test, generators are of infinite size
}

//Check a dynamic expression

template <typename LE, typename RE, cpp_enable_if(!etl_traits<RE>::is_generator && all_etl_expr<RE>::value && !all_fast<LE, RE>::value)>
void validate_assign(const LE& lhs, const RE& rhs) {
    static_assert(is_etl_expr<LE>::value, "Assign can only work on ETL expressions");
    cpp_assert(size(lhs) == size(rhs), "Cannot perform element-wise operations on collections of different size");
    cpp_unused(lhs);
    cpp_unused(rhs);
}

//Check a fast expression

template <typename LE, typename RE, cpp_enable_if(!etl_traits<RE>::is_generator && all_etl_expr<RE>::value && all_fast<LE, RE>::value)>
void validate_assign(const LE& /*unused*/, const RE& /*unused*/) {
    static_assert(is_etl_expr<LE>::value, "Assign can only work on ETL expressions");
    static_assert(etl_traits<LE>::size() == etl_traits<RE>::size(), "Cannot perform element-wise operations on collections of different size");
}

//Assign a container

template <typename LE, typename RE, cpp_enable_if(!all_etl_expr<RE>::value)>
void validate_assign(const LE& lhs, const RE& rhs) {
    static_assert(is_etl_expr<LE>::value, "Assign can only work on ETL expressions");
    cpp_assert(size(lhs) == rhs.size(), "Cannot perform element-wise operations on collections of different size");
    cpp_unused(lhs);
    cpp_unused(rhs);
}

template <typename E, cpp_enable_if(all_fast<E>::value)>
void assert_square(E&& /*expr*/){
    static_assert(decay_traits<E>::dimensions() == 2, "Function undefined for non-square matrix");
    static_assert(decay_traits<E>::template dim<0>() == decay_traits<E>::template dim<1>(), "Function undefined for non-square matrix");
}

template <typename E, cpp_disable_if(all_fast<E>::value)>
void assert_square(E&& expr){
    static_assert(decay_traits<E>::dimensions() == 2, "Function undefined for non-square matrix");
    cpp_assert(etl::dim<0>(expr) == etl::dim<1>(expr), "Function undefined for non-square matrix");
}

template <std::size_t C1, std::size_t C2, typename E, cpp_enable_if(etl_traits<E>::dimensions() == 2 && !etl_traits<E>::is_fast)>
void validate_pmax_pooling_impl(const E& e) {
    cpp_assert(etl::template dim<0>(e) % C1 == 0 && etl::template dim<1>(e) % C2 == 0, "Dimensions not divisible by the pooling ratio");
    cpp_unused(e);
}

template <std::size_t C1, std::size_t C2, typename E, cpp_enable_if(etl_traits<E>::dimensions() == 3 && !etl_traits<E>::is_fast)>
void validate_pmax_pooling_impl(const E& e) {
    cpp_assert(etl::template dim<1>(e) % C1 == 0 && etl::template dim<2>(e) % C2 == 0, "Dimensions not divisible by the pooling ratio");
    cpp_unused(e);
}

template <std::size_t C1, std::size_t C2, typename E, cpp_enable_if(etl_traits<E>::dimensions() == 2 && etl_traits<E>::is_fast)>
void validate_pmax_pooling_impl(const E& /*unused*/) {
    static_assert(etl_traits<E>::template dim<0>() % C1 == 0 && etl_traits<E>::template dim<1>() % C2 == 0, "Dimensions not divisible by the pooling ratio");
}

template <std::size_t C1, std::size_t C2, typename E, cpp_enable_if(etl_traits<E>::dimensions() == 3 && etl_traits<E>::is_fast)>
void validate_pmax_pooling_impl(const E& /*unused*/) {
    static_assert(etl_traits<E>::template dim<1>() % C1 == 0 && etl_traits<E>::template dim<2>() % C2 == 0, "Dimensions not divisible by the pooling ratio");
}

template <std::size_t C1, std::size_t C2, typename E>
void validate_pmax_pooling(const E& e) {
    static_assert(is_etl_expr<E>::value, "Prob. Max Pooling only defined for ETL expressions");
    static_assert(etl_traits<E>::dimensions() == 2 || etl_traits<E>::dimensions() == 3, "Prob. Max Pooling only defined for 2D and 3D");

    validate_pmax_pooling_impl<C1, C2>(e);
}

} //end of namespace etl
<commit_msg>Fix warning<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

namespace etl {

//Check an expression containing a generator expression

template <typename LE, typename RE, cpp_enable_if(etl_traits<LE>::is_generator || etl_traits<RE>::is_generator)>
void validate_expression(const LE& /*unused*/, const RE& /*unused*/) noexcept {
    //Nothing to test, generators are of infinite size
}

//Check a dynamic expression

template <typename LE, typename RE, cpp_enable_if(!(etl_traits<LE>::is_generator || etl_traits<RE>::is_generator) && all_etl_expr<LE, RE>::value && !all_fast<LE, RE>::value)>
void validate_expression(const LE& lhs, const RE& rhs) {
    cpp_assert(size(lhs) == size(rhs), "Cannot perform element-wise operations on collections of different size");
    cpp_unused(lhs);
    cpp_unused(rhs);
}

//Check a fast expression

template <typename LE, typename RE, cpp_enable_if(!(etl_traits<LE>::is_generator || etl_traits<RE>::is_generator) && all_etl_expr<LE, RE>::value && all_fast<LE, RE>::value)>
void validate_expression(const LE& /*unused*/, const RE& /*unused*/) {
    static_assert(etl_traits<LE>::size() == etl_traits<RE>::size(), "Cannot perform element-wise operations on collections of different size");
}

// Assign a gnerator expression

template <typename LE, typename RE, cpp_enable_if(etl_traits<RE>::is_generator)>
void validate_assign(const LE& /*unused*/, const RE& /*unused*/) noexcept {
    static_assert(is_etl_expr<LE>::value, "Assign can only work on ETL expressions");
    //Nothing to test, generators are of infinite size
}

//Check a dynamic expression

template <typename LE, typename RE, cpp_enable_if(!etl_traits<RE>::is_generator && all_etl_expr<RE>::value && !all_fast<LE, RE>::value)>
void validate_assign(const LE& lhs, const RE& rhs) {
    static_assert(is_etl_expr<LE>::value, "Assign can only work on ETL expressions");
    cpp_assert(size(lhs) == size(rhs), "Cannot perform element-wise operations on collections of different size");
    cpp_unused(lhs);
    cpp_unused(rhs);
}

//Check a fast expression

template <typename LE, typename RE, cpp_enable_if(!etl_traits<RE>::is_generator && all_etl_expr<RE>::value && all_fast<LE, RE>::value)>
void validate_assign(const LE& /*unused*/, const RE& /*unused*/) {
    static_assert(is_etl_expr<LE>::value, "Assign can only work on ETL expressions");
    static_assert(etl_traits<LE>::size() == etl_traits<RE>::size(), "Cannot perform element-wise operations on collections of different size");
}

//Assign a container

template <typename LE, typename RE, cpp_enable_if(!all_etl_expr<RE>::value)>
void validate_assign(const LE& lhs, const RE& rhs) {
    static_assert(is_etl_expr<LE>::value, "Assign can only work on ETL expressions");
    cpp_assert(size(lhs) == rhs.size(), "Cannot perform element-wise operations on collections of different size");
    cpp_unused(lhs);
    cpp_unused(rhs);
}

template <typename E, cpp_enable_if(all_fast<E>::value)>
void assert_square(E&& /*expr*/){
    static_assert(decay_traits<E>::dimensions() == 2, "Function undefined for non-square matrix");
    static_assert(decay_traits<E>::template dim<0>() == decay_traits<E>::template dim<1>(), "Function undefined for non-square matrix");
}

template <typename E, cpp_disable_if(all_fast<E>::value)>
void assert_square(E&& expr){
    static_assert(decay_traits<E>::dimensions() == 2, "Function undefined for non-square matrix");
    cpp_assert(etl::dim<0>(expr) == etl::dim<1>(expr), "Function undefined for non-square matrix");
    cpp_unused(expr); //In case assert is disabled
}

template <std::size_t C1, std::size_t C2, typename E, cpp_enable_if(etl_traits<E>::dimensions() == 2 && !etl_traits<E>::is_fast)>
void validate_pmax_pooling_impl(const E& e) {
    cpp_assert(etl::template dim<0>(e) % C1 == 0 && etl::template dim<1>(e) % C2 == 0, "Dimensions not divisible by the pooling ratio");
    cpp_unused(e);
}

template <std::size_t C1, std::size_t C2, typename E, cpp_enable_if(etl_traits<E>::dimensions() == 3 && !etl_traits<E>::is_fast)>
void validate_pmax_pooling_impl(const E& e) {
    cpp_assert(etl::template dim<1>(e) % C1 == 0 && etl::template dim<2>(e) % C2 == 0, "Dimensions not divisible by the pooling ratio");
    cpp_unused(e);
}

template <std::size_t C1, std::size_t C2, typename E, cpp_enable_if(etl_traits<E>::dimensions() == 2 && etl_traits<E>::is_fast)>
void validate_pmax_pooling_impl(const E& /*unused*/) {
    static_assert(etl_traits<E>::template dim<0>() % C1 == 0 && etl_traits<E>::template dim<1>() % C2 == 0, "Dimensions not divisible by the pooling ratio");
}

template <std::size_t C1, std::size_t C2, typename E, cpp_enable_if(etl_traits<E>::dimensions() == 3 && etl_traits<E>::is_fast)>
void validate_pmax_pooling_impl(const E& /*unused*/) {
    static_assert(etl_traits<E>::template dim<1>() % C1 == 0 && etl_traits<E>::template dim<2>() % C2 == 0, "Dimensions not divisible by the pooling ratio");
}

template <std::size_t C1, std::size_t C2, typename E>
void validate_pmax_pooling(const E& e) {
    static_assert(is_etl_expr<E>::value, "Prob. Max Pooling only defined for ETL expressions");
    static_assert(etl_traits<E>::dimensions() == 2 || etl_traits<E>::dimensions() == 3, "Prob. Max Pooling only defined for 2D and 3D");

    validate_pmax_pooling_impl<C1, C2>(e);
}

} //end of namespace etl
<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) Johan Mabille and Sylvain Corlay                           *
* Copyright (c) QuantStack                                                 *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XTENSOR_JULIA_CONFIG_HPP
#define XTENSOR_JULIA_CONFIG_HPP

#define XTENSOR_JULIA_VERSION_MAJOR 0
#define XTENSOR_JULIA_VERSION_MINOR 10
#define XTENSOR_JULIA_VERSION_PATCH 0

#endif
<commit_msg>Release 0.10.1<commit_after>/***************************************************************************
* Copyright (c) Johan Mabille and Sylvain Corlay                           *
* Copyright (c) QuantStack                                                 *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XTENSOR_JULIA_CONFIG_HPP
#define XTENSOR_JULIA_CONFIG_HPP

#define XTENSOR_JULIA_VERSION_MAJOR 0
#define XTENSOR_JULIA_VERSION_MINOR 10
#define XTENSOR_JULIA_VERSION_PATCH 1

#endif
<|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"
#include "decay_type.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;

    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;

    //{{{ Momentum

    //Compute sizes so that collections are empty if Momentum not enabled
    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;

    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;

    //}}} Momentum end

    //{{{ Sparsity

    weight q_old;
    weight q_batch;
    weight q_t;

    //}}} Sparsity end

    template<bool M = rbm_t::Momentum, typename std::enable_if<(!M), bool>::type = false>
    base_cd_trainer() : q_old(0.0) {
        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), q_old(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;
        }

        //Penalty to be applied to weights and hidden biases
        weight h_penalty = 0.0;

        //Update sparsity
        if(rbm_t::Sparsity){
            auto decay_rate = rbm.decay_rate;
            auto p = rbm.sparsity_target;
            auto cost = rbm.sparsity_cost;

            q_t = decay_rate * q_old + (1.0 - decay_rate) * q_batch;

            h_penalty = cost * (q_t - p);
        }

        //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 applied on biases only on demand
        //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

        //Update weights

        if(rbm_t::Decay == DecayType::L1 || rbm_t::Decay == DecayType::L1_FULL){
            rbm.w += learning_rate * (w_fgrad - rbm.weight_cost * abs(rbm.w) - h_penalty);
        } else if(rbm_t::Decay == DecayType::L2 || rbm_t::Decay == DecayType::L2_FULL){
            rbm.w += learning_rate * (w_fgrad - rbm.weight_cost * rbm.w - h_penalty);
        } else {
            rbm.w += learning_rate * w_fgrad - h_penalty;
        }

        //Update hidden biases

        if(rbm_t::Decay == DecayType::L1_FULL){
            rbm.b += learning_rate * (b_fgrad - rbm.weight_cost * abs(rbm.b) - h_penalty);
        } else if(rbm_t::Decay == DecayType::L2_FULL){
            rbm.b += learning_rate * (b_fgrad - rbm.weight_cost * rbm.b - h_penalty);
        } else {
            rbm.b += learning_rate * b_fgrad - h_penalty;
        }

        //Update visible biases

        if(rbm_t::Decay == DecayType::L1_FULL){
            rbm.a += learning_rate * (a_fgrad - rbm.weight_cost * abs(rbm.a));
        } else if(rbm_t::Decay == DecayType::L2_FULL){
            rbm.a += learning_rate * (a_fgrad - rbm.weight_cost * rbm.a);
        } else {
            rbm.a += learning_rate * a_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;

    using base_cd_trainer<RBM>::q_batch;

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;

        //Reset mean activation probability if necessary
        if(rbm_t::Sparsity){
            q_batch = 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;

            if(rbm_t::Sparsity){
                q_batch += sum(rbm.h2_a);
            }
        }

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

        //Compute the mean activation probabilities
        if(rbm_t::Sparsity){
            q_batch /= n_samples * num_hidden;
        }

        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;

    using base_cd_trainer<RBM>::q_batch;

    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;

        //Reset mean activation probability if necessary
        if(rbm_t::Sparsity){
            q_batch = 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;

            if(rbm_t::Sparsity){
                q_batch += sum(rbm.h2_a);
            }
        }

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

        //Compute the mean activation probabilities
        if(rbm_t::Sparsity){
            q_batch /= n_samples * num_hidden;
        }

        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>Fix CD when momentum not enabled<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"
#include "decay_type.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;

    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;

    //{{{ Momentum

    //Compute sizes so that collections are empty if Momentum not enabled
    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;

    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;

    //}}} Momentum end

    //{{{ Sparsity

    weight q_old;
    weight q_batch;
    weight q_t;

    //}}} Sparsity end

    template<bool M = rbm_t::Momentum, typename std::enable_if<(!M), bool>::type = false>
    base_cd_trainer() : q_old(0.0) {
        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), q_old(0.0) {
        static_assert(rbm_t::Momentum, "This constructor should only be used with momentum support");
    }

    template<typename T1, typename T2, bool M = rbm_t::Momentum, enable_if_u<M> = detail::dummy>
    T2& get_fgrad(T1& , T2& inc){
        return inc;
    }

    template<typename T1, typename T2, bool M = rbm_t::Momentum, disable_if_u<M> = detail::dummy>
    T1& get_fgrad(T1& grad, T2& ){
        return grad;
    }

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

        //Penalty to be applied to weights and hidden biases
        weight h_penalty = 0.0;

        //Update sparsity
        if(rbm_t::Sparsity){
            auto decay_rate = rbm.decay_rate;
            auto p = rbm.sparsity_target;
            auto cost = rbm.sparsity_cost;

            q_t = decay_rate * q_old + (1.0 - decay_rate) * q_batch;

            h_penalty = cost * (q_t - p);
        }

        //The final gradients;
        const auto& w_fgrad = get_fgrad(w_grad, w_inc);
        const auto& a_fgrad = get_fgrad(vbias_grad, a_inc);
        const auto& b_fgrad = get_fgrad(hbias_grad, b_inc);

        //Weight decay is applied on biases only on demand
        //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

        //Update weights

        if(rbm_t::Decay == DecayType::L1 || rbm_t::Decay == DecayType::L1_FULL){
            rbm.w += learning_rate * (w_fgrad - rbm.weight_cost * abs(rbm.w) - h_penalty);
        } else if(rbm_t::Decay == DecayType::L2 || rbm_t::Decay == DecayType::L2_FULL){
            rbm.w += learning_rate * (w_fgrad - rbm.weight_cost * rbm.w - h_penalty);
        } else {
            rbm.w += learning_rate * w_fgrad - h_penalty;
        }

        //Update hidden biases

        if(rbm_t::Decay == DecayType::L1_FULL){
            rbm.b += learning_rate * (b_fgrad - rbm.weight_cost * abs(rbm.b) - h_penalty);
        } else if(rbm_t::Decay == DecayType::L2_FULL){
            rbm.b += learning_rate * (b_fgrad - rbm.weight_cost * rbm.b - h_penalty);
        } else {
            rbm.b += learning_rate * b_fgrad - h_penalty;
        }

        //Update visible biases

        if(rbm_t::Decay == DecayType::L1_FULL){
            rbm.a += learning_rate * (a_fgrad - rbm.weight_cost * abs(rbm.a));
        } else if(rbm_t::Decay == DecayType::L2_FULL){
            rbm.a += learning_rate * (a_fgrad - rbm.weight_cost * rbm.a);
        } else {
            rbm.a += learning_rate * a_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;

    using base_cd_trainer<RBM>::q_batch;

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;

        //Reset mean activation probability if necessary
        if(rbm_t::Sparsity){
            q_batch = 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;

            if(rbm_t::Sparsity){
                q_batch += sum(rbm.h2_a);
            }
        }

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

        //Compute the mean activation probabilities
        if(rbm_t::Sparsity){
            q_batch /= n_samples * num_hidden;
        }

        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;

    using base_cd_trainer<RBM>::q_batch;

    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;

        //Reset mean activation probability if necessary
        if(rbm_t::Sparsity){
            q_batch = 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;

            if(rbm_t::Sparsity){
                q_batch += sum(rbm.h2_a);
            }
        }

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

        //Compute the mean activation probabilities
        if(rbm_t::Sparsity){
            q_batch /= n_samples * num_hidden;
        }

        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>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "OrbitBase/ThreadPool.h"

#include <absl/meta/type_traits.h>
#include <absl/time/time.h>

#include <algorithm>
#include <list>
#include <thread>
#include <type_traits>
#include <vector>

#include "OrbitBase/Logging.h"
#include "OrbitBase/Tracing.h"
#include "absl/container/flat_hash_map.h"
#include "absl/synchronization/mutex.h"

namespace {

class ThreadPoolImpl : public ThreadPool {
 public:
  explicit ThreadPoolImpl(size_t thread_pool_min_size, size_t thread_pool_max_size,
                          absl::Duration thread_ttl);

  size_t GetPoolSize() override;
  size_t GetNumberOfBusyThreads() override;
  void Schedule(std::unique_ptr<Action> action) override;
  void Shutdown() override;
  void Wait() override;
  void EnableAutoProfiling(bool value) override;

 private:
  bool ActionsAvailableOrShutdownInitiated();
  // Blocking call - returns nullptr if the worker thread needs to exit.
  std::unique_ptr<Action> TakeAction();
  void CleanupFinishedThreads();
  void CreateWorker();
  void WorkerFunction();

  absl::Mutex mutex_;
  std::list<std::unique_ptr<Action>> scheduled_actions_;
  absl::flat_hash_map<std::thread::id, std::thread> worker_threads_;
  std::vector<std::thread> finished_threads_;
  size_t thread_pool_min_size_;
  size_t thread_pool_max_size_;
  absl::Duration thread_ttl_;
  size_t idle_threads_;
  bool shutdown_initiated_;
  bool auto_profile_;
};

ThreadPoolImpl::ThreadPoolImpl(size_t thread_pool_min_size, size_t thread_pool_max_size,
                               absl::Duration thread_ttl)
    : thread_pool_min_size_(thread_pool_min_size),
      thread_pool_max_size_(thread_pool_max_size),
      thread_ttl_(thread_ttl),
      idle_threads_(0),
      shutdown_initiated_(false),
      auto_profile_(true) {
  CHECK(thread_pool_min_size > 0);
  CHECK(thread_pool_max_size >= thread_pool_min_size);
  // Ttl should not be too small
  CHECK(thread_ttl / absl::Nanoseconds(1) >= 1000);

  absl::MutexLock lock(&mutex_);
  for (size_t i = 0; i < thread_pool_min_size; ++i) {
    CreateWorker();
  }
}

void ThreadPoolImpl::CreateWorker() {
  CHECK(!shutdown_initiated_);
  idle_threads_++;
  std::thread thread([this] { WorkerFunction(); });
  std::thread::id thread_id = thread.get_id();
  CHECK(!worker_threads_.contains(thread_id));
  worker_threads_.insert_or_assign(thread_id, std::move(thread));
}

void ThreadPoolImpl::Schedule(std::unique_ptr<Action> action) {
  absl::MutexLock lock(&mutex_);
  CHECK(!shutdown_initiated_);

  scheduled_actions_.push_back(std::move(action));
  if (idle_threads_ < scheduled_actions_.size() && worker_threads_.size() < thread_pool_max_size_) {
    CreateWorker();
  }

  CleanupFinishedThreads();
}

void ThreadPoolImpl::CleanupFinishedThreads() {
  for (std::thread& thread : finished_threads_) {
    thread.join();
  }

  finished_threads_.clear();
}

size_t ThreadPoolImpl::GetPoolSize() {
  absl::MutexLock lock(&mutex_);
  return worker_threads_.size();
}

size_t ThreadPoolImpl::GetNumberOfBusyThreads() {
  absl::MutexLock lock(&mutex_);
  return worker_threads_.size() - idle_threads_;
}

void ThreadPoolImpl::Shutdown() {
  absl::MutexLock lock(&mutex_);
  shutdown_initiated_ = true;
}

void ThreadPoolImpl::Wait() {
  absl::MutexLock lock(&mutex_);
  CHECK(shutdown_initiated_);
  // First wait until all worker threads finished their work
  // and moved to finished_threads_ list.
  mutex_.Await(
      absl::Condition(&worker_threads_, &absl::flat_hash_map<std::thread::id, std::thread>::empty));

  CleanupFinishedThreads();
}

void ThreadPoolImpl::EnableAutoProfiling(bool value) {
  absl::MutexLock lock(&mutex_);
  auto_profile_ = value;
}

bool ThreadPoolImpl::ActionsAvailableOrShutdownInitiated() {
  return !scheduled_actions_.empty() || shutdown_initiated_;
}

std::unique_ptr<Action> ThreadPoolImpl::TakeAction() {
  while (true) {
    if (mutex_.AwaitWithTimeout(
            absl::Condition(this, &ThreadPoolImpl::ActionsAvailableOrShutdownInitiated),
            thread_ttl_)) {
      break;
    }

    // Timed out - check if we need to reduce thread pool.
    if (worker_threads_.size() > thread_pool_min_size_) {
      return nullptr;
    }
  }

  if (scheduled_actions_.empty()) {
    return nullptr;
  }

  std::unique_ptr<Action> action = std::move(scheduled_actions_.front());
  scheduled_actions_.pop_front();

  return action;
}

void ThreadPoolImpl::WorkerFunction() {
  while (true) {
    absl::MutexLock lock(&mutex_);
    std::unique_ptr<Action> action = TakeAction();

    CHECK(idle_threads_ > 0);  // Sanity check
    --idle_threads_;

    if (!action) {
      // Move this thread from the worker_threads_ to finished_threads_.
      std::thread::id thread_id = std::this_thread::get_id();
      auto it = worker_threads_.find(thread_id);
      CHECK(it != worker_threads_.end());
      finished_threads_.push_back(std::move(it->second));
      worker_threads_.erase(it);
      break;
    }

    bool auto_profile = auto_profile_;
    mutex_.Unlock();
    if (auto_profile) ORBIT_START("Execute Action");
    action->Execute();
    if (auto_profile) ORBIT_STOP();
    mutex_.Lock();
    ++idle_threads_;
  }
}

};  // namespace

std::unique_ptr<ThreadPool> ThreadPool::Create(size_t thread_pool_min_size,
                                               size_t thread_pool_max_size,
                                               absl::Duration thread_ttl) {
  return std::make_unique<ThreadPoolImpl>(thread_pool_min_size, thread_pool_max_size, thread_ttl);
}
<commit_msg>Replace absl::Condition overload<commit_after>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "OrbitBase/ThreadPool.h"

#include <absl/meta/type_traits.h>
#include <absl/time/time.h>

#include <algorithm>
#include <list>
#include <thread>
#include <type_traits>
#include <vector>

#include "OrbitBase/Logging.h"
#include "OrbitBase/Tracing.h"
#include "absl/container/flat_hash_map.h"
#include "absl/synchronization/mutex.h"

namespace {

class ThreadPoolImpl : public ThreadPool {
 public:
  explicit ThreadPoolImpl(size_t thread_pool_min_size, size_t thread_pool_max_size,
                          absl::Duration thread_ttl);

  size_t GetPoolSize() override;
  size_t GetNumberOfBusyThreads() override;
  void Schedule(std::unique_ptr<Action> action) override;
  void Shutdown() override;
  void Wait() override;
  void EnableAutoProfiling(bool value) override;

 private:
  bool ActionsAvailableOrShutdownInitiated();
  // Blocking call - returns nullptr if the worker thread needs to exit.
  std::unique_ptr<Action> TakeAction();
  void CleanupFinishedThreads();
  void CreateWorker();
  void WorkerFunction();

  absl::Mutex mutex_;
  std::list<std::unique_ptr<Action>> scheduled_actions_;
  absl::flat_hash_map<std::thread::id, std::thread> worker_threads_;
  std::vector<std::thread> finished_threads_;
  size_t thread_pool_min_size_;
  size_t thread_pool_max_size_;
  absl::Duration thread_ttl_;
  size_t idle_threads_;
  bool shutdown_initiated_;
  bool auto_profile_;
};

ThreadPoolImpl::ThreadPoolImpl(size_t thread_pool_min_size, size_t thread_pool_max_size,
                               absl::Duration thread_ttl)
    : thread_pool_min_size_(thread_pool_min_size),
      thread_pool_max_size_(thread_pool_max_size),
      thread_ttl_(thread_ttl),
      idle_threads_(0),
      shutdown_initiated_(false),
      auto_profile_(true) {
  CHECK(thread_pool_min_size > 0);
  CHECK(thread_pool_max_size >= thread_pool_min_size);
  // Ttl should not be too small
  CHECK(thread_ttl / absl::Nanoseconds(1) >= 1000);

  absl::MutexLock lock(&mutex_);
  for (size_t i = 0; i < thread_pool_min_size; ++i) {
    CreateWorker();
  }
}

void ThreadPoolImpl::CreateWorker() {
  CHECK(!shutdown_initiated_);
  idle_threads_++;
  std::thread thread([this] { WorkerFunction(); });
  std::thread::id thread_id = thread.get_id();
  CHECK(!worker_threads_.contains(thread_id));
  worker_threads_.insert_or_assign(thread_id, std::move(thread));
}

void ThreadPoolImpl::Schedule(std::unique_ptr<Action> action) {
  absl::MutexLock lock(&mutex_);
  CHECK(!shutdown_initiated_);

  scheduled_actions_.push_back(std::move(action));
  if (idle_threads_ < scheduled_actions_.size() && worker_threads_.size() < thread_pool_max_size_) {
    CreateWorker();
  }

  CleanupFinishedThreads();
}

void ThreadPoolImpl::CleanupFinishedThreads() {
  for (std::thread& thread : finished_threads_) {
    thread.join();
  }

  finished_threads_.clear();
}

size_t ThreadPoolImpl::GetPoolSize() {
  absl::MutexLock lock(&mutex_);
  return worker_threads_.size();
}

size_t ThreadPoolImpl::GetNumberOfBusyThreads() {
  absl::MutexLock lock(&mutex_);
  return worker_threads_.size() - idle_threads_;
}

void ThreadPoolImpl::Shutdown() {
  absl::MutexLock lock(&mutex_);
  shutdown_initiated_ = true;
}

void ThreadPoolImpl::Wait() {
  absl::MutexLock lock(&mutex_);
  CHECK(shutdown_initiated_);
  // First wait until all worker threads finished their work
  // and moved to finished_threads_ list.
  mutex_.Await(
      absl::Condition(&worker_threads_, &absl::flat_hash_map<std::thread::id, std::thread>::empty));

  CleanupFinishedThreads();
}

void ThreadPoolImpl::EnableAutoProfiling(bool value) {
  absl::MutexLock lock(&mutex_);
  auto_profile_ = value;
}

bool ThreadPoolImpl::ActionsAvailableOrShutdownInitiated() {
  return !scheduled_actions_.empty() || shutdown_initiated_;
}

std::unique_ptr<Action> ThreadPoolImpl::TakeAction() {
  while (true) {
    if (mutex_.AwaitWithTimeout(
            absl::Condition(
                +[](ThreadPoolImpl* self) { return self->ActionsAvailableOrShutdownInitiated(); },
                this),
            thread_ttl_)) {
      break;
    }

    // Timed out - check if we need to reduce thread pool.
    if (worker_threads_.size() > thread_pool_min_size_) {
      return nullptr;
    }
  }

  if (scheduled_actions_.empty()) {
    return nullptr;
  }

  std::unique_ptr<Action> action = std::move(scheduled_actions_.front());
  scheduled_actions_.pop_front();

  return action;
}

void ThreadPoolImpl::WorkerFunction() {
  while (true) {
    absl::MutexLock lock(&mutex_);
    std::unique_ptr<Action> action = TakeAction();

    CHECK(idle_threads_ > 0);  // Sanity check
    --idle_threads_;

    if (!action) {
      // Move this thread from the worker_threads_ to finished_threads_.
      std::thread::id thread_id = std::this_thread::get_id();
      auto it = worker_threads_.find(thread_id);
      CHECK(it != worker_threads_.end());
      finished_threads_.push_back(std::move(it->second));
      worker_threads_.erase(it);
      break;
    }

    bool auto_profile = auto_profile_;
    mutex_.Unlock();
    if (auto_profile) ORBIT_START("Execute Action");
    action->Execute();
    if (auto_profile) ORBIT_STOP();
    mutex_.Lock();
    ++idle_threads_;
  }
}

};  // namespace

std::unique_ptr<ThreadPool> ThreadPool::Create(size_t thread_pool_min_size,
                                               size_t thread_pool_max_size,
                                               absl::Duration thread_ttl) {
  return std::make_unique<ThreadPoolImpl>(thread_pool_min_size, thread_pool_max_size, thread_ttl);
}
<|endoftext|>


<commit_before>//
//  inpalprime.hpp
//  InPal
//
//  Created by Bryan Triana on 6/21/16.
//  Copyright © 2016 Inverse Palindrome. All rights reserved.
//

#ifndef inpalprime_hpp
#define inpalprime_hpp

#include <vector>
#include <string>

namespace inpal
{
    class prime
    {
    public:
        static std::size_t max_prime(std::size_t range);
        static std::size_t prime_count(std::size_t range);
        static double prime_density(double range);
        static bool prime_test(std::size_t num);
        static bool twin_test(std::size_t num);
        static bool cousin_test(std::size_t num);
        static bool sexy_test(std::size_t num);
        static std::size_t max_palprime(std::size_t range);
        static std::size_t max_factor(std::size_t num);
        static std::size_t count_factors(std::size_t num);
    private:
        static std::vector<bool> prime_sieve(std::size_t range);
        static std::vector<std::size_t> factorizer(std::size_t num);
        static bool pal_test(std::size_t num);
    };
}

#endif /* inpalprime_hpp */
<commit_msg>Delete inpalprime.hpp<commit_after><|endoftext|>


<commit_before>/*
    This file is part of KDE Kontact.

    Copyright (c) 2001 Matthias Hoelzer-Kluepfel <mhk@kde.org>
    Copyright (c) 2002-2003 Daniel Molkentin <molkentin@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include <iostream>

#include <dcopclient.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kstartupinfo.h>
#include <kuniqueapplication.h>
#include <kwin.h>
#include <ktrader.h>
#include "plugin.h"

#include <qlabel.h>
#include "splash.h"

#include "mainwindow.h"

using namespace std;

static const char description[] =
    I18N_NOOP( "KDE personal information manager" );

static const char version[] = "0.9";

class KontactApp : public KUniqueApplication {
  public:
    KontactApp() : mMainWindow( 0 ) {}
    ~KontactApp() {}

    int newInstance();

  private:
    Kontact::MainWindow *mMainWindow;
};

static void listPlugins()
{
  KInstance instance( "kontact" ); // Can't use KontactApp since it's too late for adding cmdline options
  KTrader::OfferList offers = KTrader::self()->query(
    QString::fromLatin1( "Kontact/Plugin" ),
    QString( "[X-KDE-KontactPluginVersion] == %1" ).arg( KONTACT_PLUGIN_VERSION ) );
  for(KService::List::Iterator it = offers.begin(); it != offers.end(); ++it)
  {
    KService::Ptr service = (*it);
    cout << service->library().remove( "libkontact_" ).latin1() << endl;
  }
}

static KCmdLineOptions options[] =
{
    { "module <module>",   I18N_NOOP("Start with a specific Kontact module"), 0 },
    { "nosplash",   I18N_NOOP("Disable the splash screen"), 0 },
    { "list", I18N_NOOP("List all possible modules and exit"), 0 },
    KCmdLineLastOption
};

int KontactApp::newInstance()
{
  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
  QString moduleName;
  if ( args->isSet("module") )
  {
    moduleName = QString::fromLocal8Bit(args->getOption("module"));
  }
  Kontact::Splash* splash = new Kontact::Splash( 0, "splash" );
  if ( !mMainWindow && args->isSet("splash") ) // only the first time
    splash->show();

  if ( isRestored() ) {
    // There can only be one main window
    if ( KMainWindow::canBeRestored( 1 ) ) {
      mMainWindow = new Kontact::MainWindow(splash);
      setMainWidget( mMainWindow );
      mMainWindow->show();
      mMainWindow->restore( 1 );
    }
  } else {
    if ( !mMainWindow ) {
      mMainWindow = new Kontact::MainWindow(splash);
      if ( !moduleName.isEmpty() )
        mMainWindow->activePluginModule( moduleName );
      mMainWindow->show();
      setMainWidget( mMainWindow );
    }
    else
    {
      if ( !moduleName.isEmpty() )
        mMainWindow->activePluginModule( moduleName );
    }
  }

  // Handle startup notification and window activation
  // (The first time it will do nothing except note that it was called)
  return KUniqueApplication::newInstance();
}

int main(int argc, char **argv)
{
  KAboutData about( "kontact", I18N_NOOP( "Kontact" ), version, description,
                    KAboutData::License_GPL, I18N_NOOP("(C) 2001-2004 The Kontact developers"), 0, "http://kontact.org", "kde-pim@kde.org" );
  about.addAuthor( "Daniel Molkentin", 0, "molkentin@kde.org" );
  about.addAuthor( "Don Sanders", 0, "sanders@kde.org" );
  about.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
  about.addAuthor( "Tobias K\303\266nig", 0, "tokoe@kde.org" );
  about.addAuthor( "David Faure", 0, "faure@kde.org" );
  about.addAuthor( "Ingo Kl\303\266cker", 0, "kloecker@kde.org" );
  about.addAuthor( "Sven L\303\274ppken", 0, "sven@kde.org" );
  about.addAuthor( "Zack Rusin", 0, "zack@kde.org" );
  about.addAuthor( "Matthias Hoelzer-Kluepfel", I18N_NOOP("Original Author"), "mhk@kde.org" );

  KCmdLineArgs::init( argc, argv, &about );
  KCmdLineArgs::addCmdLineOptions( options );
  KUniqueApplication::addCmdLineOptions();
  KApplication::addCmdLineOptions();

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
  if ( args->isSet( "list" ) )
  {
    listPlugins();
    return 0;
  }

  if ( !KontactApp::start() ) {
    // Already running, brought to the foreground.
    return 0;
  }

  KontactApp app;
  bool ret = app.exec();
  while ( KMainWindow::memberList->first() )
    delete KMainWindow::memberList->first();

  return ret;
}
<commit_msg>RC1<commit_after>/*
    This file is part of KDE Kontact.

    Copyright (c) 2001 Matthias Hoelzer-Kluepfel <mhk@kde.org>
    Copyright (c) 2002-2003 Daniel Molkentin <molkentin@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include <iostream>

#include <dcopclient.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kstartupinfo.h>
#include <kuniqueapplication.h>
#include <kwin.h>
#include <ktrader.h>
#include "plugin.h"

#include <qlabel.h>
#include "splash.h"

#include "mainwindow.h"

using namespace std;

static const char description[] =
    I18N_NOOP( "KDE personal information manager" );

static const char version[] = "0.99 (RC1)";

class KontactApp : public KUniqueApplication {
  public:
    KontactApp() : mMainWindow( 0 ) {}
    ~KontactApp() {}

    int newInstance();

  private:
    Kontact::MainWindow *mMainWindow;
};

static void listPlugins()
{
  KInstance instance( "kontact" ); // Can't use KontactApp since it's too late for adding cmdline options
  KTrader::OfferList offers = KTrader::self()->query(
    QString::fromLatin1( "Kontact/Plugin" ),
    QString( "[X-KDE-KontactPluginVersion] == %1" ).arg( KONTACT_PLUGIN_VERSION ) );
  for(KService::List::Iterator it = offers.begin(); it != offers.end(); ++it)
  {
    KService::Ptr service = (*it);
    cout << service->library().remove( "libkontact_" ).latin1() << endl;
  }
}

static KCmdLineOptions options[] =
{
    { "module <module>",   I18N_NOOP("Start with a specific Kontact module"), 0 },
    { "nosplash",   I18N_NOOP("Disable the splash screen"), 0 },
    { "list", I18N_NOOP("List all possible modules and exit"), 0 },
    KCmdLineLastOption
};

int KontactApp::newInstance()
{
  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
  QString moduleName;
  if ( args->isSet("module") )
  {
    moduleName = QString::fromLocal8Bit(args->getOption("module"));
  }
  Kontact::Splash* splash = new Kontact::Splash( 0, "splash" );
  if ( !mMainWindow && args->isSet("splash") ) // only the first time
    splash->show();

  if ( isRestored() ) {
    // There can only be one main window
    if ( KMainWindow::canBeRestored( 1 ) ) {
      mMainWindow = new Kontact::MainWindow(splash);
      setMainWidget( mMainWindow );
      mMainWindow->show();
      mMainWindow->restore( 1 );
    }
  } else {
    if ( !mMainWindow ) {
      mMainWindow = new Kontact::MainWindow(splash);
      if ( !moduleName.isEmpty() )
        mMainWindow->activePluginModule( moduleName );
      mMainWindow->show();
      setMainWidget( mMainWindow );
    }
    else
    {
      if ( !moduleName.isEmpty() )
        mMainWindow->activePluginModule( moduleName );
    }
  }

  // Handle startup notification and window activation
  // (The first time it will do nothing except note that it was called)
  return KUniqueApplication::newInstance();
}

int main(int argc, char **argv)
{
  KAboutData about( "kontact", I18N_NOOP( "Kontact" ), version, description,
                    KAboutData::License_GPL, I18N_NOOP("(C) 2001-2004 The Kontact developers"), 0, "http://kontact.org", "kde-pim@kde.org" );
  about.addAuthor( "Daniel Molkentin", 0, "molkentin@kde.org" );
  about.addAuthor( "Don Sanders", 0, "sanders@kde.org" );
  about.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
  about.addAuthor( "Tobias K\303\266nig", 0, "tokoe@kde.org" );
  about.addAuthor( "David Faure", 0, "faure@kde.org" );
  about.addAuthor( "Ingo Kl\303\266cker", 0, "kloecker@kde.org" );
  about.addAuthor( "Sven L\303\274ppken", 0, "sven@kde.org" );
  about.addAuthor( "Zack Rusin", 0, "zack@kde.org" );
  about.addAuthor( "Matthias Hoelzer-Kluepfel", I18N_NOOP("Original Author"), "mhk@kde.org" );

  KCmdLineArgs::init( argc, argv, &about );
  KCmdLineArgs::addCmdLineOptions( options );
  KUniqueApplication::addCmdLineOptions();
  KApplication::addCmdLineOptions();

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
  if ( args->isSet( "list" ) )
  {
    listPlugins();
    return 0;
  }

  if ( !KontactApp::start() ) {
    // Already running, brought to the foreground.
    return 0;
  }

  KontactApp app;
  bool ret = app.exec();
  while ( KMainWindow::memberList->first() )
    delete KMainWindow::memberList->first();

  return ret;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include "algorithm.h"

using namespace broken_algo;

int main()
{
    std::vector<int> l = {1, 2, 3, 4, 5};
    broken_algo::for_each(l.begin(), l.end(),
             [](auto elem) -> breaker_t<int> {
        do
        {
            if (elem == 3)
            {
                break;
            }
            std::cout << elem << std::endl;
            return no_breaker;
        } while (0);
        return breaker;
    }
    );
}
<commit_msg>less retarded test for for_each<commit_after>#include <iostream>
#include <vector>
#include "algorithm.h"

using namespace broken_algo;

int main()
{
    std::vector<int> l = {1, 2, 3, 4, 5};
    broken_algo::for_each(l.begin(), l.end(),
             [](auto elem) -> breaker_t<void> {
        do
        {
            if (elem == 3)
            {
                break;
            }
            std::cout << elem << std::endl;
            return no_breaker;
        } while (0);
        return breaker;
    }
    );
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <limits>

#include "../sources/logxx/logxx.h"
#include "../sources/deck.h"

static logxx::Log cLog("test");

inline bool Conditions(const std::vector<PlayingCard> &deck, const PlayingCard &target){
        decltype(deck.begin()) targetBegin = deck.begin() + 19;
        decltype(deck.begin()) targetEnd = deck.begin() + 25;

        decltype(deck.begin()) ownActionsBegin = deck.begin() + 3;
        decltype(deck.begin()) ownActionsEnd = deck.begin() + 9;

        return
                deck[0].GetNumber() == PlayingCard::Jack &&
                deck[1].GetNumber() == PlayingCard::Nine &&
                (deck[2].GetNumber() == PlayingCard::Ace || deck[2].GetNumber() == PlayingCard::Ten) &&
                std::find(targetBegin, targetEnd, target) != targetEnd &&
                std::find_if(ownActionsBegin, ownActionsEnd, [](const PlayingCard& p)->bool{
                        return p.GetNumber() == PlayingCard::Ace;
                }) == ownActionsEnd &&
                deck[35].GetNumber() == PlayingCard::Ten;
}

int rnd(int i){ return std::rand() % i; }

int main() {
        S_LOG("main");
//        log(logxx::info) << "Testing card" << logxx::endl;
//        PlayingCard card;
//        bool reachedEnd(false);
//        int cnt(0);
//        while (!reachedEnd){
//                log(logxx::info) << "Card: " << card.Print(true) << " -> " << card.Print() << logxx::endl;
//                card.Next(reachedEnd);
//                ++cnt;
//        }
//        log(logxx::info) << "Total " << cnt << " cards" << logxx::endl;
//        if (cnt != 36)
//                return 1;
//
//        Deck initialDeck;
//        log(logxx::info) << "Deck:" << logxx::endl;
//        initialDeck.Print(false);
//        log(logxx::info) << "Deck in abbrevations:" << logxx::endl;
//        initialDeck.Print(true);
//
//        std::vector<Deck> decks;
//        for (int i = 0; i < 100000; ++i){
//                decks.push_back(initialDeck);
//                if (!initialDeck.Next()){
//                        log(logxx::error) << "Reached an end of sequences!" << logxx::endl;
//                        return 1;
//                }
//        }
//        std::sort(decks.begin(), decks.end());
//        if (std::adjacent_find(decks.begin(), decks.end()) != decks.end()){
//                log(logxx::error) << "Found duplicate" << logxx::endl;
//                return 1;
//        } else
//                log(logxx::info) << "No duplicates found" << logxx::endl;
//
//        static const long int permutations = 1E8;
//        time_t start(time(nullptr));
//        for (long int i = 0; i < permutations; ++i)
//                initialDeck.Next();
//        log(logxx::info) << permutations << " permutations done in " << time(nullptr) - start << " seconds" << logxx::endl;

        //PlayingCard card(std::pair<PlayingCard::Suit, PlayingCard::Number>(PlayingCard::Hearts, PlayingCard::Seven));
//        PlayingCard card{PlayingCard::Seven, PlayingCard::Hearts};
        //Тб 7п Кк Тч 9к Кп 6п 8п 10ч 7к 8к Вп 6ч 6к Вч Тп Дп Вк 7б 7ч 9п 10п 10к Вб Кч 10б 8ч 9ч Кб Дч Дб 8б Дк 6б Тк 9б
//        std::string deskStr = "Вч 9к Тч Вк 7п Xк 9п 7ч 9ч Тб 6ч Дп 8ч Кб Тп Xп Вб 8п 7к 9б 6п Дч Кч Вп Xч Кп 8к Дб Xб 8б 6к Дк 7б Тк 6б Кк";
//        Deck test(deskStr);
//        log(logxx::info) << "Collapsed? " << std::boolalpha << test.Collapse() << logxx::endl;
//        Deck test({
//                {PlayingCard::Ace, PlayingCard::Hearts}
//        });
        //std::vector<PlayingCard> headerDeck({PlayingCard("В"), PlayingCard("9"), PlayingCard("Т")});

//        Deck deck;
//        deck.Print(true);

	std::srand(time(nullptr));

        PlayingCard target("Xч");
        Deck testDeck;
        Deck idealDeck;
        std::vector<PlayingCard> deck = testDeck.GetDeck();
        unsigned int maxCollapses(0);
        for (long long int i = 0; i < std::numeric_limits<decltype(i)>::max(); ++i){
                if (Conditions(deck, target)){
                        testDeck.SetDeck(deck);
                        if (testDeck.Collapse()){
                                auto targetCollapses = testDeck.collapses[target];
                                if (targetCollapses > maxCollapses){
                                        maxCollapses = targetCollapses;
                                        testDeck.Print(true);
                                        log(logxx::info) << target.Print() << " collapses: " << targetCollapses << logxx::endl;
                                        idealDeck = testDeck;
                                }
//                                log(logxx::info) << "Collapses: " << logxx::endl;
//                                for (auto &pair : testDeck.collapses){
//                                        log(logxx::info) << pair.first.Print() << ": " << pair.second << logxx::endl;
//                                }
//                                break;
                        }
                } else {
                        static time_t start(time(nullptr));
                        time_t now(time(nullptr));
                        static const time_t interval = 60;
                        if (now > start + interval){
                                log(logxx::info) << i << logxx::endl;
                                break;
//                                start = now;
//                                Deck test(deck);
//                                test.Print(true);
                        }
                }
//                if (std::find(deck.begin(), deck.end(), target) != end()){
//                        Deck test(deck);
//                        test.Print(true);
//                        break;
//                }
//                if (!std::next_permutation(deck.begin(), deck.end()))
//                        break;
                std::random_shuffle(deck.begin(), deck.end(), rnd);
        }
        log(logxx::info) << "Selected deck: " << logxx::endl;
        idealDeck.Print(true);
        log(logxx::info) << "Collapses: " << logxx::endl;
        for (auto &pair : idealDeck.collapses){
                log(logxx::info) << pair.first.Print() << ": " << pair.second << logxx::endl;
        }

        return 0;
}
<commit_msg>added dream hacking<commit_after>#include <algorithm>
#include <limits>

#include "../sources/logxx/logxx.h"
#include "../sources/patience/medici.h"

static logxx::Log cLog("test");

inline bool Conditions(const std::vector<PlayingCard> &deck, const PlayingCard &target){
        decltype(deck.begin()) targetBegin = deck.begin() + 19;
        decltype(deck.begin()) targetEnd = deck.begin() + 25;

        decltype(deck.begin()) ownActionsBegin = deck.begin() + 3;
        decltype(deck.begin()) ownActionsEnd = deck.begin() + 9;

        return
                deck[0].GetNumber() == PlayingCard::Jack &&
                deck[1].GetNumber() == PlayingCard::Nine &&
                (deck[2].GetNumber() == PlayingCard::Ace || deck[2].GetNumber() == PlayingCard::Ten) &&
                std::find(targetBegin, targetEnd, target) != targetEnd &&
                std::find_if(ownActionsBegin, ownActionsEnd, [](const PlayingCard& p)->bool{
                        return p.GetNumber() == PlayingCard::Ace;
                }) == ownActionsEnd &&
                deck[35].GetNumber() == PlayingCard::Ten;
}

size_t rnd(size_t i){ return std::rand() % i; }

void PrintDeck(const std::vector<PlayingCard>& deck, bool abbrevations = true){
        S_LOG("PrintDeck");
        auto &s = log(logxx::info);
        for (auto it = deck.begin(); it != deck.end(); ++it){
                const PlayingCard &card = *it;
                s << card.Print(abbrevations);
                if (it + 1 != deck.end())
                        s << ", ";
        }
        s << logxx::endl;
}

void PrintDeck(const Deck& d, bool abbrevations = true){
        PrintDeck(d.GetDeck(), abbrevations);
}

int main() {
        S_LOG("main");
//        log(logxx::info) << "Testing card" << logxx::endl;
//        PlayingCard card;
//        bool reachedEnd(false);
//        int cnt(0);
//        while (!reachedEnd){
//                log(logxx::info) << "Card: " << card.Print(true) << " -> " << card.Print() << logxx::endl;
//                card.Next(reachedEnd);
//                ++cnt;
//        }
//        log(logxx::info) << "Total " << cnt << " cards" << logxx::endl;
//        if (cnt != 36)
//                return 1;
//
//        Deck initialDeck;
//        log(logxx::info) << "Deck:" << logxx::endl;
//        initialDeck.Print(false);
//        log(logxx::info) << "Deck in abbrevations:" << logxx::endl;
//        initialDeck.Print(true);
//
//        std::vector<Deck> decks;
//        for (int i = 0; i < 100000; ++i){
//                decks.push_back(initialDeck);
//                if (!initialDeck.Next()){
//                        log(logxx::error) << "Reached an end of sequences!" << logxx::endl;
//                        return 1;
//                }
//        }
//        std::sort(decks.begin(), decks.end());
//        if (std::adjacent_find(decks.begin(), decks.end()) != decks.end()){
//                log(logxx::error) << "Found duplicate" << logxx::endl;
//                return 1;
//        } else
//                log(logxx::info) << "No duplicates found" << logxx::endl;
//
//        static const long int permutations = 1E8;
//        time_t start(time(nullptr));
//        for (long int i = 0; i < permutations; ++i)
//                initialDeck.Next();
//        log(logxx::info) << permutations << " permutations done in " << time(nullptr) - start << " seconds" << logxx::endl;

        //PlayingCard card(std::pair<PlayingCard::Suit, PlayingCard::Number>(PlayingCard::Hearts, PlayingCard::Seven));
//        PlayingCard card{PlayingCard::Seven, PlayingCard::Hearts};
        //Тб 7п Кк Тч 9к Кп 6п 8п 10ч 7к 8к Вп 6ч 6к Вч Тп Дп Вк 7б 7ч 9п 10п 10к Вб Кч 10б 8ч 9ч Кб Дч Дб 8б Дк 6б Тк 9б
//        std::string deskStr = "Вч 9к Тч Вк 7п Xк 9п 7ч 9ч Тб 6ч Дп 8ч Кб Тп Xп Вб 8п 7к 9б 6п Дч Кч Вп Xч Кп 8к Дб Xб 8б 6к Дк 7б Тк 6б Кк";
//        Deck test(deskStr);
//        log(logxx::info) << "Collapsed? " << std::boolalpha << test.Collapse() << logxx::endl;
//        Deck test({
//                {PlayingCard::Ace, PlayingCard::Hearts}
//        });
        //std::vector<PlayingCard> headerDeck({PlayingCard("В"), PlayingCard("9"), PlayingCard("Т")});

//        Deck deck;
//        deck.Print(true);

//	std::srand(time(nullptr));
//
//        PlayingCard target("Xч");
//        Medici testDeck;
//        Medici idealDeck;
//        std::vector<PlayingCard> deck = Deck::GenerateDeck();
////        unsigned int maxCollapses(0);
//        long int collapsed(0), conditionsMet(0);
//        for (long long int i = 0; i < std::numeric_limits<decltype(i)>::max(); ++i){
////                if (Conditions(deck, target)){
////                        testDeck.SetDeck(deck);
////                        if (testDeck.Collapse()){
////                                auto targetCollapses = testDeck.GetCollapses(target);
////                                if (targetCollapses > maxCollapses){
////                                        maxCollapses = targetCollapses;
////                                        PrintDeck(testDeck);
////                                        log(logxx::info) << target.Print() << " collapses: " << targetCollapses << logxx::endl;
////                                        idealDeck = testDeck;
////                                }
////                        }
////                } else {
//		if (Conditions(deck, target)){
//			++conditionsMet;
//                	testDeck.SetDeck(deck);
//	                if (testDeck.Collapse())
//	                        ++collapsed;
//		}
//
//                        static time_t start(time(nullptr));
//                        time_t now(time(nullptr));
//                        static const time_t maxExecutionTime = 60;
//                        if (now > start + maxExecutionTime){
//                                log(logxx::info) << "Combinations: " << i << logxx::endl;
//                                break;
//                        }
////                }
//                //std::random_shuffle(deck.begin(), deck.end(), rnd);
//                Deck::Mix(deck, rnd);
//        }
//        log(logxx::info) << "Collapsed: " << collapsed << logxx::endl;
//        log(logxx::info) << "Conditions met: " << conditionsMet << logxx::endl;

//        Deck::Mix()

//        log(logxx::info) << "Selected deck: " << logxx::endl;
//        PrintDeck(idealDeck);
//        log(logxx::info) << "Collapses: " << logxx::endl;
//        for (auto &pair : idealDeck.GetCollapses()){
//                log(logxx::info) << pair.first.Print() << ": " << pair.second << logxx::endl;
//        }

        return 0;
}
<|endoftext|>


<commit_before>#include <sx/ResFileHelper.h>
#include <ns/NodeFactory.h>
#include <node0/SceneNode.h>
#include <node0/CompComplex.h>
#include <unirender/Factory.h>
#include <ns/RegistCallback.h>
#include <facade/Facade.h>
#include <shadergraph/Evaluator.h>
#include <shadergraph/Block.h>
#include <shadergraph/ShaderGraph.h>
#include <shadergraph/block/FragmentShader.h>
#include <js/RapidJsonHelper.h>
#include <dag/Node.h>
#include <unirender/typedef.h>
#include <unirender/Device.h>
#include <unirender/ShaderProgram.h>
#include <unirender/TextureDescription.h>
#include <unirender/Framebuffer.h>
#include <unirender/Context.h>
#include <unirender/DrawState.h>
#include <unirender/ClearState.h>
#include <gimg_export.h>
#include <gimg_typedef.h>

#include <blueprint/Node.h>
#include <blueprint/Pin.h>
#include <blueprint/Connecting.h>
#include <blueprint/Blueprint.h>
#include <blueprint/CompNode.h>
#include <blueprint/NSCompNode.h>
#include <blueprint/SerializeHelper.h>
#include <blueprint/node/SubGraph.h>
#include <shaderlab/ShaderLab.h>
#include <shaderlab/ShaderAdapter.h>
#include <shaderlab/Evaluator.h>
#include <shaderlab/Node.h>
#include <shaderlab/node/Texture2DAsset.h>

#include <gl/glew.h>
#include <glfw3.h>

#include <boost/filesystem.hpp>

#include <stdio.h>
#include <stdlib.h>

namespace
{

const char* vs = R"(
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

void main()
{
	gl_Position = vec4(aPos, 0.0, 1.0);
	TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
)";

const int TEX_SIZE = 512;

uint8_t* BUFFER = nullptr;

}

void error_callback(int error, const char* description)
{
    fputs(description, stderr);
}

bool init_gl()
{
	glfwSetErrorCallback(error_callback);
	if (!glfwInit()) {
		exit(EXIT_FAILURE);
		return false;
	}

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
	GLFWwindow* window = glfwCreateWindow(100, 100, "rotate-crop", nullptr, nullptr);
	if (!window)
	{
		glfwTerminate();
		return false;
	}
	glfwMakeContextCurrent(window);

	// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
	glewExperimental = GL_TRUE;
	//// Initialize GLEW to setup the OpenGL Function pointers
	//if (glewInit() != GLEW_OK) {
	//	return -1;
	//}

	return true;
}

std::shared_ptr<ur::ShaderProgram>
build_shader(const ur::Device& dev, const std::vector<bp::NodePtr>& front_nodes,
             const std::vector<std::shared_ptr<dag::Node<shadergraph::Variant>>>& back_nodes,
             std::vector<std::pair<size_t, ur::TexturePtr>>& textures)
{
    shadergraph::Evaluator eval;

    std::string fs;

    // build frag m_shader
    for (auto& back : back_nodes)
    {
        if (!back) {
            continue;
        }
        auto block = std::static_pointer_cast<shadergraph::Block>(back);
        if (block->get_type() == rttr::type::get<shadergraph::block::FragmentShader>())
        {
            eval.Rebuild(block);
            fs = eval.GenShaderCode();
            break;
        }
    }

    if (fs.empty()) {
        return nullptr;
    }

    auto shader = dev.CreateShaderProgram(vs, fs);
    if (!shader->CheckStatus()) {
        return nullptr;
    }

    // textures
    assert(front_nodes.size() == back_nodes.size());
    for (int i = 0, n = front_nodes.size(); i < n; ++i)
    {
        auto& front = front_nodes[i];
        auto& back = back_nodes[i];
        if (front->get_type() != rttr::type::get<shaderlab::node::Texture2DAsset>()) {
            continue;
        }

        auto tex = std::static_pointer_cast<shaderlab::node::Texture2DAsset>(front)->GetTexture();
        if (!tex) {
            continue;
        }

        assert(back);
        auto block = std::static_pointer_cast<shadergraph::Block>(back);
        auto name = eval.QueryRealName(&block->GetExports()[0].var.type);

        auto slot = shader->QueryTexSlot(name);
        if (slot >= 0) {
            textures.push_back({ slot, tex });
        }
    }

    // update uniforms
    shaderlab::Evaluator::UpdateUniforms(eval, shader);

    return shader;
}

void test_file(const ur::Device& dev, ur::Context& ctx,
               const std::shared_ptr<ur::Framebuffer>& rt,
               const std::string& filepath)
{
    auto dir = boost::filesystem::path(filepath).parent_path().string();

    auto root = ns::NodeFactory::Create(dev, filepath);

    auto& ccomplex = root->GetSharedComp<n0::CompComplex>();
    auto& children = ccomplex.GetAllChildren();

    // update subgraph
    for (auto& c : children)
    {
        if (!c->HasUniqueComp<bp::CompNode>()) {
            continue;
        }
        auto bp_node = c->GetUniqueComp<bp::CompNode>().GetNode();
        if (!bp_node->get_type().is_derived_from<bp::node::SubGraph<shadergraph::Variant>>()) {
            continue;
        }
        assert(c->HasSharedComp<n0::CompComplex>());
        auto& c_ccomplex = c->GetSharedComp<n0::CompComplex>();
        std::vector<bp::NodePtr> bp_nodes;
        for (auto& cc : c_ccomplex.GetAllChildren()) {
            if (cc->HasUniqueComp<bp::CompNode>()) {
                bp_nodes.push_back(cc->GetUniqueComp<bp::CompNode>().GetNode());
            }
        }
        auto sub_graph = std::static_pointer_cast<bp::node::SubGraph<shadergraph::Variant>>(bp_node);
        sub_graph->SetChildren(bp_nodes);
    }

    std::vector<bp::NodePtr> front_nodes(children.size(), nullptr);
    std::vector<std::shared_ptr<dag::Node<shadergraph::Variant>>> back_nodes(children.size(), nullptr);

    bp::SerializeHelper::SetupNodes<shaderlab::Node, shadergraph::Variant>(
        children, "shaderlab", "shadergraph", front_nodes, back_nodes
    );
    assert(front_nodes.size() == back_nodes.size());
    for (int i = 0, n = front_nodes.size(); i < n; ++i) {
        shaderlab::ShaderAdapter::Front2Back(*front_nodes[i], *back_nodes[i], dir, dev);
    }

    bp::SerializeHelper::SetupConnections(filepath, children, front_nodes, back_nodes);

    std::vector<std::pair<size_t, ur::TexturePtr>> textures;
    auto shader = build_shader(dev, front_nodes, back_nodes, textures);

    ctx.SetFramebuffer(rt);
    ctx.SetViewport(0, 0, TEX_SIZE, TEX_SIZE);

    ur::ClearState clear;
    clear.buffers = ur::ClearBuffers::ColorAndDepthBuffer;
    clear.color.FromRGBA(0x88888888);
    ctx.Clear(clear);

    ur::DrawState ds;
    ds.program      = shader;
    ds.render_state = ur::DefaultRenderState2D();
    ds.vertex_array = dev.GetVertexArray(ur::Device::PrimitiveType::Quad, ur::VertexLayoutType::PosTex);

    for (auto& t : textures) {
        ctx.SetTexture(t.first, t.second);
    }

    ctx.Draw(ur::PrimitiveType::TriangleStrip, ds, nullptr);

    dev.ReadPixels(BUFFER, ur::TextureFormat::RGB, 0, 0, TEX_SIZE, TEX_SIZE);

    auto out_filepath = filepath.substr(0, filepath.find_last_of('.')) + ".jpg";
    gimg_export(out_filepath.c_str(), BUFFER, TEX_SIZE, TEX_SIZE, GPF_RGB, false);

    ctx.SetFramebuffer(nullptr);
}

void test_folder(const ur::Device& dev, ur::Context& ctx,
                 const std::string& dir)
{
    ur::TextureDescription desc;
    desc.target = ur::TextureTarget::Texture2D;
    desc.width  = TEX_SIZE;
    desc.height = TEX_SIZE;
    desc.format = ur::TextureFormat::RGB;
    auto tex = dev.CreateTexture(desc);

    auto fbo = dev.CreateFramebuffer();
    fbo->SetAttachment(ur::AttachmentType::Color0, ur::TextureTarget::Texture2D, tex, nullptr);

    boost::filesystem::recursive_directory_iterator itr(dir), end;
    while (itr != end)
    {
        if (boost::filesystem::is_regular(itr->path()))
        {
            auto path = itr->path().string();
            if (sx::ResFileHelper::Type(path) == sx::ResFileType::RES_FILE_JSON) {
                test_file(dev, ctx, fbo, path);
            }
        }
        ++itr;
    }
}

int main()
{
    init_gl();

    auto dev = ur::CreateDeviceGL();
    auto ctx = ur::CreateContextGL(*dev);

    ns::RegistCallback::Init();
    facade::Facade::Instance()->Init(*dev);
    bp::Blueprint::Instance();
    shadergraph::ShaderGraph::Instance();
    shaderlab::ShaderLab::Instance();

    bp::SerializeHelper::SetupConnCB();

    BUFFER = new uint8_t[TEX_SIZE * TEX_SIZE * 4];

    // fixme: id
    auto node = std::make_shared<n0::SceneNode>();
    node->AddSharedComp<n0::CompComplex>();

    test_folder(*dev, *ctx, "../../../test/cases");

    return 0;
}<commit_msg>up api<commit_after>#include <sx/ResFileHelper.h>
#include <ns/NodeFactory.h>
#include <node0/SceneNode.h>
#include <node0/CompComplex.h>
#include <unirender/Factory.h>
#include <ns/RegistCallback.h>
#include <facade/Facade.h>
#include <shadergraph/Evaluator.h>
#include <shadergraph/Block.h>
#include <shadergraph/ShaderGraph.h>
#include <shadergraph/block/FragmentShader.h>
#include <js/RapidJsonHelper.h>
#include <dag/Node.h>
#include <unirender/typedef.h>
#include <unirender/Device.h>
#include <unirender/ShaderProgram.h>
#include <unirender/TextureDescription.h>
#include <unirender/Framebuffer.h>
#include <unirender/Context.h>
#include <unirender/DrawState.h>
#include <unirender/ClearState.h>
#include <gimg_export.h>
#include <gimg_typedef.h>

#include <blueprint/Node.h>
#include <blueprint/Pin.h>
#include <blueprint/Connecting.h>
#include <blueprint/Blueprint.h>
#include <blueprint/CompNode.h>
#include <blueprint/NSCompNode.h>
#include <blueprint/SerializeHelper.h>
#include <blueprint/node/SubGraph.h>
#include <shaderlab/ShaderLab.h>
#include <shaderlab/ShaderAdapter.h>
#include <shaderlab/Evaluator.h>
#include <shaderlab/Node.h>
#include <shaderlab/node/Texture2DAsset.h>

#include <gl/glew.h>
#include <glfw3.h>

#include <boost/filesystem.hpp>

#include <stdio.h>
#include <stdlib.h>

namespace
{

const char* vs = R"(
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

void main()
{
	gl_Position = vec4(aPos, 0.0, 1.0);
	TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
)";

const int TEX_SIZE = 512;

uint8_t* BUFFER = nullptr;

}

void error_callback(int error, const char* description)
{
    fputs(description, stderr);
}

bool init_gl()
{
	glfwSetErrorCallback(error_callback);
	if (!glfwInit()) {
		exit(EXIT_FAILURE);
		return false;
	}

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
	GLFWwindow* window = glfwCreateWindow(100, 100, "rotate-crop", nullptr, nullptr);
	if (!window)
	{
		glfwTerminate();
		return false;
	}
	glfwMakeContextCurrent(window);

	// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
	glewExperimental = GL_TRUE;
	//// Initialize GLEW to setup the OpenGL Function pointers
	//if (glewInit() != GLEW_OK) {
	//	return -1;
	//}

	return true;
}

std::shared_ptr<ur::ShaderProgram>
build_shader(const ur::Device& dev, const std::vector<bp::NodePtr>& front_nodes,
             const std::vector<std::shared_ptr<dag::Node<shadergraph::Variant>>>& back_nodes,
             std::vector<std::pair<size_t, ur::TexturePtr>>& textures)
{
    shadergraph::Evaluator eval;

    std::string fs;

    // build frag m_shader
    for (auto& back : back_nodes)
    {
        if (!back) {
            continue;
        }
        auto block = std::static_pointer_cast<shadergraph::Block>(back);
        if (block->get_type() == rttr::type::get<shadergraph::block::FragmentShader>())
        {
            eval.Rebuild(block);
            fs = eval.GenShaderCode();
            break;
        }
    }

    if (fs.empty()) {
        return nullptr;
    }

    auto shader = dev.CreateShaderProgram(vs, fs);
    if (!shader->CheckStatus()) {
        return nullptr;
    }

    // textures
    assert(front_nodes.size() == back_nodes.size());
    for (int i = 0, n = front_nodes.size(); i < n; ++i)
    {
        auto& front = front_nodes[i];
        auto& back = back_nodes[i];
        if (front->get_type() != rttr::type::get<shaderlab::node::Texture2DAsset>()) {
            continue;
        }

        auto tex = std::static_pointer_cast<shaderlab::node::Texture2DAsset>(front)->GetTexture();
        if (!tex) {
            continue;
        }

        assert(back);
        auto block = std::static_pointer_cast<shadergraph::Block>(back);
        auto name = eval.QueryRealName(&block->GetExports()[0].var.type);

        auto slot = shader->QueryTexSlot(name);
        if (slot >= 0) {
            textures.push_back({ slot, tex });
        }
    }

    // update uniforms
    shaderlab::Evaluator::UpdateUniforms(eval, shader);

    return shader;
}

void test_file(const ur::Device& dev, ur::Context& ctx,
               const std::shared_ptr<ur::Framebuffer>& rt,
               const std::string& filepath)
{
    auto dir = boost::filesystem::path(filepath).parent_path().string();

    auto root = ns::NodeFactory::Create(dev, filepath);

    auto& ccomplex = root->GetSharedComp<n0::CompComplex>();
    auto& children = ccomplex.GetAllChildren();

    // update subgraph
    for (auto& c : children)
    {
        if (!c->HasUniqueComp<bp::CompNode>()) {
            continue;
        }
        auto bp_node = c->GetUniqueComp<bp::CompNode>().GetNode();
        if (!bp_node->get_type().is_derived_from<bp::node::SubGraph<shadergraph::Variant>>()) {
            continue;
        }
        assert(c->HasSharedComp<n0::CompComplex>());
        auto& c_ccomplex = c->GetSharedComp<n0::CompComplex>();
        std::vector<bp::NodePtr> bp_nodes;
        for (auto& cc : c_ccomplex.GetAllChildren()) {
            if (cc->HasUniqueComp<bp::CompNode>()) {
                bp_nodes.push_back(cc->GetUniqueComp<bp::CompNode>().GetNode());
            }
        }
        auto sub_graph = std::static_pointer_cast<bp::node::SubGraph<shadergraph::Variant>>(bp_node);
        sub_graph->SetChildren(bp_nodes);
    }

    std::vector<bp::NodePtr> front_nodes(children.size(), nullptr);
    std::vector<std::shared_ptr<dag::Node<shadergraph::Variant>>> back_nodes(children.size(), nullptr);

    bp::SerializeHelper::SetupNodes<shaderlab::Node, shadergraph::Variant>(
        children, "shaderlab", "shadergraph", front_nodes, back_nodes
    );
    assert(front_nodes.size() == back_nodes.size());
    for (int i = 0, n = front_nodes.size(); i < n; ++i) {
        shaderlab::ShaderAdapter::Front2Back(*front_nodes[i], *back_nodes[i], dir, dev);
    }

    bp::SerializeHelper::SetupConnections(filepath, children, front_nodes, back_nodes);

    std::vector<std::pair<size_t, ur::TexturePtr>> textures;
    auto shader = build_shader(dev, front_nodes, back_nodes, textures);

    ctx.SetFramebuffer(rt);
    ctx.SetViewport(0, 0, TEX_SIZE, TEX_SIZE);

    ur::ClearState clear;
    clear.buffers = ur::ClearBuffers::ColorAndDepthBuffer;
    clear.color.FromRGBA(0x88888888);
    ctx.Clear(clear);

    ur::DrawState ds;
    ds.program      = shader;
    ds.render_state = ur::DefaultRenderState2D();
    ds.vertex_array = dev.GetVertexArray(ur::Device::PrimitiveType::Quad, ur::VertexLayoutType::PosTex);

    for (auto& t : textures) {
        ctx.SetTexture(t.first, t.second);
    }

    ctx.Draw(ur::PrimitiveType::TriangleStrip, ds, nullptr);

    dev.ReadPixels(BUFFER, ur::TextureFormat::RGB, 0, 0, TEX_SIZE, TEX_SIZE);

    auto out_filepath = filepath.substr(0, filepath.find_last_of('.')) + ".jpg";
    gimg_export(out_filepath.c_str(), BUFFER, TEX_SIZE, TEX_SIZE, GPF_RGB, false);

    ctx.SetFramebuffer(nullptr);
}

void test_folder(const ur::Device& dev, ur::Context& ctx,
                 const std::string& dir)
{
    ur::TextureDescription desc;
    desc.target = ur::TextureTarget::Texture2D;
    desc.width  = TEX_SIZE;
    desc.height = TEX_SIZE;
    desc.format = ur::TextureFormat::RGB;
    auto tex = dev.CreateTexture(desc);

    auto fbo = dev.CreateFramebuffer();
    fbo->SetAttachment(ur::AttachmentType::Color0, ur::TextureTarget::Texture2D, tex, nullptr);

    boost::filesystem::recursive_directory_iterator itr(dir), end;
    while (itr != end)
    {
        if (boost::filesystem::is_regular(itr->path()))
        {
            auto path = itr->path().string();
            if (sx::ResFileHelper::Type(path) == sx::ResFileType::RES_FILE_JSON) {
                test_file(dev, ctx, fbo, path);
            }
        }
        ++itr;
    }
}

int main()
{
    init_gl();

    auto dev = ur::CreateDeviceGL(nullptr);
    auto ctx = ur::CreateContextGL(*dev);

    ns::RegistCallback::Init();
    facade::Facade::Instance()->Init(*dev);
    bp::Blueprint::Instance();
    shadergraph::ShaderGraph::Instance();
    shaderlab::ShaderLab::Instance();

    bp::SerializeHelper::SetupConnCB();

    BUFFER = new uint8_t[TEX_SIZE * TEX_SIZE * 4];

    // fixme: id
    auto node = std::make_shared<n0::SceneNode>();
    node->AddSharedComp<n0::CompComplex>();

    test_folder(*dev, *ctx, "../../../test/cases");

    return 0;
}<|endoftext|>