Commit 6aa5caf6 authored by Julian Zobel's avatar Julian Zobel
Browse files

More refactoring for social group movement

parent dc857437
......@@ -230,12 +230,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
int tries = 0;
do {
destination = new PositionVector(attractionCenter);
// Gaussian with std = 1 --> >99% of nodes
PositionVector offset = new PositionVector(
rand.nextGaussian() * apRadius / 3,
rand.nextGaussian() * apRadius / 3);
destination.add(offset);
destination = addGaussianOffsetToPosition(attractionCenter, apRadius / 3);
// Check constraints
if (!checkBoundaries(destination)) {
destination = null;
......@@ -257,6 +252,14 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
Event.scheduleWithDelay(timeBetweenMoveOperation, this, null,
EVENT_MOVE);
}
public PositionVector addGaussianOffsetToPosition(PositionVector position, double std) {
PositionVector offsetPosition = new PositionVector(position);
// Gaussian with std = 1 --> >99% of nodes
PositionVector offset = new PositionVector(rand.nextGaussian() * std, rand.nextGaussian() * std);
offsetPosition.add(offset);
return offsetPosition;
}
/**
*
......
......@@ -111,9 +111,8 @@ public class SocialGroupMovementModel extends ModularMovementModel {
// Check POIs if groups can be created. Delete groups, if destination reached.
groupFormingBehavior.manageGroups();
// Checks if groups encounter each other and applies a specified action to these groups.
Set<SocialMovementGroup[]> encounteringGroups = groupEncounterBehavior.getEncounteringGroups();
groupEncounterBehavior.handleEncounters(encounteringGroups);
// Checks if groups encounter each other and applies a specified action to these groups.
groupEncounterBehavior.handleEncounters();
/*
* Moves all nodes according to definition in group movement method
......
......@@ -89,6 +89,10 @@ public class MovementGroupContainer {
public void addGroup(SocialMovementGroup group) {
groups.add(group);
}
public boolean hasGroup(SocialMovementGroup group) {
return groups.contains(group);
}
/**
* Removes a group from the set of groups and sets the leftGroupAtTime variable for all group members.
......
......@@ -32,13 +32,14 @@ import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovement
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.common.datastructures.Pair;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* This class contains methods used by all encounter strategies.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
* @author Marcel Verst, Julian Zobel
* @version 1.1, 30.01.2020
*/
public abstract class AbstractGroupEncounter implements IGroupEncounterBehavior {
......@@ -79,6 +80,7 @@ public abstract class AbstractGroupEncounter implements IGroupEncounterBehavior
@Override
public void initialize(SocialGroupMovementModel movementModel) {
this.movementModel = movementModel;
groupCon = MovementGroupContainer.getInstance();
for(SimLocationActuator host : movementModel.getAllLocationActuators()) {
......@@ -86,61 +88,77 @@ public abstract class AbstractGroupEncounter implements IGroupEncounterBehavior
}
}
public Set<SocialMovementGroup[]> getEncounteringGroups() {
@Override
public Set<Pair<SocialMovementGroup>> getEncounteringGroups() {
if(!enableGroupEncounters)
return null;
Set<SocialMovementGroup[]> encounteringGroups = new LinkedHashSet<>();
Set<Pair<SocialMovementGroup>> encounteringGroups = new LinkedHashSet<>();
Set<SocialMovementGroup> alreadyProcessed = new LinkedHashSet<>();
Set<SocialMovementGroup> allGroups = groupCon.getGroups();
for(SocialMovementGroup group1 : allGroups) {
for(SocialMovementGroup group2 : allGroups) {
if(group1 != group2) {
if(!(alreadyProcessed.contains(group1) && alreadyProcessed.contains(group2))) {
if(getDistanceBetweenGroups(group1, group2) <= groupEncounterMeetingDistance) {
SimLocationActuator g1Leader = group1.getLeader();
if(!groupCon.getHasMerged().get(g1Leader)) {
SocialMovementGroup[] groups = new SocialMovementGroup[2];
groups[0] = group1;
groups[1] = group2;
encounteringGroups.add(groups);
alreadyProcessed.add(group1);
alreadyProcessed.add(group2);
}
else {
if(waitedLongEnoughAfterMerging(g1Leader)) {
SocialMovementGroup[] groups = new SocialMovementGroup[2];
groups[0] = group1;
groups[1] = group2;
encounteringGroups.add(groups);
alreadyProcessed.add(group1);
alreadyProcessed.add(group2);
}
}
}
}
if(group1 == group2) {
continue;
}
// skip if at least one of the groups is in the area of an attraction point
if(movementModel.getAttractionAssignmentStrategy().hostInAttractionPointArea(group1.getLeader())
|| movementModel.getAttractionAssignmentStrategy().hostInAttractionPointArea(group2.getLeader())) {
continue;
}
if(!(alreadyProcessed.contains(group1) && alreadyProcessed.contains(group2))) {
if(getDistanceBetweenGroups(group1, group2) <= groupEncounterMeetingDistance) {
SimLocationActuator g1Leader = group1.getLeader();
if(!groupCon.getHasMerged().get(g1Leader) || waitedLongEnoughAfterMerging(g1Leader) ) {
Pair<SocialMovementGroup> encounter = new Pair<SocialMovementGroup>(group1, group2);
encounteringGroups.add(encounter);
alreadyProcessed.add(group1);
alreadyProcessed.add(group2);
}
}
}
}
}
return encounteringGroups;
}
/**
* {@inheritDoc}
*/
public void handleEncounters(Set<SocialMovementGroup[]> encounteringGroups) {
public void handleEncounters() {
if(!enableGroupEncounters)
return;
Set<Pair<SocialMovementGroup>> encounteringGroups = getEncounteringGroups();
if(encounteringGroups == null || encounteringGroups.isEmpty()) {
return;
}
for(SocialMovementGroup[] groups : encounteringGroups) {
handleGroupEncounter(groups[0], groups[1]);
for(Pair<SocialMovementGroup> encounter : encounteringGroups) {
if(groupCon.hasGroup(encounter.getFirst()) && groupCon.hasGroup(encounter.getSecond())) {
handleGroupEncounter(encounter.getFirst(), encounter.getSecond());
}
}
}
/**
* Defines what to do with both groups in case they encountered.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
*
*/
protected abstract void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2);
/**
* Returns the distance between two groups based on their leaders position.
*
......@@ -236,9 +254,8 @@ public abstract class AbstractGroupEncounter implements IGroupEncounterBehavior
SocialMovementGroup large = getLargerGroup(group1, group2);
SocialMovementGroup small = getSmallerGroup(group1, group2);
Set<SimLocationActuator> toRemove = new LinkedHashSet<>();
toRemove.addAll(small.getMembers());
Set<SimLocationActuator> toRemove = new LinkedHashSet<>(small.getMembers());
for(SimLocationActuator participant : toRemove) {
small.removeHostFromGroup(participant);
groupCon.addLeftGroupAtTimeEntry(participant, Time.getCurrentTime());
......
......@@ -22,9 +22,9 @@ package de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupencounte
import java.util.Set;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
import de.tudarmstadt.maki.simonstrator.api.common.datastructures.Pair;
/**
* Handles group encounters. Check group encounters based on the leaders location of {@link SocialMovementGroup}s.
......@@ -37,35 +37,22 @@ public interface IGroupEncounterBehavior {
/**
* Initializes class variables.
*
* @author Marcel Verst
*/
void initialize(SocialGroupMovementModel movementModel);
/**
* Checks if any of the current groups come in a close range which is equivalent to a group meeting.
* Calls the handleGroupEncounters(Group, Group) method to define the group behavior.
*
* @author Marcel Verst
*
* @return
*/
Set<SocialMovementGroup[]> getEncounteringGroups();
Set<Pair<SocialMovementGroup>> getEncounteringGroups();
/**
* Applies an encountering action to each detected encountering groups.
*
* @param Set<Group[]> The set of encountering groups.
*
* @author Marcel Verst
*/
void handleEncounters(Set<SocialMovementGroup[]> encounteringGroups);
public void handleEncounters();
/**
* Defines what to do with both groups in case they encountered.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
*
* @author Marcel Verst
*/
void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2);
}
\ No newline at end of file
......@@ -66,12 +66,9 @@ public class Wait extends AbstractGroupEncounter{
*/
private void wait(SocialMovementGroup group1, SocialMovementGroup group2) {
// Do not apply waiting process if one of both groups is already waiting
if(groupCon.waitingGroups.containsKey(group1) && !groupCon.waitingGroups.containsKey(group2)) {
if(groupCon.waitingGroups.containsKey(group1) ^ groupCon.waitingGroups.containsKey(group2)) {
return;
}
if(!groupCon.waitingGroups.containsKey(group1) && groupCon.waitingGroups.containsKey(group2)) {
return;
}
}
// If both groups are not waiting, declare them as waiting groups for a duration of timeToWait
if(!groupCon.waitingGroups.containsKey(group1) && !groupCon.waitingGroups.containsKey(group2)) {
......
......@@ -193,12 +193,9 @@ public abstract class AbstractGroupForming implements IGroupFormingBehavior {
} while(nextDestination == leaderTarget);
// Add Offset to destination
PositionVector destination = new PositionVector(nextDestination);
double apRadius = nextDestination.getRadius();
PositionVector offset = new PositionVector(rand.nextGaussian() * apRadius / 3, rand.nextGaussian() * apRadius / 3);
destination.plus(offset);
PositionVector destination = movementModel.addGaussianOffsetToPosition(new PositionVector(nextDestination),
nextDestination.getRadius() / 3);
group.setDestination(destination);
setGroupMeetingPoint(group);
......@@ -350,23 +347,13 @@ public abstract class AbstractGroupForming implements IGroupFormingBehavior {
/**
* Checks if a host has waited long enough before he is allowed to join groups again.
* Returns true, if the host has waited long enough, false else.
* Returns true, if the host has waited long enough, false otherwise.
*
* @param SimLocationActuator The host to be checked.
* @param int The current time.
* @return boolean
*
* @author Marcel Verst
*/
protected boolean groupRejoinTimerExpired(SimLocationActuator host) {
long t = groupCon.getTimeSinceHostLeftLastGroup(host);
System.out.println(host.getHost().getId() + " | "+Time.getFormattedTime()
+" | Wait for:" +Time.getFormattedTime(t) + ", req is " + Time.getFormattedTime(groupRejoinWaitTime) );
boolean dec = t >= groupRejoinWaitTime;
return dec;
protected boolean groupRejoinTimerExpired(SimLocationActuator host) {
return groupCon.getTimeSinceHostLeftLastGroup(host) >= groupRejoinWaitTime;
}
/**
......@@ -374,8 +361,6 @@ public abstract class AbstractGroupForming implements IGroupFormingBehavior {
*
* @param SimLocacationActuator The host to be checked.
* @return Boolean
*
* @author Marcel Verst
*/
protected boolean beenInGroup(SimLocationActuator host) {
return groupCon.hostWasGroupMember(host);
......@@ -391,13 +376,12 @@ public abstract class AbstractGroupForming implements IGroupFormingBehavior {
* the group members first have to meet at the meeting point.
*
* @param SocialMovementGroup The group to set the meeting point.
*
* @author Marcel Verst, Julian Zobel
*/
protected void setGroupMeetingPoint(SocialMovementGroup group) {
PositionVector leaderPos = group.getLeader().getRealPosition();
BasicAttractionPoint meetingPoint = new BasicAttractionPoint("Group Movement Meeting Point of Leader #"+group.getLeader().getHost().getId(), leaderPos);
BasicAttractionPoint meetingPoint =
new BasicAttractionPoint("Group Movement Meeting Point of Leader #"+group.getLeader().getHost().getId(), leaderPos);
group.setMeetingPoint(meetingPoint);
......@@ -405,7 +389,7 @@ public abstract class AbstractGroupForming implements IGroupFormingBehavior {
for(SimLocationActuator participant : group.getMembers()) {
movementModel.getAttractionAssignmentStrategy().updateTargetAttractionPoint(participant, meetingPoint);
}
}
}
@Override
public int getMinGroupSize() {
......
......@@ -20,12 +20,13 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupforming;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
......@@ -36,7 +37,6 @@ import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
......@@ -103,43 +103,45 @@ public class DefaultGroupForming extends AbstractGroupForming {
int numberOfHostsInAttractionPoint = hostCounter.getHostCountOfAttractionPoint(apCandidate);
int groupSize = this.rndGroupSize(numberOfHostsInAttractionPoint);
Set<SimLocationActuator> groupCandidates = new LinkedHashSet<>();
Set<SimLocationActuator> hostsOfPoi = hostCounter.getHostsOfAttractionPoint(apCandidate);
// shuffle the hosts at the attraction point (more randomness ftw!)
LinkedList<SimLocationActuator> randomShuffledHostsAtAttractionPoint = new LinkedList<>(hostCounter.getHostsOfAttractionPoint(apCandidate));
Collections.shuffle(randomShuffledHostsAtAttractionPoint, rand);
for (SimLocationActuator m : hostsOfPoi) {
for (SimLocationActuator m : randomShuffledHostsAtAttractionPoint) {
// skip already added hosts (should never happen)
if(groupCandidates.contains(m)) {
System.err.println("Cannot be???");
continue;
}
// skip single hosts
if(movementModel.getSingleHosts().contains(m)) {
System.out.println("ACM Single Host is not added");
continue;
}
// skip hosts that are already part of a group
if(groupCon.isGroupMember(m)) {
System.out.println("No members allowed");
continue;
}
// test if the host wants and also is allowed to join this group
if(wantsToJoin()) {
if(!beenInGroup(m) || groupRejoinTimerExpired(m)) {
groupCandidates.add(m);
}
}
// do not continue if enough group members are gathered
if(groupCandidates.size() == groupSize) {
System.out.println("Group full, now go!");
break;
}
}
if(groupCandidates.isEmpty() || groupCandidates == null) {
System.out.println("--no cands");
// if there are no candidates, wait a minute until asking again
if(groupCandidates.isEmpty() || groupCandidates == null) {
Event.scheduleWithDelay(Time.MINUTE, new EventHandler() {
@Override
public void eventOccurred(Object content, int type) {
......@@ -149,13 +151,12 @@ public class DefaultGroupForming extends AbstractGroupForming {
break;
}
System.out.println("Group creation: " + groupCandidates.size() + " => " + apCandidate);
for(SimLocationActuator candidate : groupCandidates) {
INodeID id = candidate.getHost().getId();
stayDuration.put(id, new Tuple<Long, Long>(0L, Time.getCurrentTime())); // FIXME why?
}
}
createGroup(groupCandidates);
}
}
......@@ -214,18 +215,8 @@ public class DefaultGroupForming extends AbstractGroupForming {
for(SimLocationActuator component : movementModel.getAllLocationActuators()) {
INodeID id = component.getHost().getId();
// Check if host is in an AP area
boolean isInAp = false;
for(AttractionPoint ap : IAttractionGenerator.attractionPoints) {
Location hostLocation = component.getLastLocation();
if(ap.distanceTo(hostLocation) <= ap.getRadius()) {
isInAp = true;
break;
}
}
// In AP, increase stayDuration
if(isInAp) {
if(movementModel.getAttractionAssignmentStrategy().hostInAttractionPointArea(component)) {
Tuple<Long, Long> timeInfo = stayDuration.get(id);
long delta = Time.getCurrentTime() - timeInfo.getB();
......@@ -242,4 +233,6 @@ public class DefaultGroupForming extends AbstractGroupForming {
}
......@@ -20,6 +20,7 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupforming;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
/**
......@@ -59,7 +60,7 @@ public interface IGroupFormingBehavior {
* @author Marcel Verst
*/
void runGroupDeletionProcess();
public int getMinGroupSize();
public int getMaxGroupSize();
}
\ No newline at end of file
......@@ -128,4 +128,16 @@ public abstract class AbstractAttractionBasedAssignmentStrategy implements IAttr
AttractionPoint assignment = candidates.get(rnd.nextInt(candidates.size()));
return assignment;
}
@Override
public boolean hostInAttractionPointArea(SimLocationActuator host) {
for(AttractionPoint ap : IAttractionGenerator.attractionPoints) {
if(ap.distanceTo(host.getRealPosition()) <= ap.getRadius()) {
return true;
}
}
return false;
}
}
......@@ -84,5 +84,6 @@ public interface IAttractionAssigmentStrategy {
AttractionPoint newAssignment);
}
public boolean hostInAttractionPointArea(SimLocationActuator host);
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm.transition;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import java.util.*;
......@@ -68,4 +69,15 @@ public class ManualAssignmentStrategy implements IAttractionAssigmentStrategy
assignments.put(comp, attractionPoint);
listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
}
@Override
public boolean hostInAttractionPointArea(SimLocationActuator host) {
for(AttractionPoint ap : IAttractionGenerator.attractionPoints) {
if(ap.distanceTo(host.getRealPosition()) <= ap.getRadius()) {
return true;
}
}
return false;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment