Program Listing for File Cell.hpp

Return to documentation for file (include/dish2/cell/Cell.hpp)

#pragma once
#ifndef DISH2_CELL_CELL_HPP_INCLUDE
#define DISH2_CELL_CELL_HPP_INCLUDE

#include <cstddef>
#include <utility>

#include "../../../third-party/conduit/include/netuit/assign/AssignIntegrated.hpp"
#include "../../../third-party/conduit/include/netuit/assign/AssignThisProc.hpp"
#include "../../../third-party/conduit/include/netuit/mesh/Mesh.hpp"
#include "../../../third-party/conduit/include/netuit/mesh/MeshNode.hpp"
#include "../../../third-party/Empirical/include/emp/base/optional.hpp"
#include "../../../third-party/Empirical/include/emp/base/vector.hpp"
#include "../../../third-party/signalgp-lite/include/sgpl/utility/ThreadLocalRandom.hpp"

#include "../config/cfg.hpp"
#include "../enum/CauseOfDeath.hpp"
#include "../events/EventManager.hpp"
#include "../events/_index.hpp"
#include "../genome/Genome.hpp"
#include "../push/PushCellState.hpp"
#include "../quorum/CellQuorumState.hpp"
#include "../runninglog/RunningLogs.hpp"

#include "Cardinal.hpp"

#include "cardinal_iterators/IdentityWrapper.hpp"
#include "cardinal_iterators/NeighborKinGroupIDViewWrapper.hpp"
#include "cardinal_iterators/ResourceStockpileWrapper.hpp"

namespace dish2 {

template<typename Spec>
struct Cell {

  emp::vector< dish2::Cardinal<Spec> > cardinals;

  dish2::RunningLogs<Spec> running_logs;

  using genome_t = dish2::Genome<Spec>;
  emp::optional< genome_t > genome{ std::in_place, std::in_place };

  using genome_mesh_spec_t = typename Spec::genome_mesh_spec_t;
  using genome_node_t = netuit::MeshNode<genome_mesh_spec_t>;

  using intra_message_mesh_spec_t = typename Spec::intra_message_mesh_spec_t;
  using intra_message_node_t = netuit::MeshNode<intra_message_mesh_spec_t>;

  using message_mesh_spec_t = typename Spec::message_mesh_spec_t;
  using message_node_t = netuit::MeshNode<message_mesh_spec_t>;

  using push_mesh_spec_t = typename Spec::push_mesh_spec_t;
  using push_node_t = netuit::MeshNode<push_mesh_spec_t>;

  dish2::PushCellState cell_push_state;

  using quorum_mesh_spec_t = typename Spec::quorum_mesh_spec_t;
  using quorum_node_t = netuit::MeshNode<quorum_mesh_spec_t>;

  dish2::CellQuorumState< Spec > cell_quorum_state;

  using resource_mesh_spec_t = typename Spec::resource_mesh_spec_t;
  using resource_node_t = netuit::MeshNode<resource_mesh_spec_t>;

  using state_mesh_spec_t = typename Spec::state_mesh_spec_t;
  using state_node_t = netuit::MeshNode<state_mesh_spec_t>;

  using spec_t = Spec;
  using this_t = dish2::Cell<Spec>;

  // out of class implementations
  void DeathRoutine(const dish2::CauseOfDeath);
  void FragmentationRoutine();
  void HeirPayoutRoutine();
  void MakeAliveRoutine();

  Cell(
    const genome_node_t& genome_node,
    const message_node_t& message_node,
    const push_node_t& push_node,
    const quorum_node_t& quorum_node,
    const resource_node_t& resource_node,
    const state_node_t& state_node
  ) {

    // make sure that input and output counts are consistent
    emp_assert(( 1 == std::set<size_t>{
      genome_node.GetNumInputs(),
      message_node.GetNumInputs(),
      push_node.GetNumInputs(),
      quorum_node.GetNumInputs(),
      resource_node.GetNumInputs(),
      state_node.GetNumInputs(),
      genome_node.GetNumOutputs(),
      message_node.GetNumOutputs(),
      push_node.GetNumOutputs(),
      quorum_node.GetNumOutputs(),
      resource_node.GetNumOutputs(),
      state_node.GetNumOutputs(),
    }.size() ));

    const size_t num_cardinals = message_node.GetNumInputs();

    using intra_message_mesh_t = netuit::Mesh<intra_message_mesh_spec_t>;
    using intra_message_backend_t
      = typename intra_message_mesh_spec_t::ProcBackEnd;
    using intra_message_mesh_topology_factory_t
      = typename Spec::intra_topology_factory_t;
    intra_message_mesh_t intra_message_mesh{
      intra_message_mesh_topology_factory_t{}( num_cardinals ),
      uitsl::AssignIntegrated<uitsl::thread_id_t>{},
      netuit::AssignThisProc{},
      std::make_shared<intra_message_backend_t>(),
      MPI_COMM_WORLD,
      0 // const size_t mesh_id_
    };

    auto intra_message_submesh = intra_message_mesh.GetSubmesh(0);

    emp_assert( intra_message_submesh.size() == num_cardinals );

    // set up cardinals, one for each cell neighbor
    cardinals.reserve( num_cardinals );
    for (size_t i{}; i < num_cardinals; ++i) {
      cardinals.emplace_back(
        genome_node.GetInput(i),
        genome_node.GetOutput(i),
        message_node.GetInput(i),
        message_node.GetOutput(i),
        push_node.GetInput(i),
        push_node.GetOutput(i),
        quorum_node.GetInput(i),
        quorum_node.GetOutput(i),
        resource_node.GetInput(i),
        resource_node.GetOutput(i),
        state_node.GetInput(i),
        state_node.GetOutput(i),
        intra_message_submesh[i]
      );
    }

    MakeAliveRoutine();

    // setup start resource
    std::fill(
      this->template begin< dish2::ResourceStockpileWrapper<Spec> >(),
      this->template end< dish2::ResourceStockpileWrapper<Spec> >(),
      sgpl::tlrand.Get().GetDouble(
        dish2::cfg.MIN_START_RESOURCE(), dish2::cfg.MAX_START_RESOURCE()
      )
    );

  }

  void Clear() {
    genome.reset();
    for (auto& cardinal : cardinals) cardinal.Reset();
  }

  template<
    typename T=dish2::IdentityWrapper<Spec>, typename... Args
  >
  T begin( Args&&... args ) {
    return T{ cardinals.begin(), std::forward<Args>(args)... };
  }

  // TODO fix bad const_cast
  template<
    typename T=dish2::IdentityWrapper<Spec>, typename... Args
  >
  T begin( Args&&... args ) const {
    return T{
      const_cast<Cell*>(this)->cardinals.begin(),
    };
  }

  template<typename T=dish2::IdentityWrapper<Spec>>
  T end() { return T{ cardinals.end() }; }

  // TODO fix bad const_cast
  template<typename T=dish2::IdentityWrapper<Spec>>
  T end() const { return T{ const_cast<Cell*>(this)->cardinals.end() }; }

  bool IsAlive() const {
    emp_assert( cardinals.front().peripheral.readable_state.template Get<
      dish2::IsAlive
    >().Get() == genome.has_value() );
    return genome.has_value();
  }

  emp::optional<size_t> GetRootID() const {
    if (!IsAlive()) return {};
    else return {GetGenome().root_id};
  }

  size_t GetPeripherality( const size_t lev ) const {
    if ( !IsAlive() ) return false;

    const auto kin_group_id = genome->kin_group_id.GetBuffer()[ lev ];
    return std::count_if(
      this->begin<dish2::NeighborKinGroupIDViewWrapper<Spec>>(),
      this->end<dish2::NeighborKinGroupIDViewWrapper<Spec>>(),
      [lev, kin_group_id]( const auto& neighbor_kin_group_id_view ){
        return kin_group_id != neighbor_kin_group_id_view.Get( lev );
      }
    );
  }

  auto GetPeripherality() const {
    emp::array<size_t, Spec::NLEV> res;
    for (size_t l{}; l < Spec::NLEV; ++l) res[l] = GetPeripherality(l);
    return res;
  }

  size_t GetNumCardinals() const { return cardinals.size(); }

  const genome_t& GetGenome() const { return *genome; }

  void Update(const size_t update) {

    using service_manager_t = typename Spec::service_manager_t;

    service_manager_t::template Run<this_t>( *this, update, IsAlive() );

  }

};

} // namespace dish2

// include out of class implementtions
#include "routine_impls/_index.hpp"

#endif // #ifndef DISH2_CELL_CELL_HPP_INCLUDE