<commit_before>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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.
 */
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <graphene/chain/protocol/block.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
#include <fc/smart_ref_impl.hpp>
#include <algorithm>

namespace graphene { namespace chain {

digest_type processed_transaction::merkle_digest()const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, *this );
   return enc.result();
}

digest_type transaction::digest()const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, *this );
   return enc.result();
}

digest_type transaction::sig_digest( const chain_id_type& chain_id )const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
   fc::raw::pack( enc, *this );
   return enc.result();
}

void transaction::validate() const
{
   FC_ASSERT( operations.size() > 0, "A transaction must have at least one operation", ("trx",*this) );
   for( const auto& op : operations )
      operation_validate(op);
}

graphene::chain::transaction_id_type graphene::chain::transaction::id() const
{
   auto h = digest();
   transaction_id_type result;
   memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h)));
   return result;
}

const signature_type& graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)
{
   digest_type h = sig_digest( chain_id );
   signatures.push_back(key.sign_compact(h));
   return signatures.back();
}

signature_type graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
   fc::raw::pack( enc, *this );
   return key.sign_compact(enc.result());
}

void transaction::set_expiration( fc::time_point_sec expiration_time )
{
    expiration = expiration_time;
}

void transaction::set_reference_block( const block_id_type& reference_block )
{
   ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]);
   ref_block_prefix = reference_block._hash[1];
}

void transaction::get_required_authorities( flat_set<account_id_type>& active, flat_set<account_id_type>& owner, vector<authority>& other )const
{
   for( const auto& op : operations )
      operation_get_required_authorities( op, active, owner, other );
   for( const auto& account : owner )
      active.erase( account );
}

const flat_set<public_key_type> empty_keyset;

struct sign_state
{
      /** returns true if we have a signature for this key or can
       * produce a signature for this key, else returns false.
       */
      bool signed_by( const public_key_type& k )
      {
         auto itr = provided_signatures.find(k);
         if( itr == provided_signatures.end() )
         {
            auto pk = available_keys.find(k);
            if( pk  != available_keys.end() )
               return provided_signatures[k] = true;
            return false;
         }
         return itr->second = true;
      }

      optional<map<address,public_key_type>> available_address_sigs;
      optional<map<address,public_key_type>> provided_address_sigs;

      bool signed_by( const address& a ) {
         if( !available_address_sigs ) {
            available_address_sigs = std::map<address,public_key_type>();
            provided_address_sigs = std::map<address,public_key_type>();
            for( auto& item : available_keys ) {
             (*available_address_sigs)[ address(pts_address(item, false, 56) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, true, 56) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, false, 0) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, true, 0) ) ] = item;
             (*available_address_sigs)[ address(item) ] = item;
            }
            for( auto& item : provided_signatures ) {
             (*provided_address_sigs)[ address(pts_address(item.first, false, 56) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, true, 56) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, false, 0) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, true, 0) ) ] = item.first;
             (*provided_address_sigs)[ address(item.first) ] = item.first;
            }
         }
         auto itr = provided_address_sigs->find(a);
         if( itr == provided_address_sigs->end() )
         {
            auto aitr = available_address_sigs->find(a);
            if( aitr != available_address_sigs->end() ) {
               auto pk = available_keys.find(aitr->second);
               if( pk != available_keys.end() )
                  return provided_signatures[aitr->second] = true;
               return false;
            }
         }
         return provided_signatures[itr->second] = true;
      }

      bool check_authority( account_id_type id )
      {
         if( approved_by.find(id) != approved_by.end() ) return true;
         return check_authority( get_active(id) );
      }

      /**
       *  Checks to see if we have signatures of the active authorites of
       *  the accounts specified in authority or the keys specified.
       */
      bool check_authority( const authority* au, uint32_t depth = 0 )
      {
         if( au == nullptr ) return false;
         const authority& auth = *au;

         uint32_t total_weight = 0;
         for( const auto& k : auth.key_auths )
            if( signed_by( k.first ) )
            {
               total_weight += k.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }

         for( const auto& k : auth.address_auths )
            if( signed_by( k.first ) )
            {
               total_weight += k.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }

         for( const auto& a : auth.account_auths )
         {
            if( approved_by.find(a.first) == approved_by.end() )
            {
               if( depth == max_recursion )
                  continue;
               if( check_authority( get_active( a.first ), depth+1 ) )
               {
                  approved_by.insert( a.first );
                  total_weight += a.second;
                  if( total_weight >= auth.weight_threshold )
                     return true;
               }
            }
            else
            {
               total_weight += a.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }
         }
         return total_weight >= auth.weight_threshold;
      }

      bool remove_unused_signatures()
      {
         vector<public_key_type> remove_sigs;
         for( const auto& sig : provided_signatures )
            if( !sig.second ) remove_sigs.push_back( sig.first );

         for( auto& sig : remove_sigs )
            provided_signatures.erase(sig);

         return remove_sigs.size() != 0;
      }

      sign_state( const flat_set<public_key_type>& sigs,
                  const std::function<const authority*(account_id_type)>& a,
                  const flat_set<public_key_type>& keys = empty_keyset )
      :get_active(a),available_keys(keys)
      {
         for( const auto& key : sigs )
            provided_signatures[ key ] = false;
         approved_by.insert( GRAPHENE_TEMP_ACCOUNT  );
      }

      const std::function<const authority*(account_id_type)>& get_active;
      const flat_set<public_key_type>&                        available_keys;

      flat_map<public_key_type,bool>   provided_signatures;
      flat_set<account_id_type>        approved_by;
      uint32_t                         max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH;
};

void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
                       const std::function<const authority*(account_id_type)>& get_active,
                       const std::function<const authority*(account_id_type)>& get_owner,
                       uint32_t max_recursion_depth,
                       bool  allow_committe,
                       const flat_set<account_id_type>& active_aprovals,
                       const flat_set<account_id_type>& owner_approvals )
{ try {
   flat_set<account_id_type> required_active;
   flat_set<account_id_type> required_owner;
   vector<authority> other;

   for( const auto& op : ops )
      operation_get_required_authorities( op, required_active, required_owner, other );

   if( !allow_committe )
      GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
                       invalid_committee_approval, "Committee account may only propose transactions" );

   sign_state s(sigs,get_active);
   s.max_recursion = max_recursion_depth;
   for( auto& id : active_aprovals )
      s.approved_by.insert( id );
   for( auto& id : owner_approvals )
      s.approved_by.insert( id );

   for( const auto& auth : other )
   {
      GRAPHENE_ASSERT( s.check_authority(&auth), tx_missing_other_auth, "Missing Authority", ("auth",auth)("sigs",sigs) );
   }

   // fetch all of the top level authorities
   for( auto id : required_owner )
   {
      GRAPHENE_ASSERT( owner_approvals.find(id) != owner_approvals.end() ||
                       s.check_authority(get_owner(id)),
                       tx_missing_owner_auth, "Missing Owner Authority ${id}", ("id",id)("auth",*get_owner(id)) );
   }

   for( auto id : required_active )
   {
      GRAPHENE_ASSERT( s.check_authority(id) ||
                       s.check_authority(get_owner(id)),
                       tx_missing_active_auth, "Missing Active Authority ${id}",
                       ("id",id)("auth",*get_active(id))("owner",*get_owner(id)) );
   }

   GRAPHENE_ASSERT(
      !s.remove_unused_signatures(),
      tx_irrelevant_sig,
      "Unnecessary signature(s) detected"
      );
} FC_CAPTURE_AND_RETHROW( (ops)(sigs) ) }

flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id_type& chain_id )const
{ try {
   auto d = sig_digest( chain_id );
   flat_set<public_key_type> result;
   for( const auto&  sig : signatures )
   {
      GRAPHENE_ASSERT(
         result.insert( fc::ecc::public_key(sig,d) ).second,
         tx_duplicate_sig,
         "Duplicate Signature detected" );
   }
   return result;
} FC_CAPTURE_AND_RETHROW() }

set<public_key_type> signed_transaction::get_required_signatures(
   const chain_id_type& chain_id,
   const flat_set<public_key_type>& available_keys,
   const std::function<const authority*(account_id_type)>& get_active,
   const std::function<const authority*(account_id_type)>& get_owner,
   uint32_t max_recursion_depth )const
{
   flat_set<account_id_type> required_active;
   flat_set<account_id_type> required_owner;
   vector<authority> other;
   get_required_authorities( required_active, required_owner, other );

   flat_set<public_key_type> signature_keys = get_signature_keys( chain_id );
   sign_state s( signature_keys, get_active, available_keys );
   s.max_recursion = max_recursion_depth;

   for( const auto& auth : other )
      s.check_authority(&auth);
   for( auto& owner : required_owner )
      s.check_authority( get_owner( owner ) );
   for( auto& active : required_active )
      s.check_authority( active ) || s.check_authority( get_owner( active ) );

   s.remove_unused_signatures();

   set<public_key_type> result;

   for( auto& provided_sig : s.provided_signatures )
      if( available_keys.find( provided_sig.first ) != available_keys.end()
            && signature_keys.find( provided_sig.first ) == signature_keys.end() )
         result.insert( provided_sig.first );

   return result;
}

set<public_key_type> signed_transaction::minimize_required_signatures(
   const chain_id_type& chain_id,
   const flat_set<public_key_type>& available_keys,
   const std::function<const authority*(account_id_type)>& get_active,
   const std::function<const authority*(account_id_type)>& get_owner,
   uint32_t max_recursion
   ) const
{
   set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, max_recursion );
   flat_set< public_key_type > result( s.begin(), s.end() );

   for( const public_key_type& k : s )
   {
      result.erase( k );
      try
      {
         graphene::chain::verify_authority( operations, result, get_active, get_owner, max_recursion );
         continue;  // element stays erased if verify_authority is ok
      }
      catch( const tx_missing_owner_auth& e ) {}
      catch( const tx_missing_active_auth& e ) {}
      catch( const tx_missing_other_auth& e ) {}
      result.insert( k );
   }
   return set<public_key_type>( result.begin(), result.end() );
}

void signed_transaction::verify_authority(
   const chain_id_type& chain_id,
   const std::function<const authority*(account_id_type)>& get_active,
   const std::function<const authority*(account_id_type)>& get_owner,
   uint32_t max_recursion )const
{ try {
   graphene::chain::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, max_recursion );
} FC_CAPTURE_AND_RETHROW( (*this) ) }

} } // graphene::chain
<commit_msg>Removed trailing whitespaces from code<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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.
 */
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
#include <graphene/chain/protocol/block.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
#include <fc/smart_ref_impl.hpp>
#include <algorithm>

namespace graphene { namespace chain {

digest_type processed_transaction::merkle_digest()const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, *this );
   return enc.result();
}

digest_type transaction::digest()const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, *this );
   return enc.result();
}

digest_type transaction::sig_digest( const chain_id_type& chain_id )const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
   fc::raw::pack( enc, *this );
   return enc.result();
}

void transaction::validate() const
{
   FC_ASSERT( operations.size() > 0, "A transaction must have at least one operation", ("trx",*this) );
   for( const auto& op : operations )
      operation_validate(op);
}

graphene::chain::transaction_id_type graphene::chain::transaction::id() const
{
   auto h = digest();
   transaction_id_type result;
   memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h)));
   return result;
}

const signature_type& graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)
{
   digest_type h = sig_digest( chain_id );
   signatures.push_back(key.sign_compact(h));
   return signatures.back();
}

signature_type graphene::chain::signed_transaction::sign(const private_key_type& key, const chain_id_type& chain_id)const
{
   digest_type::encoder enc;
   fc::raw::pack( enc, chain_id );
   fc::raw::pack( enc, *this );
   return key.sign_compact(enc.result());
}

void transaction::set_expiration( fc::time_point_sec expiration_time )
{
    expiration = expiration_time;
}

void transaction::set_reference_block( const block_id_type& reference_block )
{
   ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]);
   ref_block_prefix = reference_block._hash[1];
}

void transaction::get_required_authorities( flat_set<account_id_type>& active, flat_set<account_id_type>& owner, vector<authority>& other )const
{
   for( const auto& op : operations )
      operation_get_required_authorities( op, active, owner, other );
   for( const auto& account : owner )
      active.erase( account );
}

const flat_set<public_key_type> empty_keyset;

struct sign_state
{
      /** returns true if we have a signature for this key or can
       * produce a signature for this key, else returns false.
       */
      bool signed_by( const public_key_type& k )
      {
         auto itr = provided_signatures.find(k);
         if( itr == provided_signatures.end() )
         {
            auto pk = available_keys.find(k);
            if( pk  != available_keys.end() )
               return provided_signatures[k] = true;
            return false;
         }
         return itr->second = true;
      }

      optional<map<address,public_key_type>> available_address_sigs;
      optional<map<address,public_key_type>> provided_address_sigs;

      bool signed_by( const address& a ) {
         if( !available_address_sigs ) {
            available_address_sigs = std::map<address,public_key_type>();
            provided_address_sigs = std::map<address,public_key_type>();
            for( auto& item : available_keys ) {
             (*available_address_sigs)[ address(pts_address(item, false, 56) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, true, 56) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, false, 0) ) ] = item;
             (*available_address_sigs)[ address(pts_address(item, true, 0) ) ] = item;
             (*available_address_sigs)[ address(item) ] = item;
            }
            for( auto& item : provided_signatures ) {
             (*provided_address_sigs)[ address(pts_address(item.first, false, 56) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, true, 56) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, false, 0) ) ] = item.first;
             (*provided_address_sigs)[ address(pts_address(item.first, true, 0) ) ] = item.first;
             (*provided_address_sigs)[ address(item.first) ] = item.first;
            }
         }
         auto itr = provided_address_sigs->find(a);
         if( itr == provided_address_sigs->end() )
         {
            auto aitr = available_address_sigs->find(a);
            if( aitr != available_address_sigs->end() ) {
               auto pk = available_keys.find(aitr->second);
               if( pk != available_keys.end() )
                  return provided_signatures[aitr->second] = true;
               return false;
            }
         }
         return provided_signatures[itr->second] = true;
      }

      bool check_authority( account_id_type id )
      {
         if( approved_by.find(id) != approved_by.end() ) return true;
         return check_authority( get_active(id) );
      }

      /**
       *  Checks to see if we have signatures of the active authorites of
       *  the accounts specified in authority or the keys specified.
       */
      bool check_authority( const authority* au, uint32_t depth = 0 )
      {
         if( au == nullptr ) return false;
         const authority& auth = *au;

         uint32_t total_weight = 0;
         for( const auto& k : auth.key_auths )
            if( signed_by( k.first ) )
            {
               total_weight += k.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }

         for( const auto& k : auth.address_auths )
            if( signed_by( k.first ) )
            {
               total_weight += k.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }

         for( const auto& a : auth.account_auths )
         {
            if( approved_by.find(a.first) == approved_by.end() )
            {
               if( depth == max_recursion )
                  continue;
               if( check_authority( get_active( a.first ), depth+1 ) )
               {
                  approved_by.insert( a.first );
                  total_weight += a.second;
                  if( total_weight >= auth.weight_threshold )
                     return true;
               }
            }
            else
            {
               total_weight += a.second;
               if( total_weight >= auth.weight_threshold )
                  return true;
            }
         }
         return total_weight >= auth.weight_threshold;
      }

      bool remove_unused_signatures()
      {
         vector<public_key_type> remove_sigs;
         for( const auto& sig : provided_signatures )
            if( !sig.second ) remove_sigs.push_back( sig.first );

         for( auto& sig : remove_sigs )
            provided_signatures.erase(sig);

         return remove_sigs.size() != 0;
      }

      sign_state( const flat_set<public_key_type>& sigs,
                  const std::function<const authority*(account_id_type)>& a,
                  const flat_set<public_key_type>& keys = empty_keyset )
      :get_active(a),available_keys(keys)
      {
         for( const auto& key : sigs )
            provided_signatures[ key ] = false;
         approved_by.insert( GRAPHENE_TEMP_ACCOUNT  );
      }

      const std::function<const authority*(account_id_type)>& get_active;
      const flat_set<public_key_type>&                        available_keys;

      flat_map<public_key_type,bool>   provided_signatures;
      flat_set<account_id_type>        approved_by;
      uint32_t                         max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH;
};

void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
                       const std::function<const authority*(account_id_type)>& get_active,
                       const std::function<const authority*(account_id_type)>& get_owner,
                       uint32_t max_recursion_depth,
                       bool  allow_committe,
                       const flat_set<account_id_type>& active_aprovals,
                       const flat_set<account_id_type>& owner_approvals )
{ try {
   flat_set<account_id_type> required_active;
   flat_set<account_id_type> required_owner;
   vector<authority> other;

   for( const auto& op : ops )
      operation_get_required_authorities( op, required_active, required_owner, other );

   if( !allow_committe )
      GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
                       invalid_committee_approval, "Committee account may only propose transactions" );

   sign_state s(sigs,get_active);
   s.max_recursion = max_recursion_depth;
   for( auto& id : active_aprovals )
      s.approved_by.insert( id );
   for( auto& id : owner_approvals )
      s.approved_by.insert( id );

   for( const auto& auth : other )
   {
      GRAPHENE_ASSERT( s.check_authority(&auth), tx_missing_other_auth, "Missing Authority", ("auth",auth)("sigs",sigs) );
   }

   // fetch all of the top level authorities
   for( auto id : required_owner )
   {
      GRAPHENE_ASSERT( owner_approvals.find(id) != owner_approvals.end() ||
                       s.check_authority(get_owner(id)),
                       tx_missing_owner_auth, "Missing Owner Authority ${id}", ("id",id)("auth",*get_owner(id)) );
   }

   for( auto id : required_active )
   {
      GRAPHENE_ASSERT( s.check_authority(id) ||
                       s.check_authority(get_owner(id)),
                       tx_missing_active_auth, "Missing Active Authority ${id}",
                       ("id",id)("auth",*get_active(id))("owner",*get_owner(id)) );
   }

   GRAPHENE_ASSERT(
      !s.remove_unused_signatures(),
      tx_irrelevant_sig,
      "Unnecessary signature(s) detected"
      );
} FC_CAPTURE_AND_RETHROW( (ops)(sigs) ) }

flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id_type& chain_id )const
{ try {
   auto d = sig_digest( chain_id );
   flat_set<public_key_type> result;
   for( const auto&  sig : signatures )
   {
      GRAPHENE_ASSERT(
         result.insert( fc::ecc::public_key(sig,d) ).second,
         tx_duplicate_sig,
         "Duplicate Signature detected" );
   }
   return result;
} FC_CAPTURE_AND_RETHROW() }

set<public_key_type> signed_transaction::get_required_signatures(
   const chain_id_type& chain_id,
   const flat_set<public_key_type>& available_keys,
   const std::function<const authority*(account_id_type)>& get_active,
   const std::function<const authority*(account_id_type)>& get_owner,
   uint32_t max_recursion_depth )const
{
   flat_set<account_id_type> required_active;
   flat_set<account_id_type> required_owner;
   vector<authority> other;
   get_required_authorities( required_active, required_owner, other );

   flat_set<public_key_type> signature_keys = get_signature_keys( chain_id );
   sign_state s( signature_keys, get_active, available_keys );
   s.max_recursion = max_recursion_depth;

   for( const auto& auth : other )
      s.check_authority(&auth);
   for( auto& owner : required_owner )
      s.check_authority( get_owner( owner ) );
   for( auto& active : required_active )
      s.check_authority( active ) || s.check_authority( get_owner( active ) );

   s.remove_unused_signatures();

   set<public_key_type> result;

   for( auto& provided_sig : s.provided_signatures )
      if( available_keys.find( provided_sig.first ) != available_keys.end()
            && signature_keys.find( provided_sig.first ) == signature_keys.end() )
         result.insert( provided_sig.first );

   return result;
}

set<public_key_type> signed_transaction::minimize_required_signatures(
   const chain_id_type& chain_id,
   const flat_set<public_key_type>& available_keys,
   const std::function<const authority*(account_id_type)>& get_active,
   const std::function<const authority*(account_id_type)>& get_owner,
   uint32_t max_recursion
   ) const
{
   set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, max_recursion );
   flat_set< public_key_type > result( s.begin(), s.end() );

   for( const public_key_type& k : s )
   {
      result.erase( k );
      try
      {
         graphene::chain::verify_authority( operations, result, get_active, get_owner, max_recursion );
         continue;  // element stays erased if verify_authority is ok
      }
      catch( const tx_missing_owner_auth& e ) {}
      catch( const tx_missing_active_auth& e ) {}
      catch( const tx_missing_other_auth& e ) {}
      result.insert( k );
   }
   return set<public_key_type>( result.begin(), result.end() );
}

void signed_transaction::verify_authority(
   const chain_id_type& chain_id,
   const std::function<const authority*(account_id_type)>& get_active,
   const std::function<const authority*(account_id_type)>& get_owner,
   uint32_t max_recursion )const
{ try {
   graphene::chain::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, max_recursion );
} FC_CAPTURE_AND_RETHROW( (*this) ) }

} } // graphene::chain
<|endoftext|>


<commit_before>#include "segment.h"
#include "gtest/gtest.h"

namespace oop_project {

TEST(SegmentTest, CreatesRandomCars) {
  Segment segment(10, NULL, 50, 5, 5);
  ASSERT_GE(segment.num_cars(), 1);
  ASSERT_LE(segment.num_cars(), Segment::kMaxCars);
  ASSERT_LE(segment.num_cars(), 10);
  ASSERT_LE(segment.ready_cars().size(), 50 * segment.num_cars() / 100);
}

TEST(SegmentTest, EntersLessThanCapacity) {
  Segment prev_segment(10, NULL, 50, 5, 5);
  Segment segment(10, &prev_segment, 50, 5, 5);
  segment.Enter();
  ASSERT_LE(segment.num_cars(), 10);
}

TEST(SegmentTest, RemovesCarsFromFreeway) {
  Segment segment(10, NULL, 50, 5, 5);
  std::vector<Car*> ready_cars = segment.ready_cars();
  size_t num_before_exit = segment.num_cars();

  size_t ready_to_exit = 0;
  for (size_t i = 0; i < ready_cars.size(); ++i) {
    if (ready_cars[i]->exit_junction() == segment.enter_junction() + 1) {
      ++ready_to_exit;
    }
  }

  segment.Exit();
  ASSERT_EQ(segment.num_cars(), num_before_exit - ready_to_exit);
}

TEST(SegmentTest, Operates) {
  Segment segment(10, NULL, 50, 5, 5);
  std::vector<Car*> prev_ready_cars = segment.ready_cars();
  segment.Operate();
  std::vector<Car*> ready_cars = segment.ready_cars();

  ASSERT_GE(ready_cars.size(), prev_ready_cars.size());
  ASSERT_LE(ready_cars.size() - prev_ready_cars.size(),
            50 * segment.num_cars() / 100);
}

TEST(SegmentTest, PassesReadyCars) {
  Segment segment(10, NULL, 50, 5, 5);
  Segment next_segment(10, NULL, 50, 5, 5);
  segment.set_next(&next_segment);

  std::vector<Car*> ready_cars = segment.ready_cars();
  size_t ready_to_pass = 0;
  for (size_t i = 0; i < ready_cars.size(); ++i) {
    if (ready_cars[i]->exit_junction() != segment.enter_junction() + 1) {
        ++ready_to_pass;
    }
  }

  size_t num_before_pass = segment.num_cars();
  segment.Pass(5);
  ASSERT_GE(static_cast<int>(segment.num_cars()),
            static_cast<int>(num_before_pass) - 5);
  ASSERT_GE(segment.num_cars(), num_before_pass - ready_to_pass);
  ASSERT_LE(next_segment.num_cars(), 10);
}

TEST(SegmentTest, ReturnsReadyCars) {
  Segment segment(10, NULL, 50, 5, 5);
  std::vector<Car*> ready_cars = segment.ready_cars();

  ASSERT_LE(ready_cars.size(), segment.num_cars());
  for (size_t i = 0; i < ready_cars.size(); ++i) {
    ASSERT_EQ(ready_cars[i]->ready(), true);
  }
}

TEST(SegmentTest, ReturnsEnterJunction) {
  Segment segment0(10, NULL, 50, 5, 5);
  Segment segment1(10, NULL, 50, 5, 5);
  Segment segment2(10, NULL, 50, 5, 5);
  ASSERT_GE(segment0.enter_junction(), 1);
  ASSERT_EQ(segment1.enter_junction(), segment0.enter_junction() + 1);
  ASSERT_EQ(segment2.enter_junction(), segment0.enter_junction() + 2);
}

}  // namespace oop_project
<commit_msg>Segment: Changed Test name<commit_after>#include "segment.h"
#include "gtest/gtest.h"

namespace oop_project {

TEST(SegmentTest, CreatesRandomCars) {
  Segment segment(10, NULL, 50, 5, 5);
  ASSERT_GE(segment.num_cars(), 1);
  ASSERT_LE(segment.num_cars(), Segment::kMaxCars);
  ASSERT_LE(segment.num_cars(), 10);
  ASSERT_LE(segment.ready_cars().size(), 50 * segment.num_cars() / 100);
}

TEST(SegmentTest, EntersLessOrEqualToCapacity) {
  Segment prev_segment(10, NULL, 50, 5, 5);
  Segment segment(10, &prev_segment, 50, 5, 5);
  segment.Enter();
  ASSERT_LE(segment.num_cars(), 10);
}

TEST(SegmentTest, RemovesCarsFromFreeway) {
  Segment segment(10, NULL, 50, 5, 5);
  std::vector<Car*> ready_cars = segment.ready_cars();
  size_t num_before_exit = segment.num_cars();

  size_t ready_to_exit = 0;
  for (size_t i = 0; i < ready_cars.size(); ++i) {
    if (ready_cars[i]->exit_junction() == segment.enter_junction() + 1) {
      ++ready_to_exit;
    }
  }

  segment.Exit();
  ASSERT_EQ(segment.num_cars(), num_before_exit - ready_to_exit);
}

TEST(SegmentTest, Operates) {
  Segment segment(10, NULL, 50, 5, 5);
  std::vector<Car*> prev_ready_cars = segment.ready_cars();
  segment.Operate();
  std::vector<Car*> ready_cars = segment.ready_cars();

  ASSERT_GE(ready_cars.size(), prev_ready_cars.size());
  ASSERT_LE(ready_cars.size() - prev_ready_cars.size(),
            50 * segment.num_cars() / 100);
}

TEST(SegmentTest, PassesReadyCars) {
  Segment segment(10, NULL, 50, 5, 5);
  Segment next_segment(10, NULL, 50, 5, 5);
  segment.set_next(&next_segment);

  std::vector<Car*> ready_cars = segment.ready_cars();
  size_t ready_to_pass = 0;
  for (size_t i = 0; i < ready_cars.size(); ++i) {
    if (ready_cars[i]->exit_junction() != segment.enter_junction() + 1) {
        ++ready_to_pass;
    }
  }

  size_t num_before_pass = segment.num_cars();
  segment.Pass(5);
  ASSERT_GE(static_cast<int>(segment.num_cars()),
            static_cast<int>(num_before_pass) - 5);
  ASSERT_GE(segment.num_cars(), num_before_pass - ready_to_pass);
  ASSERT_LE(next_segment.num_cars(), 10);
}

TEST(SegmentTest, ReturnsReadyCars) {
  Segment segment(10, NULL, 50, 5, 5);
  std::vector<Car*> ready_cars = segment.ready_cars();

  ASSERT_LE(ready_cars.size(), segment.num_cars());
  for (size_t i = 0; i < ready_cars.size(); ++i) {
    ASSERT_EQ(ready_cars[i]->ready(), true);
  }
}

TEST(SegmentTest, ReturnsEnterJunction) {
  Segment segment0(10, NULL, 50, 5, 5);
  Segment segment1(10, NULL, 50, 5, 5);
  Segment segment2(10, NULL, 50, 5, 5);
  ASSERT_GE(segment0.enter_junction(), 1);
  ASSERT_EQ(segment1.enter_junction(), segment0.enter_junction() + 1);
  ASSERT_EQ(segment2.enter_junction(), segment0.enter_junction() + 2);
}

}  // namespace oop_project
<|endoftext|>


<commit_before>#include <elevator/scheduler.h>
#include <elevator/restartwrapper.h>
#include <elevator/elevator.h>

namespace elevator {

Scheduler::Scheduler( int localId, BasicDriverInfo info, GlobalState &global,
        ConcurrentQueue< StateChange > &stateUpdateIn,
        ConcurrentQueue< StateChange > &stateUpdateOut,
        ConcurrentQueue< Command > &commandsToRemote,
        ConcurrentQueue< Command > &commandsToLocal ) :
    _localElevId( localId ),
    _bounds( info ),
    _globalState( global ),
    _stateUpdateIn( stateUpdateIn ),
    _stateUpdateOut( stateUpdateOut ),
    _commandsToRemote( commandsToRemote ),
    _commandsToLocal( commandsToLocal ),
    _terminate( false )
{ }

Scheduler::~Scheduler() {
    if ( _thrSched.joinable() ) {
        _terminate = true;
        _thrSched.join();
        _thrReq.join();
    }
}

void Scheduler::run( HeartBeat &shed, HeartBeat &req ) {
    _thrSched = std::thread( restartWrapper( &Scheduler::_schedLoop ), this, &shed );
    _thrReq = std::thread( restartWrapper( &Scheduler::_reqCheckLoop ), this, &req );
}

const char *showChange( ChangeType );

void Scheduler::_forwardToTargets( Command comm ) {
    if ( comm.targetElevatorId == Command::ANY_ID || comm.targetElevatorId == _localElevId )
        _commandsToLocal.enqueue( comm );
    if ( comm.targetElevatorId != _localElevId )
        _commandsToRemote.enqueue( comm );
}

int Scheduler::_optimalElevator( ButtonType type, int floor ) {
    int minDistance = INT_MAX;
    int minId = INT_MIN;

    MillisecondTime now = elevator::now();
    // somawhat arbitrary thresholds for time-aware scheduling
    MillisecondTime outdatedThresh = Elevator::keepAlive * 1.2;
    MillisecondTime deadThresh = Elevator::keepAlive * 3;

    for ( auto &statepair : _globalState.elevators() ) {
        const ElevatorState &state = statepair.second;

        MillisecondTime age = now - state.timestamp;

        int dist = std::abs( state.lastFloor - floor );

        // time-aware penasisation
        if ( age > outdatedThresh )
            dist += 10 * (_bounds.maxFloor() - _bounds.minFloor());
        if ( age > deadThresh )
            continue; // skip this one completely, it is most likely dead
        // note: At least local cannot be dead so we should always find minumum

        // penalizations for non-idle elevators
        if ( state.stopped )
            dist += 10 * (_bounds.maxFloor() - _bounds.minFloor()); // stopped penalization

        if (    ( state.direction == Direction::Up
                        && ( (type == ButtonType::CallUp && floor > state.lastFloor )
                            || floor == _bounds.maxFloor() ) )
            ||
                ( state.direction == Direction::Down
                        && ( (type == ButtonType::CallDown && floor < state.lastFloor )
                            || floor == _bounds.minFloor() ) )
           )
            dist += _bounds.maxFloor() - _bounds.minFloor() + 1; // busy penalization
        else if ( state.direction != Direction::None ) // not idle
            // as a last resort we can schedule floor even to elevator which is
            // running in different direction
            dist += 2 * (_bounds.maxFloor() - _bounds.minFloor() + 1); // penalization

        if ( dist < minDistance ) {
            minDistance = dist;
            minId = state.id;
        }
    }
    assert_leq( 0, minId, "no minimal distance found" );
    return minId;
}

void Scheduler::_resendRequest( Request r ) {
    ++r.repeated;
    if ( r.repeated > 3 || r.type == RequestType::NotDone ) {
        // reschedule
        r.command.targetElevatorId = _optimalElevator(
                r.command.commandType == CommandType::CallToFloorAndGoUp
                    ? ButtonType::CallUp : ButtonType::CallDown,
                r.command.targetFloor );
        r.type = RequestType::NotAcknowledged;
    }
    r.updateDeadline();
    _globalState.requests().push( r );
    _forwardToTargets( r.command );
}

void Scheduler::_addAndForwardRequest( Command comm ) {
    Request r( comm, 100 ); // we need to be fast here
    _globalState.requests().push( r );
    _forwardToTargets( comm );
}

void Scheduler::_handleButtonPress( int updateElId, ButtonType type, int floor ) {
    // first setup lights
    Command lights{ type == ButtonType::CallUp
                      ? CommandType::TurnOnLightUp : CommandType::TurnOnLightDown,
                    Command::ANY_ID, floor };
    _forwardToTargets( lights );

    // each elevator schedules changes originating from it
    if ( updateElId == _localElevId ) {
        int minId = _optimalElevator( type, floor );

        Command comm{ type == ButtonType::CallUp
                          ? CommandType::CallToFloorAndGoUp
                          : CommandType::CallToFloorAndGoDown,
                      minId, floor };
        _addAndForwardRequest( comm );
    }
}

void Scheduler::_schedLoop( HeartBeat *heartbeat ) {
    while ( !_terminate.load( std::memory_order::memory_order_relaxed ) ) {
        auto maybeUpdate = _stateUpdateIn.timeoutDequeue( heartbeat->threshold() / 10 );
        if ( !maybeUpdate.isNothing() ) {
            auto update = maybeUpdate.value();
            _globalState.update( update.state );
            std::cerr << "state update: { id = " << update.state.id
                << ", timestamp = " << update.state.timestamp
                << ", changeType = " << showChange( update.changeType )
                << ", changeFloor = " << update.changeFloor
                << ", stopped = " << update.state.stopped
                << ", direction = " << int( update.state.direction )
                << " }" << std::endl;

            if ( update.state.id == _localElevId ) {
                _stateUpdateOut.enqueue( update ); // propagate update
            }

            // each elevator is responsible for scheduling commnads from its hardware
            switch ( update.changeType ) {
                case ChangeType::None:
                case ChangeType::KeepAlive:
                case ChangeType::OtherChange:
                case ChangeType::InsideButtonPresed:
                case ChangeType::Served:
                    break;
                case ChangeType::ButtonUpPressed:
                    _handleButtonPress( update.state.id, ButtonType::CallUp, update.changeFloor );
                    break;
                case ChangeType::ButtonDownPressed:
                    _handleButtonPress( update.state.id, ButtonType::CallDown, update.changeFloor );
                    break;
                case ChangeType::ServedDown:
                    _forwardToTargets( Command{ CommandType::TurnOffLightDown,
                            _localElevId, update.changeFloor } );
                    _globalState.requests().ackRequest( update );
                    break;
                case ChangeType::ServedUp:
                    _forwardToTargets( Command{ CommandType::TurnOffLightUp,
                            _localElevId, update.changeFloor } );
                    _globalState.requests().ackRequest( update );
                    break;
                case ChangeType::GoingToServeUp:
                case ChangeType::GoingToServeDown:
                    // the deadline here is quite high, because it takes time
                    // to do the job
                    _globalState.requests().ackRequest( update, 30 * 1000 );
                    break;
            }
        }

        heartbeat->beat();
    }
}

void Scheduler::_reqCheckLoop( HeartBeat *heartbeat ) {
    while ( !_terminate.load( std::memory_order::memory_order_relaxed ) ) {

        auto mreq = _globalState.requests().waitForEarliestDeadline( heartbeat->threshold() / 10 );
        if ( !mreq.isNothing() )
            _resendRequest( mreq.value() );

        heartbeat->beat();
    }
}

const char *showChange( ChangeType t ) {
#define show( X ) case ChangeType::X: return #X
    switch ( t ) {
        show( None );
        show( KeepAlive );

        show( InsideButtonPresed );
        show( ButtonDownPressed );
        show( ButtonUpPressed );

        show( Served );
        show( ServedUp );
        show( ServedDown );

        show( GoingToServeDown );
        show( GoingToServeUp );

        show( OtherChange );
    }
#undef show
    return "<<unknown>>";
}

}
<commit_msg>scheduler: Warn about re-sending packets.<commit_after>#include <elevator/scheduler.h>
#include <elevator/restartwrapper.h>
#include <elevator/elevator.h>

namespace elevator {

Scheduler::Scheduler( int localId, BasicDriverInfo info, GlobalState &global,
        ConcurrentQueue< StateChange > &stateUpdateIn,
        ConcurrentQueue< StateChange > &stateUpdateOut,
        ConcurrentQueue< Command > &commandsToRemote,
        ConcurrentQueue< Command > &commandsToLocal ) :
    _localElevId( localId ),
    _bounds( info ),
    _globalState( global ),
    _stateUpdateIn( stateUpdateIn ),
    _stateUpdateOut( stateUpdateOut ),
    _commandsToRemote( commandsToRemote ),
    _commandsToLocal( commandsToLocal ),
    _terminate( false )
{ }

Scheduler::~Scheduler() {
    if ( _thrSched.joinable() ) {
        _terminate = true;
        _thrSched.join();
        _thrReq.join();
    }
}

void Scheduler::run( HeartBeat &shed, HeartBeat &req ) {
    _thrSched = std::thread( restartWrapper( &Scheduler::_schedLoop ), this, &shed );
    _thrReq = std::thread( restartWrapper( &Scheduler::_reqCheckLoop ), this, &req );
}

const char *showChange( ChangeType );
const char *showCommand( CommandType );

void Scheduler::_forwardToTargets( Command comm ) {
    if ( comm.targetElevatorId == Command::ANY_ID || comm.targetElevatorId == _localElevId )
        _commandsToLocal.enqueue( comm );
    if ( comm.targetElevatorId != _localElevId )
        _commandsToRemote.enqueue( comm );
}

int Scheduler::_optimalElevator( ButtonType type, int floor ) {
    int minDistance = INT_MAX;
    int minId = INT_MIN;

    MillisecondTime now = elevator::now();
    // somawhat arbitrary thresholds for time-aware scheduling
    MillisecondTime outdatedThresh = Elevator::keepAlive * 1.2;
    MillisecondTime deadThresh = Elevator::keepAlive * 3;

    for ( auto &statepair : _globalState.elevators() ) {
        const ElevatorState &state = statepair.second;

        MillisecondTime age = now - state.timestamp;

        int dist = std::abs( state.lastFloor - floor );

        // time-aware penasisation
        if ( age > outdatedThresh )
            dist += 10 * (_bounds.maxFloor() - _bounds.minFloor());
        if ( age > deadThresh )
            continue; // skip this one completely, it is most likely dead
        // note: At least local cannot be dead so we should always find minumum

        // penalizations for non-idle elevators
        if ( state.stopped )
            dist += 10 * (_bounds.maxFloor() - _bounds.minFloor()); // stopped penalization

        if (    ( state.direction == Direction::Up
                        && ( (type == ButtonType::CallUp && floor > state.lastFloor )
                            || floor == _bounds.maxFloor() ) )
            ||
                ( state.direction == Direction::Down
                        && ( (type == ButtonType::CallDown && floor < state.lastFloor )
                            || floor == _bounds.minFloor() ) )
           )
            dist += _bounds.maxFloor() - _bounds.minFloor() + 1; // busy penalization
        else if ( state.direction != Direction::None ) // not idle
            // as a last resort we can schedule floor even to elevator which is
            // running in different direction
            dist += 2 * (_bounds.maxFloor() - _bounds.minFloor() + 1); // penalization

        if ( dist < minDistance ) {
            minDistance = dist;
            minId = state.id;
        }
    }
    assert_leq( 0, minId, "no minimal distance found" );
    return minId;
}

void Scheduler::_resendRequest( Request r ) {
    std::cerr << "WARNING: re-sending request: { type = "
              << (r.type == RequestType::NotAcknowledged ? "NotAcknowledged" : "NotDone")
              << ", repeated = " << r.repeated << ", command = { elevator = "
              << r.command.targetElevatorId << ", floor = " << r.command.targetFloor
              << ", type = " << showCommand( r.command.commandType ) << " } }" << std::endl;
    ++r.repeated;
    if ( r.repeated > 3 || r.type == RequestType::NotDone ) {
        // reschedule
        r.command.targetElevatorId = _optimalElevator(
                r.command.commandType == CommandType::CallToFloorAndGoUp
                    ? ButtonType::CallUp : ButtonType::CallDown,
                r.command.targetFloor );
        r.type = RequestType::NotAcknowledged;
    }
    r.updateDeadline();
    _globalState.requests().push( r );
    _forwardToTargets( r.command );
}

void Scheduler::_addAndForwardRequest( Command comm ) {
    Request r( comm, 100 ); // we need to be fast here
    _globalState.requests().push( r );
    _forwardToTargets( comm );
}

void Scheduler::_handleButtonPress( int updateElId, ButtonType type, int floor ) {
    // first setup lights
    Command lights{ type == ButtonType::CallUp
                      ? CommandType::TurnOnLightUp : CommandType::TurnOnLightDown,
                    Command::ANY_ID, floor };
    _forwardToTargets( lights );

    // each elevator schedules changes originating from it
    if ( updateElId == _localElevId ) {
        int minId = _optimalElevator( type, floor );

        Command comm{ type == ButtonType::CallUp
                          ? CommandType::CallToFloorAndGoUp
                          : CommandType::CallToFloorAndGoDown,
                      minId, floor };
        _addAndForwardRequest( comm );
    }
}

void Scheduler::_schedLoop( HeartBeat *heartbeat ) {
    while ( !_terminate.load( std::memory_order::memory_order_relaxed ) ) {
        auto maybeUpdate = _stateUpdateIn.timeoutDequeue( heartbeat->threshold() / 10 );
        if ( !maybeUpdate.isNothing() ) {
            auto update = maybeUpdate.value();
            _globalState.update( update.state );
            std::cerr << "state update: { id = " << update.state.id
                << ", timestamp = " << update.state.timestamp
                << ", changeType = " << showChange( update.changeType )
                << ", changeFloor = " << update.changeFloor
                << ", stopped = " << update.state.stopped
                << ", direction = " << int( update.state.direction )
                << " }" << std::endl;

            if ( update.state.id == _localElevId ) {
                _stateUpdateOut.enqueue( update ); // propagate update
            }

            // each elevator is responsible for scheduling commnads from its hardware
            switch ( update.changeType ) {
                case ChangeType::None:
                case ChangeType::KeepAlive:
                case ChangeType::OtherChange:
                case ChangeType::InsideButtonPresed:
                case ChangeType::Served:
                    break;
                case ChangeType::ButtonUpPressed:
                    _handleButtonPress( update.state.id, ButtonType::CallUp, update.changeFloor );
                    break;
                case ChangeType::ButtonDownPressed:
                    _handleButtonPress( update.state.id, ButtonType::CallDown, update.changeFloor );
                    break;
                case ChangeType::ServedDown:
                    _forwardToTargets( Command{ CommandType::TurnOffLightDown,
                            _localElevId, update.changeFloor } );
                    _globalState.requests().ackRequest( update );
                    break;
                case ChangeType::ServedUp:
                    _forwardToTargets( Command{ CommandType::TurnOffLightUp,
                            _localElevId, update.changeFloor } );
                    _globalState.requests().ackRequest( update );
                    break;
                case ChangeType::GoingToServeUp:
                case ChangeType::GoingToServeDown:
                    // the deadline here is quite high, because it takes time
                    // to do the job
                    _globalState.requests().ackRequest( update, 30 * 1000 );
                    break;
            }
        }

        heartbeat->beat();
    }
}

void Scheduler::_reqCheckLoop( HeartBeat *heartbeat ) {
    while ( !_terminate.load( std::memory_order::memory_order_relaxed ) ) {

        auto mreq = _globalState.requests().waitForEarliestDeadline( heartbeat->threshold() / 10 );
        if ( !mreq.isNothing() )
            _resendRequest( mreq.value() );

        heartbeat->beat();
    }
}

const char *showChange( ChangeType t ) {
#define show( X ) case ChangeType::X: return #X
    switch ( t ) {
        show( None );
        show( KeepAlive );

        show( InsideButtonPresed );
        show( ButtonDownPressed );
        show( ButtonUpPressed );

        show( Served );
        show( ServedUp );
        show( ServedDown );

        show( GoingToServeDown );
        show( GoingToServeUp );

        show( OtherChange );
    }
#undef show
    return "<<unknown>>";
}

const char *showCommand( CommandType t ) {
#define show( X ) case CommandType::X: return #X
    switch ( t ) {
        show( Empty );
        show( CallToFloorAndGoUp );
        show( CallToFloorAndGoDown );
        show( TurnOffLightUp );
        show( TurnOffLightDown );
        show( TurnOnLightDown );
        show( TurnOnLightUp );
    }
#undef show
    return "<<unknown>>";
}

}
<|endoftext|>


<commit_before>#include <hx/CFFI.h>
#include <ui/WindowEvent.h>

namespace lime {

	AutoGCRoot* WindowEvent::callback = 0;
	AutoGCRoot* WindowEvent::eventObject = 0;

	static int id_height;
	static int id_type;
	static int id_width;
	static int id_x;
	static int id_y;
	static bool init = false;

	WindowEvent::WindowEvent () {

		type = WINDOW_ACTIVATE;
		width = 0;
		height = 0;
		x = 0;
		y = 0;

	}

	void WindowEvent::Dispatch (WindowEvent* event) {

		if (WindowEvent::callback) {

			if (!init) {

				id_height = val_id ("height");
				id_type = val_id ("type");
				id_width = val_id ("width");
				id_x = val_id ("x");
				id_y = val_id ("y");
				init = true;

			}

			value object = (WindowEvent::eventObject ? WindowEvent::eventObject->get () : alloc_empty_object ());

			alloc_field (object, id_type, alloc_int (event->type));

			switch (event->type) {

				case WINDOW_MOVE:

					alloc_field (object, id_x, alloc_int (event->x));
					alloc_field (object, id_y, alloc_int (event->y));
					break;

				case WINDOW_RESIZE:

					alloc_field (object, id_width, alloc_int (event->width));
					alloc_field (object, id_height, alloc_int (event->height));
					break;

			}

			val_call0 (WindowEvent::callback->get ());

		}

	}

}<commit_msg>Fix warning<commit_after>#include <hx/CFFI.h>
#include <ui/WindowEvent.h>

namespace lime {

	AutoGCRoot* WindowEvent::callback = 0;
	AutoGCRoot* WindowEvent::eventObject = 0;

	static int id_height;
	static int id_type;
	static int id_width;
	static int id_x;
	static int id_y;
	static bool init = false;

	WindowEvent::WindowEvent () {

		type = WINDOW_ACTIVATE;
		width = 0;
		height = 0;
		x = 0;
		y = 0;

	}

	void WindowEvent::Dispatch (WindowEvent* event) {

		if (WindowEvent::callback) {

			if (!init) {

				id_height = val_id ("height");
				id_type = val_id ("type");
				id_width = val_id ("width");
				id_x = val_id ("x");
				id_y = val_id ("y");
				init = true;

			}

			value object = (WindowEvent::eventObject ? WindowEvent::eventObject->get () : alloc_empty_object ());

			alloc_field (object, id_type, alloc_int (event->type));

			switch (event->type) {

				case WINDOW_MOVE:

					alloc_field (object, id_x, alloc_int (event->x));
					alloc_field (object, id_y, alloc_int (event->y));
					break;

				case WINDOW_RESIZE:

					alloc_field (object, id_width, alloc_int (event->width));
					alloc_field (object, id_height, alloc_int (event->height));
					break;

				default: break;

			}

			val_call0 (WindowEvent::callback->get ());

		}

	}

}<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver.
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "tdriver_highlighter.h"

#include <QRegExp>
#include <QSyntaxHighlighter>
#include <QTextCharFormat>
#include <QFont>
#include <QStringList>
#include <QFile>

#include "tdriver_editor_common.h"

#include <tdriver_debug_macros.h>

TDriverHighlighter::TDriverHighlighter(QTextDocument *parent) :
        QSyntaxHighlighter(parent),
        defaultFormat(new QTextCharFormat),
        keywordFormat(new QTextCharFormat),
        singleQuotationFormat(new QTextCharFormat),
        doubleQuotationFormat(new QTextCharFormat),
        ruleListList()
{

    // setup formats
    // this is used to detect if a given char is formatted with defaultFormat or not
    defaultFormat->setProperty(QTextFormat::UserProperty, true);

    keywordFormat->setForeground(Qt::darkBlue);
    keywordFormat->setFontWeight(QFont::Bold);

    // bright green HSV is 120, 255, 255
    singleQuotationFormat->setForeground(QColor::fromHsv(150, 255, 150));
    doubleQuotationFormat->setForeground(QColor::fromHsv(90, 255, 150));

    // add a set of default rules that should be suitable for any text
    QList<const HighlightingRuleBase*> rules;

    {
        HighlightingRule2 *rule2;

        rule2 = new HighlightingRule2(this);
        rule2->matchPat = new QRegExp("\"");
        // endPat matches " at the beginning, or preceded by even number of backslashes
        // requires endCaretMode QRegExp::CaretAtOffset
        rule2->endPat = new QRegExp("(^\\\"|[^\\\\](\\\\\\\\)*\\\")");
        rule2->format = doubleQuotationFormat;
        //qDebug() << FFL << rule2->matchPat->pattern();
        rules.append(rule2);
        rule2=NULL;

        rule2 = new HighlightingRule2(this);
        rule2->matchPat = new QRegExp("'");
        // endPat matches ' at the beginning, or preceded by even number of backslashes
        // requires endCaretMode QRegExp::CaretAtOffset
        rule2->endPat = new QRegExp("(^\\'|[^\\\\](\\\\\\\\)*\\')");
        rule2->format = singleQuotationFormat;
        //qDebug() << FFL << rule2->matchPat->pattern();
        rules.append(rule2);
        rule2=NULL;
    }
    ruleListList.append(rules);
    rules.clear();
}

int TDriverHighlighter::readPlainStrings(
        const QString &fileName,
        const QTextCharFormat *format,
        QList<const HighlightingRuleBase*> &rules)
{
    QStringList keywords;
    MEC::DefinitionFileType type = MEC::getDefinitionFile(fileName, keywords);

    if (type == MEC::InvalidDefinitionFile) {
        qWarning() << "getDefinitionFile failed for" << fileName;
        return -1;
    }

    int count = 0;
    foreach (QString word, keywords) {
        HighlightingRule1 *rule1 = new HighlightingRule1(this);
        rule1->matchPat = new QRegExp(word.trimmed().prepend("\\b").append("\\b"));
        rule1->format = format;
        rules.append(rule1);
        ++count;
    }
    return count;
}

void TDriverHighlighter::highlightBlock(const QString &text)
{
    qDebug() << ">>> START BLOCK ";

    int startIndex = 0;
    if (previousBlockState() >= 0) {
        const HighlightingRuleBase *rule = stateRulePtrs.value(previousBlockState());
        Q_ASSERT(rule);
        qDebug() << FFL << "calling handlePreviousState of rule type" << rule->type();
        startIndex = rule->handlePreviousState(text);

        if (startIndex == -1) {
            qDebug() << FFL << "DONE after handlePreviousState, with state" << currentBlockState();
            return;
        }
    }

    setCurrentBlockState(-1);
    qDebug() << FFL << "startIndex" << startIndex << ", set block state" << currentBlockState();

    setFormat(startIndex, text.length() - startIndex, *defaultFormat);

    // optimization: eat initial whitespace and return if empty block
    while (startIndex < text.length() && text[startIndex].isSpace()) {
        ++startIndex;
    }
    if (startIndex >= text.length()) return;

    QList<const HighlightingRuleBase*> ruleList;
    foreach (ruleList, ruleListList) {
        const HighlightingRuleBase *rule;
        foreach (rule, ruleList) {
            int index = startIndex;

            forever {
                index = rule->matchPat->indexIn(text, index, rule->matchCaretMode);

                // break if no match
                if (index == -1) break; // continue inner foreach to next rule

                // this length value applies if rule coveres all of text to be highlighted
                int length = rule->matchPat->matchedLength();

                qDebug() << FFL << index << length;

                // skip this match if position already formatted
                if (format(index).property(QTextFormat::UserProperty).toBool() != true) {
                    qDebug() << FFL << format(index) << "formated already, skip at index" << index;
                    index += length;
                    continue;
                }

                // this is needed for cases like end-of-line comment overriding previous multiline-quote start
                if (rule->resetBlockState) setCurrentBlockState(-1);

                rule->postMatch(text, index, length);

                qDebug() << FFL << "startindex " << startIndex << " new index " << index;

                // optimization: extend already known to be formatted part of line,
                // and return if entire line highlighted (common case with #-style comment)
                if (startIndex == index) {
                    startIndex += length;
                    if (startIndex >= text.length()) return;
                }

                index += length;
            }
        }
    }
}

//
// member functions of HighlightingRuleBase

TDriverHighlighter::HighlightingRuleBase::HighlightingRuleBase(TDriverHighlighter *owner_) :
        matchPat(NULL),
        matchCaretMode(QRegExp::CaretAtOffset),
        format(NULL),
        owner(owner_),
        stateIndex(owner->stateRulePtrs.size()),
        resetBlockState(false)
{
    TDriverHighlighter *castowner = const_cast<TDriverHighlighter *>(owner);
    castowner->stateRulePtrs.append(this);
}

void TDriverHighlighter::HighlightingRuleBase::postMatch (
        const QString &,
        int &startInd,
        int &formatLen ) const
{
    TDriverHighlighter *castowner = const_cast<TDriverHighlighter *>(owner);
    castowner->setFormat(startInd, formatLen, *format);
}

//
// member functions of HighlightingRule2

TDriverHighlighter::HighlightingRule2::HighlightingRule2(TDriverHighlighter *owner_)  :
        HighlightingRuleBase(owner_),
        endPat(NULL),
        endCaretMode(QRegExp::CaretAtOffset)
{
}

int TDriverHighlighter::HighlightingRule2::handlePreviousState(const QString &text) const
{
    TDriverHighlighter *castowner = const_cast<TDriverHighlighter *>(owner);
    int startIndex = endPat->indexIn(text, 0, endCaretMode);

    if (startIndex == -1) {
        castowner->setFormat(0, text.length(), *format);
        castowner->setCurrentBlockState(castowner->previousBlockState());
         qDebug() << FFL << "full line formatted, block state continuation" << castowner->previousBlockState();
    }
    else {
        startIndex += endPat->matchedLength();
        castowner->setFormat(0, startIndex, *format);
        qDebug() << FFL << "formated until pos" << startIndex;
    }

    return startIndex;
}

void TDriverHighlighter::HighlightingRule2::postMatch (
        const QString &text,
        int &startInd,
        int &formatLen ) const
{
    TDriverHighlighter *castowner = const_cast<TDriverHighlighter *>(owner);
    int endIndex = endPat->indexIn(text, startInd+formatLen, endCaretMode);
    qDebug() << FFL << text << " " << startInd << " " << formatLen << " " << endIndex;

    if (endIndex == -1) {
        // rule continues to next line:
        // set formatLen to cover rest of line and return new block state for Highlighter
        formatLen = text.length() - startInd; // rest of the text
        castowner->setCurrentBlockState(stateIndex);
        qDebug() << FFL << "re-set block state" <<castowner->currentBlockState();;
    }
    else {
        // set formatLen to cover start and end patters (including text between)
        formatLen = endIndex - startInd + endPat->matchedLength();

        // RESET remaining block before setting new rule format
        // Higher priority rules format has been already applied but not closed if current block state is not -1.
        // If a lower priority rule now is closed before the higher one then have to first clear previous formatting
        // on the remaining block to be processed, before applying the new formatting.
        if (castowner->currentBlockState() < stateIndex)
        {
            int start_remaining_block = startInd;
            int end_remaining_block = castowner->currentBlock().position() + castowner->currentBlock().length() -1;
            castowner->setFormat(start_remaining_block, end_remaining_block, *castowner->defaultFormat);
            castowner->setCurrentBlockState(-1);
        }
    }

    castowner->setFormat(startInd, formatLen, *format);
}
<commit_msg>Commented out highlighter debug messages<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver.
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "tdriver_highlighter.h"

#include <QRegExp>
#include <QSyntaxHighlighter>
#include <QTextCharFormat>
#include <QFont>
#include <QStringList>
#include <QFile>

#include "tdriver_editor_common.h"

#include <tdriver_debug_macros.h>

TDriverHighlighter::TDriverHighlighter(QTextDocument *parent) :
        QSyntaxHighlighter(parent),
        defaultFormat(new QTextCharFormat),
        keywordFormat(new QTextCharFormat),
        singleQuotationFormat(new QTextCharFormat),
        doubleQuotationFormat(new QTextCharFormat),
        ruleListList()
{

    // setup formats
    // this is used to detect if a given char is formatted with defaultFormat or not
    defaultFormat->setProperty(QTextFormat::UserProperty, true);

    keywordFormat->setForeground(Qt::darkBlue);
    keywordFormat->setFontWeight(QFont::Bold);

    // bright green HSV is 120, 255, 255
    singleQuotationFormat->setForeground(QColor::fromHsv(150, 255, 150));
    doubleQuotationFormat->setForeground(QColor::fromHsv(90, 255, 150));

    // add a set of default rules that should be suitable for any text
    QList<const HighlightingRuleBase*> rules;

    {
        HighlightingRule2 *rule2;

        rule2 = new HighlightingRule2(this);
        rule2->matchPat = new QRegExp("\"");
        // endPat matches " at the beginning, or preceded by even number of backslashes
        // requires endCaretMode QRegExp::CaretAtOffset
        rule2->endPat = new QRegExp("(^\\\"|[^\\\\](\\\\\\\\)*\\\")");
        rule2->format = doubleQuotationFormat;
        //qDebug() << FFL << rule2->matchPat->pattern();
        rules.append(rule2);
        rule2=NULL;

        rule2 = new HighlightingRule2(this);
        rule2->matchPat = new QRegExp("'");
        // endPat matches ' at the beginning, or preceded by even number of backslashes
        // requires endCaretMode QRegExp::CaretAtOffset
        rule2->endPat = new QRegExp("(^\\'|[^\\\\](\\\\\\\\)*\\')");
        rule2->format = singleQuotationFormat;
        //qDebug() << FFL << rule2->matchPat->pattern();
        rules.append(rule2);
        rule2=NULL;
    }
    ruleListList.append(rules);
    rules.clear();
}

int TDriverHighlighter::readPlainStrings(
        const QString &fileName,
        const QTextCharFormat *format,
        QList<const HighlightingRuleBase*> &rules)
{
    QStringList keywords;
    MEC::DefinitionFileType type = MEC::getDefinitionFile(fileName, keywords);

    if (type == MEC::InvalidDefinitionFile) {
        qWarning() << "getDefinitionFile failed for" << fileName;
        return -1;
    }

    int count = 0;
    foreach (QString word, keywords) {
        HighlightingRule1 *rule1 = new HighlightingRule1(this);
        rule1->matchPat = new QRegExp(word.trimmed().prepend("\\b").append("\\b"));
        rule1->format = format;
        rules.append(rule1);
        ++count;
    }
    return count;
}

void TDriverHighlighter::highlightBlock(const QString &text)
{
    int startIndex = 0;
    if (previousBlockState() >= 0) {
        const HighlightingRuleBase *rule = stateRulePtrs.value(previousBlockState());
        Q_ASSERT(rule);
        //qDebug() << FCFL << "calling handlePreviousState of rule type" << rule->type();
        startIndex = rule->handlePreviousState(text);

        if (startIndex == -1) {
            //qDebug() << FCFL << "DONE after handlePreviousState, with state" << currentBlockState();
            return;
        }
    }

    setCurrentBlockState(-1);
    //qDebug() << FCFL << "startIndex" << startIndex << ", set block state" << currentBlockState();

    setFormat(startIndex, text.length() - startIndex, *defaultFormat);

    // optimization: eat initial whitespace and return if empty block
    while (startIndex < text.length() && text[startIndex].isSpace()) {
        ++startIndex;
    }
    if (startIndex >= text.length()) return;

    QList<const HighlightingRuleBase*> ruleList;
    foreach (ruleList, ruleListList) {
        const HighlightingRuleBase *rule;
        foreach (rule, ruleList) {
            int index = startIndex;

            forever {
                index = rule->matchPat->indexIn(text, index, rule->matchCaretMode);

                // break if no match
                if (index == -1) break; // continue inner foreach to next rule

                // this length value applies if rule coveres all of text to be highlighted
                int length = rule->matchPat->matchedLength();

                //qDebug() << FFL << index << length;

                // skip this match if position already formatted
                if (format(index).property(QTextFormat::UserProperty).toBool() != true) {
                    //qDebug() << FFL << format(index) << "formated already, skip at index" << index;
                    index += length;
                    continue;
                }

                // this is needed for cases like end-of-line comment overriding previous multiline-quote start
                if (rule->resetBlockState) setCurrentBlockState(-1);

                rule->postMatch(text, index, length);

                //qDebug() << FFL << "startindex " << startIndex << " new index " << index;

                // optimization: extend already known to be formatted part of line,
                // and return if entire line highlighted (common case with #-style comment)
                if (startIndex == index) {
                    startIndex += length;
                    if (startIndex >= text.length()) return;
                }

                index += length;
            }
        }
    }
}

//
// member functions of HighlightingRuleBase

TDriverHighlighter::HighlightingRuleBase::HighlightingRuleBase(TDriverHighlighter *owner_) :
        matchPat(NULL),
        matchCaretMode(QRegExp::CaretAtOffset),
        format(NULL),
        owner(owner_),
        stateIndex(owner->stateRulePtrs.size()),
        resetBlockState(false)
{
    TDriverHighlighter *castowner = const_cast<TDriverHighlighter *>(owner);
    castowner->stateRulePtrs.append(this);
}

void TDriverHighlighter::HighlightingRuleBase::postMatch (
        const QString &,
        int &startInd,
        int &formatLen ) const
{
    TDriverHighlighter *castowner = const_cast<TDriverHighlighter *>(owner);
    castowner->setFormat(startInd, formatLen, *format);
}

//
// member functions of HighlightingRule2

TDriverHighlighter::HighlightingRule2::HighlightingRule2(TDriverHighlighter *owner_)  :
        HighlightingRuleBase(owner_),
        endPat(NULL),
        endCaretMode(QRegExp::CaretAtOffset)
{
}

int TDriverHighlighter::HighlightingRule2::handlePreviousState(const QString &text) const
{
    TDriverHighlighter *castowner = const_cast<TDriverHighlighter *>(owner);
    int startIndex = endPat->indexIn(text, 0, endCaretMode);

    if (startIndex == -1) {
        castowner->setFormat(0, text.length(), *format);
        castowner->setCurrentBlockState(castowner->previousBlockState());
         //qDebug() << FFL << "full line formatted, block state continuation" << castowner->previousBlockState();
    }
    else {
        startIndex += endPat->matchedLength();
        castowner->setFormat(0, startIndex, *format);
        //qDebug() << FFL << "formated until pos" << startIndex;
    }

    return startIndex;
}

void TDriverHighlighter::HighlightingRule2::postMatch (
        const QString &text,
        int &startInd,
        int &formatLen ) const
{
    TDriverHighlighter *castowner = const_cast<TDriverHighlighter *>(owner);
    int endIndex = endPat->indexIn(text, startInd+formatLen, endCaretMode);
    //qDebug() << FFL << text << " " << startInd << " " << formatLen << " " << endIndex;

    if (endIndex == -1) {
        // rule continues to next line:
        // set formatLen to cover rest of line and return new block state for Highlighter
        formatLen = text.length() - startInd; // rest of the text
        castowner->setCurrentBlockState(stateIndex);
        //qDebug() << FFL << "re-set block state" <<castowner->currentBlockState();;
    }
    else {
        // set formatLen to cover start and end patters (including text between)
        formatLen = endIndex - startInd + endPat->matchedLength();

        // RESET remaining block before setting new rule format
        // Higher priority rules format has been already applied but not closed if current block state is not -1.
        // If a lower priority rule now is closed before the higher one then have to first clear previous formatting
        // on the remaining block to be processed, before applying the new formatting.
        if (castowner->currentBlockState() < stateIndex)
        {
            int start_remaining_block = startInd;
            int end_remaining_block = castowner->currentBlock().position() + castowner->currentBlock().length() -1;
            castowner->setFormat(start_remaining_block, end_remaining_block, *castowner->defaultFormat);
            castowner->setCurrentBlockState(-1);
        }
    }

    castowner->setFormat(startInd, formatLen, *format);
}
<|endoftext|>


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

#include <deque>

#include "dll_test.hpp"

#include "dll/neural/conv_layer.hpp"
#include "dll/neural/dense_layer.hpp"
#include "dll/neural/activation_layer.hpp"
#include "dll/neural/batch_normalization_layer.hpp"
#include "dll/pooling/mp_layer.hpp"
#include "dll/dbn.hpp"
#include "dll/datasets.hpp"

#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"

// (Dense) BN after the non-linearity
TEST_CASE("unit/bn/1", "[unit][bn]") {
    using network_t = dll::dbn_desc<
        dll::dbn_layers<
            dll::dense_desc<28 * 28, 200, dll::no_bias, dll::activation<dll::function::SIGMOID>>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::activation<dll::function::SIGMOID>>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 10, dll::activation<dll::function::SOFTMAX>>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::dbn_t;

    auto dataset = dll::make_mnist_dataset_val(0, 1000, 2000, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto dbn = std::make_unique<network_t>();

    dbn->display();
    dataset.display();

    dbn->initial_momentum = 0.9;
    dbn->final_momentum   = 0.9;
    dbn->learning_rate    = 0.01;

    FT_CHECK_DATASET_VAL(50, 5e-2);
    TEST_CHECK_DATASET(0.25);
}

// (Dense) BN before the non-linearity
TEST_CASE("unit/bn/2", "[unit][bn]") {
    using network_t = dll::dbn_desc<
        dll::dbn_layers<
            dll::dense_desc<28 * 28, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<200, 10, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SOFTMAX>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::dbn_t;

    auto dataset = dll::make_mnist_dataset_val(0, 1000, 3000, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto dbn = std::make_unique<network_t>();

    dbn->display();
    dataset.display();

    dbn->initial_momentum = 0.9;
    dbn->final_momentum   = 0.9;
    dbn->learning_rate    = 0.01;

    FT_CHECK_DATASET_VAL(50, 5e-2);
    TEST_CHECK_DATASET(0.25);
}

// (Conv) BN after the non-linearity
TEST_CASE("unit/bn/3", "[unit][bn]") {
    using network_t = dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_desc<1, 28, 28, 6, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_4d_desc<6, 24, 24>::layer_t,

            dll::conv_desc<6, 24, 24, 6, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_4d_desc<6, 20, 20>::layer_t,

            dll::dense_desc<6 * 20 * 20, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 10, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SOFTMAX>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::dbn_t;

    auto dataset = dll::make_mnist_dataset_val(0, 500, 2500, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto dbn = std::make_unique<network_t>();

    dbn->display();
    dataset.display();

    dbn->initial_momentum = 0.9;
    dbn->final_momentum   = 0.9;
    dbn->learning_rate    = 0.01;

    FT_CHECK_DATASET_VAL(50, 5e-2);
    TEST_CHECK_DATASET(0.25);
}

// (Conv) BN before the non-linearity
TEST_CASE("unit/bn/4", "[unit][bn]") {
    using network_t = dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_desc<1, 28, 28, 6, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_4d_desc<6, 24, 24>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::conv_desc<6, 24, 24, 6, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_4d_desc<6, 20, 20>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<6 * 20 * 20, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<200, 10, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SOFTMAX>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::dbn_t;

    auto dataset = dll::make_mnist_dataset_val(0, 500, 2500, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto dbn = std::make_unique<network_t>();

    dbn->display();
    dataset.display();

    dbn->initial_momentum = 0.9;
    dbn->final_momentum   = 0.9;
    dbn->learning_rate    = 0.01;

    FT_CHECK_DATASET_VAL(50, 5e-2);
    TEST_CHECK_DATASET(0.25);
}

// (Conv+MP) BN after the non-linearity
TEST_CASE("unit/bn/5", "[unit][bn]") {
    constexpr size_t K = 6;

    using network_t = dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_desc<1, 28, 28, K, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::mp_layer_2d_desc<K, 24, 24, 2, 2>::layer_t,
            dll::batch_normalization_layer_4d_desc<K, 12, 12>::layer_t,

            dll::conv_desc<K, 12, 12, K, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::mp_layer_2d_desc<K, 8, 8, 2, 2>::layer_t,
            dll::batch_normalization_layer_4d_desc<K, 4, 4>::layer_t,

            dll::dense_desc<K * 4 * 4, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 10, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SOFTMAX>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::dbn_t;

    auto dataset = dll::make_mnist_dataset_val(0, 500, 2500, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto dbn = std::make_unique<network_t>();

    dbn->display();
    dataset.display();

    dbn->initial_momentum = 0.9;
    dbn->final_momentum   = 0.9;
    dbn->learning_rate    = 0.01;

    FT_CHECK_DATASET_VAL(50, 5e-2);
    TEST_CHECK_DATASET(0.25);
}
<commit_msg>Adapt a test<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <deque>

#include "dll_test.hpp"

#include "dll/neural/conv_layer.hpp"
#include "dll/neural/dense_layer.hpp"
#include "dll/neural/activation_layer.hpp"
#include "dll/neural/batch_normalization_layer.hpp"
#include "dll/pooling/mp_layer.hpp"
#include "dll/network.hpp"
#include "dll/datasets.hpp"

#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"

// (Dense) BN after the non-linearity
TEST_CASE("unit/bn/1", "[unit][bn]") {
    using network_t = dll::network_desc<
        dll::network_layers<
            dll::dense_desc<28 * 28, 200, dll::no_bias, dll::activation<dll::function::SIGMOID>>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::activation<dll::function::SIGMOID>>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 10, dll::activation<dll::function::SOFTMAX>>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::network_t;

    auto dataset = dll::make_mnist_dataset_val(0, 1000, 2000, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto net = std::make_unique<network_t>();

    net->display();
    dataset.display();

    net->initial_momentum = 0.9;
    net->final_momentum   = 0.9;
    net->learning_rate    = 0.01;

    FT_CHECK_2_VAL(net, dataset, 50, 5e-2);
    TEST_CHECK_2(net, dataset, 0.25);
}

// (Dense) BN before the non-linearity
TEST_CASE("unit/bn/2", "[unit][bn]") {
    using network_t = dll::network_desc<
        dll::network_layers<
            dll::dense_desc<28 * 28, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<200, 10, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SOFTMAX>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::network_t;

    auto dataset = dll::make_mnist_dataset_val(0, 1000, 3000, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto net = std::make_unique<network_t>();

    net->display();
    dataset.display();

    net->initial_momentum = 0.9;
    net->final_momentum   = 0.9;
    net->learning_rate    = 0.01;

    FT_CHECK_2_VAL(net, dataset, 50, 5e-2);
    TEST_CHECK_2(net, dataset, 0.25);
}

// (Conv) BN after the non-linearity
TEST_CASE("unit/bn/3", "[unit][bn]") {
    using network_t = dll::network_desc<
        dll::network_layers<
            dll::conv_desc<1, 28, 28, 6, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_4d_desc<6, 24, 24>::layer_t,

            dll::conv_desc<6, 24, 24, 6, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_4d_desc<6, 20, 20>::layer_t,

            dll::dense_desc<6 * 20 * 20, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 10, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SOFTMAX>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::network_t;

    auto dataset = dll::make_mnist_dataset_val(0, 500, 2500, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto net = std::make_unique<network_t>();

    net->display();
    dataset.display();

    net->initial_momentum = 0.9;
    net->final_momentum   = 0.9;
    net->learning_rate    = 0.01;

    FT_CHECK_2_VAL(net, dataset, 50, 5e-2);
    TEST_CHECK_2(net, dataset, 0.25);
}

// (Conv) BN before the non-linearity
TEST_CASE("unit/bn/4", "[unit][bn]") {
    using network_t = dll::network_desc<
        dll::network_layers<
            dll::conv_desc<1, 28, 28, 6, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_4d_desc<6, 24, 24>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::conv_desc<6, 24, 24, 6, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_4d_desc<6, 20, 20>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<6 * 20 * 20, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,

            dll::dense_desc<200, 10, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SOFTMAX>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::network_t;

    auto dataset = dll::make_mnist_dataset_val(0, 500, 2500, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto net = std::make_unique<network_t>();

    net->display();
    dataset.display();

    net->initial_momentum = 0.9;
    net->final_momentum   = 0.9;
    net->learning_rate    = 0.01;

    FT_CHECK_2_VAL(net, dataset, 50, 5e-2);
    TEST_CHECK_2(net, dataset, 0.25);
}

// (Conv+MP) BN after the non-linearity
TEST_CASE("unit/bn/5", "[unit][bn]") {
    constexpr size_t K = 6;

    using network_t = dll::network_desc<
        dll::network_layers<
            dll::conv_desc<1, 28, 28, K, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::mp_layer_2d_desc<K, 24, 24, 2, 2>::layer_t,
            dll::batch_normalization_layer_4d_desc<K, 12, 12>::layer_t,

            dll::conv_desc<K, 12, 12, K, 5, 5, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::mp_layer_2d_desc<K, 8, 8, 2, 2>::layer_t,
            dll::batch_normalization_layer_4d_desc<K, 4, 4>::layer_t,

            dll::dense_desc<K * 4 * 4, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 200, dll::no_bias, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SIGMOID>::layer_t,
            dll::batch_normalization_layer_2d_desc<200>::layer_t,

            dll::dense_desc<200, 10, dll::no_activation>::layer_t,
            dll::activation_layer_desc<dll::function::SOFTMAX>::layer_t
        >,
        dll::updater<dll::updater_type::ADADELTA>, dll::early_training, dll::batch_size<25>>::network_t;

    auto dataset = dll::make_mnist_dataset_val(0, 500, 2500, 0, dll::batch_size<25>{}, dll::scale_pre<255>{});

    auto net = std::make_unique<network_t>();

    net->display();
    dataset.display();

    net->initial_momentum = 0.9;
    net->final_momentum   = 0.9;
    net->learning_rate    = 0.01;

    FT_CHECK_2_VAL(net, dataset, 50, 5e-2);
    TEST_CHECK_2(net, dataset, 0.25);
}
<|endoftext|>