AbstractGroupForming.java 13.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
 *
 * This file is part of PeerfactSim.KOM.
 * 
 * PeerfactSim.KOM is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * PeerfactSim.KOM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with PeerfactSim.KOM.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupforming;

Julian Zobel's avatar
wip    
Julian Zobel committed
23
import java.util.LinkedHashMap;
24
25
26
27
import java.util.Map;
import java.util.Random;
import java.util.Set;

Julian Zobel's avatar
wip    
Julian Zobel committed
28
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
29
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
30
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ISocialGroupMovementAnalyzer;
31
32
33
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.BasicAttractionPoint;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
34
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.hostcount.HostAtAttractionPointCounter;
35
36
37
38
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.MovementGroupContainer;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.util.Tuple;
Julian Zobel's avatar
wip    
Julian Zobel committed
39
40
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
41
import de.tudarmstadt.maki.simonstrator.api.Monitor;
42
43
44
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
45
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
Julian Zobel's avatar
wip    
Julian Zobel committed
46
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
47
48
49
50

/**
 * Abstract class implementation for implementing GroupFormingStrategies.
 * 
51
52
 * @author Marcel Verst, Julian Zobel
 * @version 1.1, 30.01.2020
53
54
55
56
57
58
59
60
61
 */
public abstract class AbstractGroupForming implements IGroupFormingBehavior {
	protected Random rand = Randoms.getRandom(AbstractGroupForming.class);	
	
	protected SocialGroupMovementModel movementModel;	
	protected MovementGroupContainer groupCon;	
	
	// Holds time information of nodes for the groups (stay duration, last update)
	protected Map<INodeID, Tuple<Long,Long>> stayDuration;
Julian Zobel's avatar
wip    
Julian Zobel committed
62
	
63
64
65
66
67
	// GROUP VARIABLES FROM CONFIGS
	protected boolean enableGroups;
	protected int minGroupSize;
	protected int maxGroupSize;
	protected double probabilityToJoin;
Julian Zobel's avatar
wip    
Julian Zobel committed
68
69
70
71
	protected int maxNumberOfGroups;	
	
	protected long groupRejoinWaitTime;
	protected long groupFormationSetupDelay;
72
	private long groupFormationDelay;
73
74
	
	public static AbstractGroupForming instance;
75

Julian Zobel's avatar
wip    
Julian Zobel committed
76
77
78
	@XMLConfigurableConstructor({"enableGroups", "maxNumberOfGroups", "minGroupSize", "maxGroupSize", "probabilityToJoin", "groupFormationSetupDelay", "groupFormationDelay","groupRejoinWaitTime"})
	public AbstractGroupForming(boolean enableGroups, int maxNumberOfGroups, int minGroupSize, int maxGroupSize, double probabilityToJoin, long groupFormationSetupDelay, long groupFormationDelay, long groupRejoinWaitTime) {
		
79
80
		instance = this;
		
Julian Zobel's avatar
wip    
Julian Zobel committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
		this.enableGroups = enableGroups;
		
		if(enableGroups) {
			if (probabilityToJoin < 0 || probabilityToJoin > 1.0) {
				throw new ConfigurationException(
						"GroupForming: probabilityToJoin must be between 0.0 and 1.0!");
			}
			
			if (maxNumberOfGroups <= 0) {
				throw new ConfigurationException(
						"GroupForming: maxNumberOfGroups must be >= 1!");
			}
			
			if (minGroupSize < 0) {
				throw new ConfigurationException(
						"GroupForming: minGroupSize must be >= 1!");
			}
			
			if (maxGroupSize < minGroupSize) {
				throw new ConfigurationException(
						"GroupForming: maxGroupSize cannot be bigger than minGroupSize!");
			}
			
			if (groupFormationSetupDelay <= 0) {
				throw new ConfigurationException(
						"GroupForming: groupFormationSetupDelay must be > 0!");
			}
			
109
			if (groupFormationDelay < -1) {
Julian Zobel's avatar
wip    
Julian Zobel committed
110
				throw new ConfigurationException(
111
						"GroupForming: groupFormationDelay must be >= -1!");
Julian Zobel's avatar
wip    
Julian Zobel committed
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
			}
			
			if (groupRejoinWaitTime < 0) {
				throw new ConfigurationException(
						"GroupForming: groupRejoinWaitTime must be >= 1!");
			}
		}
		
		this.maxNumberOfGroups = maxNumberOfGroups;
		this.minGroupSize = minGroupSize;
		this.maxGroupSize = maxGroupSize;
		this.probabilityToJoin = probabilityToJoin;		
		this.groupFormationSetupDelay = groupFormationSetupDelay;
		this.groupFormationDelay = groupFormationDelay;
		this.groupRejoinWaitTime = groupRejoinWaitTime;
	}
	
	@Override
	public void initialize(SocialGroupMovementModel movementModel) {
		this.movementModel = movementModel;
		
		groupCon = MovementGroupContainer.getInstance();		
		
		stayDuration = new LinkedHashMap<INodeID, Tuple<Long,Long>>();

		for(SimLocationActuator host : movementModel.getAllLocationActuators()) {
			stayDuration.put(host.getHost().getId(), new Tuple<Long, Long>(0L, Time.getCurrentTime()));			
		}
		
141
142
143
144
145
146
147
148
149
150
151
152
		
		for(int g = 0; g < 20; g++) {
			
			// FIXME random Gauß distribution?
			long std = (long) (4.3 * Time.MINUTE);
			long mean = (long) (7.38 * Time.MINUTE);					
			long delay = (long) (rand.nextGaussian() * std + mean);
			
			delay = (long) ((rand.nextDouble() * (Time.MINUTE * 45) + Time.MINUTE));		
			
			if(delay < Time.MINUTE) {
				delay = Time.MINUTE;
Julian Zobel's avatar
wip    
Julian Zobel committed
153
			}
154
			
155
			// System.out.println(Time.getFormattedTime(delay) );
156
157
158
159
160
161
162
163
						
			Event.scheduleWithDelay(delay, new EventHandler() {			
				@Override
				public void eventOccurred(Object content, int type) {
					assembleGroup();
				}
			}, null, 0);			
		}		
Julian Zobel's avatar
wip    
Julian Zobel committed
164
	}
165

Julian Zobel's avatar
wip    
Julian Zobel committed
166
	
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
	/**
	 * Returns a time delay between removal and creation of a group. A random part of up to half of the 
	 * stated formation delay is added to/substracted from the formation delay.
	 * 
	 * @return
	 */
	protected long rndGroupFormationDelay() {		
		return (long) ((rand.nextDouble() + 0.5) * groupFormationDelay);		
	}
	
	/**
	 * Returns a random integer value between the minimum and maximumn group size boundaries 
	 * with an additional upper boundary. 
	 *  
	 * @return
	 */
	protected int rndGroupSize(int max) {			
		return Math.min(rndGroupSize(), max);
	}
	
	/**
	 * Returns a random integer value between the minimum and maximumn group size boundaries.
	 *  
	 * @return
	 */
	protected int rndGroupSize() {
193
194
		if(maxGroupSize == minGroupSize) 
			return minGroupSize;
195
196
197
198
199
200
201
		else {
			// int groupsize = (int) Math.max(1, rand.nextGaussian() * 0.93 + 2.76);
			int groupsize = rand.nextInt(5) + 1;
			System.out.println(groupsize);
			return groupsize;
		}
		//return rand.nextInt(maxGroupSize - minGroupSize) + minGroupSize;
202
203
	}
	
204
	/**
205
	 * Creates a group with the given set of members.
206
	 * 
207
	 * @param Set<SimLocationActuator> The members which want to form a group.
208
	 */
209
210
	protected void createGroup(Set<SimLocationActuator> members) {		
		SocialMovementGroup group = new SocialMovementGroup(members);
211
	
Julian Zobel's avatar
Julian Zobel committed
212
213
214
215
216
		// force a new attraction point assignment on the leader
		IAttractionPoint currentDestination = movementModel.getAttractionAssignmentStrategy().getAssignment(group.getLeader());
		movementModel.getAttractionAssignmentStrategy().addComponent(group.getLeader());		
		IAttractionPoint targetDestination =  movementModel.getAttractionAssignmentStrategy().getAssignment(group.getLeader());
				
217
		// Add Offset to group destination
Julian Zobel's avatar
Julian Zobel committed
218
219
		PositionVector destination = movementModel.addGaussianOffsetToPosition(new PositionVector(targetDestination),
				targetDestination.getRadius() / 3);
220
				
221
		group.setDestination(destination);
Julian Zobel's avatar
wip    
Julian Zobel committed
222
		setGroupMeetingPoint(group);
223
224

		for(SimLocationActuator member : group.getMembers()) {
Julian Zobel's avatar
Julian Zobel committed
225
226
227
228
229
			// only set the attraction point for non-leaders, as the leader was already assigned an attraction point above
			if(group.getLeader() != member) {
				member.setTargetAttractionPoint(targetDestination);
			}
			// remove any left-over entries
230
			if(groupCon.hostWasGroupMember(member)) {
231
232
233
				groupCon.removeLeftGroupAtTimeEntry(member);
			}
		}
Julian Zobel's avatar
wip    
Julian Zobel committed
234
		
235
		groupCon.addGroup(group);
236
237
238
		
		// Inform analyzer of new group
		if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {			
Julian Zobel's avatar
Julian Zobel committed
239
			Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupForming(group, currentDestination, targetDestination);
240
		}
241
242
243
244
245
246
247
248
	}

	/**
	 * Removes a group.
	 * 
	 * @param SocialMovementGroup The group to be removed.
	 * 
	 */
249
250
	@Override
	public void removeGroup(SocialMovementGroup group) {
251
252
253
254
255
256
257
258
259
260
261
			
		// Inform analyzer of group removal
		if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {			
			Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupDisbanding(group);
		}
				
		// If this group is removed, reassign the group target attraction point as new target attraction point 
		// for each former group member (prevents errors when routing was not reset correctly)
		if(group.getGroupSize() > 0 || group.getLeader() != null) {
			IAttractionPoint currentAP = group.getLeader().getCurrentTargetAttractionPoint();
			
Julian Zobel's avatar
Julian Zobel committed
262
263
			for (SimLocationActuator host : group.getMembers()) {		
				host.setTargetAttractionPoint(currentAP);
264
265
266
			}			
		}			
	
267
		groupCon.removeGroup(group);
268
		
269
270
		long delay = 0;		
			
271
		if(groupFormationDelay == -1) {
272
273
274
275
276
277
			if(group.getLeader() == null) {
				delay = movementModel.getAttractionAssignmentStrategy().getPauseTime(null);
			}	
			else {
				delay = movementModel.getAttractionAssignmentStrategy().getPauseTime(group.getLeader().getCurrentTargetAttractionPoint());
			}
278
279
280
281
		}
		else {
			delay = rndGroupFormationDelay();
		}
282
	
283
		Event.scheduleWithDelay(delay, new EventHandler() {			
284
285
			@Override
			public void eventOccurred(Object content, int type) {
286
				assembleGroup();		
287
288
			}
		}, null, 0);
289
	}
290
291
292
293
	
	public static void nodeready() {
		instance.assembleGroup();
	}
294

295
296
297
	protected abstract void assembleGroup();
	
	
298
299
300
301
302
303
	/**
	 * Returns the first AttractionPoint which contains the host with the greatest stayDuration of all hosts located in AttractionPoints.
	 * 
	 * @return AttractionPoint
	 * 
	 */
304
305
	protected IAttractionPoint getAttractionPointWithOldestHost() {
		IAttractionPoint result = null;
306
307
		long maxDuration = 0;
		
308
309
		for(IAttractionPoint ap : IAttractionGenerator.attractionPoints) {
			for(SimLocationActuator host :  HostAtAttractionPointCounter.getHostsOfAttractionPoint(ap, movementModel.getAllLocationActuators())) {
310
311
312
313
314
315
316
317
318
319
320
321
				INodeID id = host.getHost().getId();
				long duration = stayDuration.get(id).getA();
				
				if(duration > maxDuration) {					
					result = ap;
					maxDuration = duration;
				}
			}
		}
		
		return result;
	}
322
		
323
324
	protected IAttractionPoint getAttractionPointWithMostHosts() {
		IAttractionPoint apCandidate = null;
325
		int size = 0;
326
327
		for(IAttractionPoint ap : IAttractionGenerator.attractionPoints) {
			int numberOfHostsInAP = HostAtAttractionPointCounter.getHostCountOfAttractionPoint(ap, movementModel.getAllLocationActuators());
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
			if(numberOfHostsInAP > size) {
				apCandidate = ap;
				size = numberOfHostsInAP;
			}
		}
		return apCandidate;
	}
	
	/**
	 * Checks if a host wants to join a group or not based on a given probability.
	 * Returns true if willing to join, false else.
	 * 
	 * @return boolean
	 */
	protected boolean wantsToJoin() {
		return (rand.nextDouble() <= probabilityToJoin);
	}

	/**
	 * Checks if a host has waited long enough before he is allowed to join groups again.
348
	 * Returns true, if the host has waited long enough, false otherwise.
349
350
351
352
	 * 
	 * @param SimLocationActuator The host to be checked.
	 * @return boolean
	 */
353
354
	protected boolean groupRejoinTimerExpired(SimLocationActuator host) {		
		return groupCon.getTimeSinceHostLeftLastGroup(host) >= groupRejoinWaitTime;		
355
356
357
358
359
360
361
362
363
	}

	/**
	 * Returns true, if a host has been in a group before at least once. False else.
	 * 
	 * @param SimLocacationActuator The host to be checked.
	 * @return Boolean
	 */
	protected boolean beenInGroup(SimLocationActuator host) {
364
		return groupCon.hostWasGroupMember(host);
365
366
367
368
369
370
371
372
373
374
375
376
377
	}

	/* 
	 * =====================================================================================================
	 * === MEETING POINT FUNCTIONS
	 * =====================================================================================================
	 */
	/**
	 * Sets the meeting point of a group after the group has been created. Before walking towards the destination,
	 * the group members first have to meet at the meeting point.
	 * 
	 * @param SocialMovementGroup The group to set the meeting point.
	 */
Julian Zobel's avatar
wip    
Julian Zobel committed
378
	protected void setGroupMeetingPoint(SocialMovementGroup group) {
379
380
		PositionVector leaderPos = group.getLeader().getRealPosition();
		
381
382
		BasicAttractionPoint meetingPoint = 
				new BasicAttractionPoint("Group Movement Meeting Point of Leader #"+group.getLeader().getHost().getId(), leaderPos);
383
384
	
		group.setMeetingPoint(meetingPoint);
385
	}	
Julian Zobel's avatar
wip    
Julian Zobel committed
386
387
388
389
390
	
	@Override
	public int getMinGroupSize() {
		return minGroupSize;
	}
391

Julian Zobel's avatar
wip    
Julian Zobel committed
392
393
394
395
	@Override
	public int getMaxGroupSize() {
		return maxGroupSize;
	}
396
397

}