Program Listing for File BirthSetupService.hpp

Return to documentation for file (include/dish2/services/BirthSetupService.hpp)

#pragma once
#ifndef DISH2_SERVICES_BIRTHSETUPSERVICE_HPP_INCLUDE
#define DISH2_SERVICES_BIRTHSETUPSERVICE_HPP_INCLUDE

#include <functional>
#include <utility>

#include "../../../third-party/conduit/include/uitsl/math/shift_mod.hpp"
#include "../../../third-party/conduit/include/uitsl/polyfill/identity.hpp"
#include "../../../third-party/Empirical/include/emp/base/vector.hpp"
#include "../../../third-party/signalgp-lite/include/sgpl/utility/ThreadLocalRandom.hpp"

#include "../cell/cardinal_iterators/GenomeNodeInputWrapper.hpp"
#include "../config/cfg.hpp"
#include "../debug/LogScope.hpp"
#include "../peripheral/readable_state/ReadableState.hpp"
#include "../runninglog/BirthEvent.hpp"

namespace dish2 {

struct BirthSetupService {

  static bool ShouldRun( const size_t update, const bool alive ) {
    const size_t freq = dish2::cfg.BIRTH_SETUP_SERVICE_FREQUENCY();
    return
      freq > 0
      && uitsl::shift_mod( update, freq ) == 0;
  }

  template<typename Cell>
  static void DoService( Cell& cell ) {
    // TODO check quiescence period?
    const dish2::LogScope guard{ "birth setup service", "TODO", 3 };

    using spec_t = typename Cell::spec_t;

    thread_local emp::vector< size_t > fresh_input_idxs;
    fresh_input_idxs.clear();

    for (size_t idx{}; idx < cell.cardinals.size(); ++idx) {
      if ( cell.cardinals[idx].genome_node_input.Jump() ) {
        fresh_input_idxs.push_back( idx );
      }
    }

    if ( fresh_input_idxs.size() ) {

      const size_t cardinal_idx = fresh_input_idxs[
        sgpl::tlrand.Get().GetUInt( fresh_input_idxs.size() )
      ];
      const auto& peripheral = cell.cardinals[ cardinal_idx ].peripheral;
      const size_t epoch = peripheral.readable_state.template Get<
        dish2::Epoch
      >();

      const auto& incoming_genome = std::as_const(
        cell.cardinals[ cardinal_idx ].genome_node_input
      ).Get();
      const size_t replev = std::as_const(
        peripheral.state_node_input
      ).Get().template Get< dish2::RepLevRequest< spec_t > >().GetRepLev();

      // record birth event in running log
      const size_t kin_id_commonality_parent_daughter
        = spec_t::NLEV - replev;
      const size_t kin_id_commonality_daughter_eliminated = cell.genome
        ? cell.genome->kin_group_id.CountCommonality(
          incoming_genome.kin_group_id
        )
        : 0;
      const size_t kin_id_commonality_parent_eliminated =
        peripheral.readable_state.template Get<
          dish2::KinGroupIDView<spec_t>
        >().CountCommonality(
          std::as_const( peripheral.state_node_input ).Get().template Get<
            dish2::KinGroupIDView<spec_t>
          >()
        );
      cell.running_logs.Record( dish2::BirthEvent<spec_t>{
        kin_id_commonality_daughter_eliminated,
        kin_id_commonality_parent_daughter,
        kin_id_commonality_parent_eliminated,
        cell.GetPeripherality(),
        replev
      } );

      // setup new genome
      cell.DeathRoutine( dish2::CauseOfDeath::elimination );
      cell.genome = incoming_genome;
      cell.genome->ElapseGeneration( replev, epoch );

      cell.MakeAliveRoutine();
    }

  }

};

} // namespace dish2

#endif // #ifndef DISH2_SERVICES_BIRTHSETUPSERVICE_HPP_INCLUDE