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/Empirical/include/emp/math/random_utils.hpp"
#include "../../../third-party/signalgp-lite/include/sgpl/utility/ThreadLocalRandom.hpp"

#include "../cell/cardinal_iterators/GenomeNodeInputWrapper.hpp"
#include "../cell/cardinal_iterators/ResourceStockpileWrapper.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 );
      }
    }

    emp::Shuffle( sgpl::tlrand.Get(), fresh_input_idxs );

    // if current cell has >=1 resource, remove resource before accepting births
    float resource_stockpile = *cell.template begin<
      dish2::ResourceStockpileWrapper<spec_t>
    >();
    while (
      resource_stockpile >= dish2::cfg.SPAWN_DEFENSE_COST()
      && fresh_input_idxs.size()
    ) {
      resource_stockpile -= dish2::cfg.SPAWN_DEFENSE_COST();
      fresh_input_idxs.pop_back();
    }

    std::fill(
      cell.template begin<dish2::ResourceStockpileWrapper<spec_t>>(),
      cell.template end<dish2::ResourceStockpileWrapper<spec_t>>(),
      resource_stockpile
    );

    if ( fresh_input_idxs.size() ) {

      const size_t cardinal_idx = fresh_input_idxs.back();
      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
      if ( cell.genome.has_value() ) {
        cell.DeathRoutine( dish2::CauseOfDeath::elimination );
      }
      cell.genome = incoming_genome;
      cell.genome->ElapseGeneration( replev, epoch );

      cell.MakeAliveRoutine();

      // record SpawnedFrom direction
      cell.cardinals[cardinal_idx].peripheral.readable_state.template Get<
        dish2::SpawnedFrom
      >() = replev + 1;

    }

  }

};

} // namespace dish2

#endif // #ifndef DISH2_SERVICES_BIRTHSETUPSERVICE_HPP_INCLUDE