fpmas-metamodel 1.0
Loading...
Searching...
No Matches
agent.h
Go to the documentation of this file.
1#pragma once
2
3#include "fpmas.h"
4#include "cell.h"
5
14template<typename CellType>
22 virtual CellType* selectCell(
23 fpmas::model::Neighbors<CellType>& mobility_field) const = 0;
24};
25
32template<typename CellType>
33struct RandomMovePolicy : public MovePolicyFunction<CellType> {
34 CellType* selectCell(
35 fpmas::model::Neighbors<CellType>& mobility_field) const override;
36};
37
43template<typename CellType>
44struct MaxMovePolicy : public MovePolicyFunction<CellType> {
45 CellType* selectCell(
46 fpmas::model::Neighbors<CellType>& mobility_field) const override;
47};
48
49template<typename CellType>
51 fpmas::model::Neighbors<CellType> &mobility_field) const {
52 std::vector<float> utilities;
53 std::vector<CellType*> cells;
54
55 bool null_utilities = true;
56 for(auto cell : mobility_field) {
57 fpmas::model::ReadGuard read(cell);
58 if(cell->getUtility() > 0)
59 null_utilities = false;
60 utilities.push_back(cell->getUtility());
61 cells.push_back(cell);
62 }
63 std::size_t rd_index;
64 if(null_utilities) {
65 fpmas::random::UniformIntDistribution<std::size_t> rd_cell(0, cells.size()-1);
66 rd_index = rd_cell(fpmas::model::RandomNeighbors::rd);
67 } else {
68 fpmas::random::DiscreteDistribution<std::size_t> rd_cell(utilities);
69 rd_index = rd_cell(fpmas::model::RandomNeighbors::rd);
70 }
71 return cells[rd_index];
72}
73
74template<typename CellType>
76 fpmas::model::Neighbors<CellType> &mobility_field) const {
77 // Prevents bias when several cells have the max value
78 mobility_field.shuffle();
79
80 std::vector<std::pair<CellType*, float>> cells;
81 for(auto cell : mobility_field) {
82 fpmas::model::ReadGuard read(cell);
83 cells.push_back({cell, cell->getUtility()});
84 }
85
86 return std::max_element(cells.begin(), cells.end(),
87 [] (
88 const std::pair<CellType*, float>& a1,
89 const std::pair<CellType*, float>& a2
90 ) {
91 return a1.second < a2.second;
92 }
93 )->first;
94}
95
106 public:
110 static std::size_t max_contacts;
116 static std::size_t range_size;
120 static float contact_weight;
126 private:
127 std::deque<DistributedId> _contacts;
128 protected:
133 std::deque<DistributedId>& contacts();
134
135 public:
143 bool is_in_contacts(DistributedId id);
144
148 virtual const fpmas::api::model::AgentNode* agentNode() const = 0;
149 public:
160 MetaAgentBase(const std::deque<DistributedId>& contacts)
161 : _contacts(contacts) {}
162
166 const std::deque<DistributedId>& contacts() const;
167};
168
180template<typename AgentBase, typename PerceptionRange>
181class MetaAgent : public AgentBase, public MetaAgentBase {
182 private:
183 PerceptionRange range;
184
189 void add_to_contacts(fpmas::api::model::Agent* agent);
190
191 public:
195 MetaAgent() : range(range_size) {}
201 MetaAgent(const std::deque<DistributedId>& contacts)
202 : MetaAgentBase(contacts), range(range_size) {}
203
212
238 void handle_new_contacts();
242 void move();
243
244 const fpmas::api::model::AgentNode* agentNode() const override {
245 return this->AgentBase::node();
246 }
247};
248
249template<typename AgentBase, typename PerceptionRange>
250void MetaAgent<AgentBase, PerceptionRange>::add_to_contacts(fpmas::api::model::Agent* agent) {
251 if(contacts().size() == max_contacts) {
252 for(auto edge : this->node()->getOutgoingEdges(CONTACT)) {
253 // Finds the edge corresponding to the queue's head and unlinks it
254 if(edge->getTargetNode()->getId() == contacts().front()) {
255 this->model()->graph().unlink(edge);
256 // No need to loop until the last edge
257 break;
258 }
259 }
260 // Removes queue's head once unlinked
261 contacts().pop_front();
262 }
263 // Links the new contact...
264 this->model()->link(this, agent, CONTACT)->setWeight(MetaAgentBase::contact_weight);
265 // ... and adds it at the end of the queue
266 contacts().push_back(agent->node()->getId());
267}
268
269template<typename AgentBase, typename PerceptionRange>
271 // Agents currently in the Moore neighborhood
272 auto perceptions = this->perceptions();
273 // Shuffles perceptions, to ensure that a random perception will be
274 // selected as a new contact
275 perceptions.shuffle();
276
277 auto current_perception = perceptions.begin();
278 // Searches for an agent not already in this agent's contact in the current
279 // Moore neighborhood
280 while(current_perception != perceptions.end()) {
281 if(!is_in_contacts(current_perception->agent()->node()->getId())) {
282 add_to_contacts(*current_perception);
283
284 // Ends while loop
285 current_perception = perceptions.end();
286 } else {
287 current_perception++;
288 }
289 }
290}
291
292template<typename AgentBase, typename PerceptionRange>
294 auto contacts =
295 this->template outNeighbors<MetaAgent<AgentBase, PerceptionRange>>(CONTACT);
296 if(contacts.count() >= 2) {
297 // Selects a random contact and puts it at the begining of the list.
298 std::size_t random_index =
299 fpmas::random::UniformIntDistribution<std::size_t>(0, contacts.count()-1)(
300 fpmas::model::RandomNeighbors::rd
301 );
302 std::swap(contacts[0], contacts[random_index]);
303 // contacts[0] is now the contact to which we would like to add a new
304 // contact from this agent's contacts.
305 std::size_t i = 1;
306 {
307 // Reads contacts[0], so that is_in_contacts() can be called safely
308 fpmas::model::ReadGuard read(contacts[0]);
309 // Searches a contact from this agent's contacts that is not
310 // already in contacts[0]'s contacts
311 while(
312 i < contacts.count() &&
313 contacts[0]->is_in_contacts(contacts[i]->node()->getId()))
314 i++;
315 }
316 if(i < contacts.count())
317 // If founds, creates a NEW_CONTACT, that will be handled from
318 // contacts[0] by handle_new_contacts() after the next
319 // synchronization.
320 this->model()->link(contacts[0], contacts[i], NEW_CONTACT);
321 }
322}
323
324template<typename AgentBase, typename PerceptionRange>
326 auto new_contacts =
327 this->template outNeighbors<MetaAgent<AgentBase, PerceptionRange>>(NEW_CONTACT);
328 for(auto new_contact : new_contacts) {
329 // Adds new_contact to this agent's contacts
330 add_to_contacts(new_contact);
331
332 // Unlinks temporary NEW_CONTACT edge
333 this->model()->unlink(new_contact.edge());
334 }
335}
336
337template<typename AgentBase, typename PerceptionRange>
339 auto mobility_field = this->mobilityField();
340 typename AgentBase::Cell* selected_cell;
341 switch(move_policy) {
344 .selectCell(mobility_field);
345 break;
346 case MovePolicy::MAX:
348 .selectCell(mobility_field);
349 break;
350 };
351
352 this->moveTo(selected_cell);
353}
354
361template<typename AgentType>
366 static void to_json(nlohmann::json& j, const AgentType* agent);
370 static AgentType* from_json(const nlohmann::json& j);
371
375 static std::size_t size(const fpmas::io::datapack::ObjectPack& o, const AgentType* agent);
379 static void to_datapack(
380 fpmas::io::datapack::ObjectPack& o, const AgentType* agent);
384 static AgentType* from_datapack(const fpmas::io::datapack::ObjectPack& o);
385};
386
387template<typename AgentType>
388void MetaAgentSerialization<AgentType>::to_json(nlohmann::json& j, const AgentType* agent) {
389 j = agent->contacts();
390}
391
392template<typename AgentType>
393AgentType* MetaAgentSerialization<AgentType>::from_json(const nlohmann::json& j) {
394 return new AgentType(j.get<std::deque<DistributedId>>());
395}
396
397template<typename AgentType>
399 const fpmas::io::datapack::ObjectPack &o, const AgentType *agent) {
400 return o.size(agent->contacts());
401}
402
403template<typename AgentType>
405 fpmas::io::datapack::ObjectPack& o, const AgentType* agent) {
406 o.put(agent->contacts());
407}
408
409template<typename AgentType>
411 const fpmas::io::datapack::ObjectPack &o) {
412 return new AgentType(o.get<std::deque<DistributedId>>());
413}
414
419 public MetaAgent<
420 GridAgent<MetaGridAgent, MetaGridCell>,
421 MooreRange<MooreGrid<MetaGridCell>>>,
422 public MetaAgentSerialization<MetaGridAgent> {
423 public:
424 using MetaAgent<
425 GridAgent<MetaGridAgent, MetaGridCell>,
426 MooreRange<MooreGrid<MetaGridCell>>>::MetaAgent;
427};
428
433 public MetaAgent<
434 SpatialAgent<MetaGraphAgent, MetaGraphCell>, GraphRange<MetaGraphCell>
435 >,
436 public MetaAgentSerialization<MetaGraphAgent> {
437 using MetaAgent<
438 SpatialAgent<MetaGraphAgent, MetaGraphCell>, GraphRange<MetaGraphCell>
440 };
Definition: agent.h:105
const std::deque< DistributedId > & contacts() const
static std::size_t range_size
Definition: agent.h:116
static std::size_t max_contacts
Definition: agent.h:110
MetaAgentBase(const std::deque< DistributedId > &contacts)
Definition: agent.h:160
static MovePolicy move_policy
Definition: agent.h:125
MetaAgentBase()
Definition: agent.h:154
bool is_in_contacts(DistributedId id)
virtual const fpmas::api::model::AgentNode * agentNode() const =0
static float contact_weight
Definition: agent.h:120
std::deque< DistributedId > & contacts()
Definition: agent.h:181
void handle_new_contacts()
Definition: agent.h:325
FPMAS_PERCEPTION_RANGE(range)
FPMAS_MOBILITY_RANGE(range)
MetaAgent()
Definition: agent.h:195
const fpmas::api::model::AgentNode * agentNode() const override
Definition: agent.h:244
void create_relations_from_contacts()
Definition: agent.h:293
MetaAgent(const std::deque< DistributedId > &contacts)
Definition: agent.h:201
void move()
Definition: agent.h:338
void create_relations_from_neighborhood()
Definition: agent.h:270
Definition: agent.h:436
Definition: agent.h:422
MovePolicy
Definition: config.h:99
Definition: agent.h:44
CellType * selectCell(fpmas::model::Neighbors< CellType > &mobility_field) const override
Definition: agent.h:75
Definition: agent.h:362
static AgentType * from_json(const nlohmann::json &j)
Definition: agent.h:393
static void to_datapack(fpmas::io::datapack::ObjectPack &o, const AgentType *agent)
Definition: agent.h:404
static AgentType * from_datapack(const fpmas::io::datapack::ObjectPack &o)
Definition: agent.h:410
static std::size_t size(const fpmas::io::datapack::ObjectPack &o, const AgentType *agent)
Definition: agent.h:398
static void to_json(nlohmann::json &j, const AgentType *agent)
Definition: agent.h:388
Definition: agent.h:15
virtual CellType * selectCell(fpmas::model::Neighbors< CellType > &mobility_field) const =0
Definition: agent.h:33
CellType * selectCell(fpmas::model::Neighbors< CellType > &mobility_field) const override
Definition: agent.h:50