Passed
Push — master ( 634a3f...1f3b93 )
by Alessandro
05:38
created

notify(TemporalNetworkNotification)   B

Complexity

Conditions 7

Size

Total Lines 135
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 14
dl 0
loc 135
rs 8
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
package it.cnr.istc.pst.platinum.ai.framework.time.solver.apsp;
2
3
import java.util.HashMap;
4
import java.util.Iterator;
5
import java.util.Map;
6
7
import it.cnr.istc.pst.platinum.ai.framework.time.solver.TemporalSolver;
8
import it.cnr.istc.pst.platinum.ai.framework.time.tn.TemporalNetwork;
9
import it.cnr.istc.pst.platinum.ai.framework.time.tn.TimePoint;
10
import it.cnr.istc.pst.platinum.ai.framework.time.tn.lang.event.TemporalNetworkNotification;
11
import it.cnr.istc.pst.platinum.ai.framework.time.tn.lang.query.TimePointDistanceFromOriginQuery;
12
import it.cnr.istc.pst.platinum.ai.framework.time.tn.lang.query.TimePointDistanceQuery;
13
import it.cnr.istc.pst.platinum.ai.framework.time.tn.lang.query.TimePointDistanceToHorizonQuery;
14
import it.cnr.istc.pst.platinum.ai.framework.time.tn.lang.query.TimePointQuery;
15
import it.cnr.istc.pst.platinum.ai.framework.time.tn.lang.query.TimePointScheduleQuery;
16
17
/**
18
 * 
19
 * @author alessandro
20
 *
21
 */
22
public final class APSPTemporalSolver extends TemporalSolver<TimePointQuery>
23
{
24
	private DistanceGraph dg;									// distance graph
25
	private Map<TimePoint, Map<TimePoint, Long>> distance;		// the distance matrix containing the minimum distances between points;
26
	private boolean toPropagate;								// lazy approach - propagate constraint only when needed
27
	private int propagationCounter;		
28
	
29
	/**
30
	 * Create an All-Pair-Shortest-Path Solver instance.
31
	 * 
32
	 */
33
	public APSPTemporalSolver(TemporalNetwork tn) {
34
		super(tn);
35
		
36
		// initialize APSP data structure
37
		this.distance = null;
38
		// attribute for testing purposes
39
		this.propagationCounter = 0;
40
		// initialize
41
		this.dg();
42
		// set flag
43
		this.toPropagate = true;
44
	}
45
	
46
	/**
47
	 * 
48
	 */
49
	private void dg() {
50
51
		// create the distance graph
52
		this.dg = new DistanceGraph();
53
		// set temporal horizon
54
		this.dg.setInfity(this.tn.getHorizon());
55
		// add all points to the distance graph
56
		for (TimePoint point : this.tn.getTimePoints()) {
57
			// add node to the distance graph
58
			this.dg.add(point);
59
		}
60
		
61
		// add edges between points 
62
		for (TimePoint reference : this.tn.getTimePoints()) {
63
			for (TimePoint target : this.tn.getTimePoints()) {
64
				
65
				// check if different
66
				if (!reference.equals(target)) {
67
					
68
					// get constraint bounds
69
					long[] bounds = this.tn.getConstraintBounds(reference, target);
70
					// check if a bound exists
71
					if (bounds != null) {
72
						
73
						// set distance graph's edges according to the computed bounds
74
						this.dg.add(reference, target, bounds[1]);
75
						this.dg.add(target, reference, -bounds[0]);
76
					}
77
				} 
78
			}
79
		}
80
	}
81
	
82
	/**
83
	 * 
84
	 * @return
85
	 */
86
	@Override
87
	public boolean isConsistent() 
88
	{
89
		// check information status
90
		if (this.toPropagate) {
91
			// clean distance matrix's data
92
			this.compute();
93
		}
94
		
95
		// check consistency
96
		boolean consistent = true;
97
		Iterator<TimePoint> it = this.dg.getPoints().iterator();
98
		while (it.hasNext() && consistent) {
99
			
100
			// next time point
101
			TimePoint tp = it.next();
102
			// check cyclic distance
103
			long d = this.distance.get(tp).get(tp);
104
			// check condition
105
			consistent = (d == 0);
106
		}
107
		
108
		// get consistency check result
109
		return consistent;
110
	}
111
	
112
	/**
113
	 * 
114
	 */
115
	@Override
116
	public void notify(TemporalNetworkNotification info)
117
	{
118
		// check notification type
119
		switch (info.getType()) 
120
		{
121
			// temporal network initialized
122
//			case INITIALIZATION: {
123
//		
124
//				// initialize data structures
125
//				this.dg();
126
//				// set to propagate flag
127
//				this.toPropagate = true;
128
//			}
129
//			break;
130
		
131
			// temporal constraint added
132
//			case ADD_REL: {
133
//
134
//				// handle request
135
//				AddRelationTemporalNetworkNotification notif = (AddRelationTemporalNetworkNotification) info;
136
//				// check pairs of involved time points
137
//				Map<TimePoint, Set<TimePoint>> p2p= new HashMap<>();
138
//				// check added constraints
139
//				for (TimePointDistanceConstraint constraint : notif.getRels()) {
140
//					// check time points
141
//					if (!p2p.containsKey(constraint.getReference())) {
142
//						p2p.put(constraint.getReference(), new HashSet<>());
143
//					}
144
//					
145
//					// add pair
146
//					p2p.get(constraint.getReference()).add(constraint.getTarget());
147
//				}
148
//				
149
//				
150
//				// update the internal distance graph
151
//				for (TimePoint reference : p2p.keySet()) {
152
//					for (TimePoint target : p2p.get(reference)) {
153
//						
154
//						// get constraint bounds
155
//						long[] bounds = this.tn.getConstraintBounds(reference, target);
156
//						// check if bound exists
157
//						if (bounds != null) {
158
//							// add/replace the associated edge of the distance graph
159
//							this.dg.add(reference, target, bounds[1]);
160
//							this.dg.add(target, reference, -bounds[0]);
161
//						}
162
//					}
163
//				}
164
//				
165
//				// set propagate flag
166
//				this.toPropagate = true;
167
//			}
168
//			break;
169
			
170
			// temporal constraint deleted 
171
//			case DEL_REL: {
172
//				
173
//				// handle request
174
//				DelRelationTemporalNetworkNotification notif = (DelRelationTemporalNetworkNotification) info;
175
//				// check pairs of involved time points
176
//				Map<TimePoint, Set<TimePoint>> p2p= new HashMap<>();
177
//				for (TimePointDistanceConstraint constraint : notif.getRels()) {
178
//					// check time points
179
//					if (!p2p.containsKey(constraint.getReference())) {
180
//						p2p.put(constraint.getReference(), new HashSet<>());
181
//					}
182
//					
183
//					// add pair
184
//					p2p.get(constraint.getReference()).add(constraint.getTarget());
185
//				}
186
//				
187
//				
188
//				// update the internal distance graph
189
//				for (TimePoint reference : p2p.keySet()) {
190
//					for (TimePoint target : p2p.get(reference)) {
191
//						
192
//						// get constraint bounds
193
//						long[] bounds = this.tn.getConstraintBounds(reference, target);
194
//						// check if bound exists
195
//						if (bounds != null) {
196
//							// add/replace the associated edge of the distance graph
197
//							this.dg.add(reference, target, bounds[1]);
198
//							this.dg.add(target, reference, -bounds[0]);
199
//						}
200
//					}
201
//				}
202
//				
203
//				// set propagate flag
204
//				this.toPropagate = true;
205
//			}
206
//			break;
207
			
208
			// time point deleted
209
			case INITIALIZATION :
210
			case ADD_TP : 
211
			case ADD_REL : 
212
			case DEL_REL : 
213
			case DEL_TP : {
214
				
215
				// handle request
216
//				DelTimePointTemporalNetworkNotification notif = (DelTimePointTemporalNetworkNotification) info;
217
				// delete time points
218
//				for (TimePoint point : notif.getPoints()) {
219
//					// delete node from the distance graph
220
//					this.dg.delete(point);
221
//				}
222
//				
223
				// recompute dependency graph distance bounds
224
				this.dg();	
225
				// set to propagate flag
226
				this.toPropagate = true;
227
			}
228
			break;
229
			
230
			// time point added 
231
//			case ADD_TP: {
232
//				
233
//				// handle request
234
//				AddTimePointTemporalNetworkNotification notif = (AddTimePointTemporalNetworkNotification) info;
235
//				// get added time points
236
//				for (TimePoint point : notif.getPoints()) {
237
//					// add the point to the distance graph
238
//					this.dg.add(point);
239
//				}
240
//				
241
//				
242
//				// it is not necessary to update information yet
243
//				this.toPropagate = true;
244
//			}
245
//			break;
246
			
247
			// other	
248
			default: {
249
				throw new RuntimeException("[" + this.getClass().getName() + "]: Unknown notification received type= " + info.getType());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
250
			}
251
		}
252
	}
253
	
254
	/**
255
	 * 
256
	 * @return
257
	 */
258
	public DistanceGraph getDistanceGraph() {
259
		// get the distance graph
260
		return this.dg;
261
	}
262
	
263
	/**
264
	 * 
265
	 */
266
	@Override
267
	public String toString() {
268
		// check if to propagate
269
		if (this.toPropagate) {
270
			this.compute();
271
		}
272
		
273
		// print distance matrix 
274
		String matrix = "Distance matrix (Computed by Floyd-Warshall Algorithm)\n";
275
		if (this.toPropagate) {
276
			// not update distance information
277
			matrix += "Not Updated Distance Information";
278
		} else {
279
			for (TimePoint i : this.dg.getPoints()) {
280
				for (TimePoint j : this.dg.getPoints()) {
281
					matrix += "\t" + this.distance.get(i).get(j);
0 ignored issues
show
Performance introduced by
String concatenation with + is inefficient. Doing so in a loop may incur a significant performance penalty. Consider using a StringBuilder instead
Loading history...
282
				}
283
				matrix += "\n";
0 ignored issues
show
Performance introduced by
String concatenation with + is inefficient. Doing so in a loop may incur a significant performance penalty. Consider using a StringBuilder instead
Loading history...
284
			}
285
		}
286
		
287
		// get description of the distance matrix
288
		return matrix;
289
	}
290
	
291
	/**
292
	 * Returns the number of temporal propagation actually done
293
	 * Only for testing purposes
294
	 * 
295
	 * @return
296
	 */
297
	public int getPropagationCounter() {
298
		return propagationCounter;
299
	}
300
	
301
	/**
302
	 * 
303
	 */
304
	@Override
305
	public void process(TimePointQuery query) {
306
		
307
		// check query type 
308
		switch (query.getType()) {
309
		
310
			// handle time point bound query
311
			case TP_SCHEDULE : {
312
				
313
				// get query
314
				TimePointScheduleQuery tpBoundQuery = (TimePointScheduleQuery) query;
315
				// get time point
316
				TimePoint point = tpBoundQuery.getTimePoint();
317
				// get distance between the origin and the time point
318
				long[] distance = this.getDistance(this.tn.getOriginTimePoint(), point); 
0 ignored issues
show
Comprehensibility introduced by
The variable distanceshadows a field with the same name declared in line 25. Consider renaming it.
Loading history...
319
				// set information 
320
				point.setLowerBound(distance[0]);
321
				point.setUpperBound(distance[1]);
322
			}
323
			break;
324
			
325
			// handle time point distance query
326
			case TP_DISTANCE : {
327
				
328
				// get query
329
				TimePointDistanceQuery tpDistanceQuery = (TimePointDistanceQuery) query;
330
				// get source point 
331
				TimePoint source = tpDistanceQuery.getSource();
332
				// get target point 
333
				TimePoint target = tpDistanceQuery.getTarget();
334
				// get distance between points
335
				long[] distance = this.getDistance(source, target);
0 ignored issues
show
Comprehensibility introduced by
The variable distanceshadows a field with the same name declared in line 25. Consider renaming it.
Loading history...
336
				// set information
337
				tpDistanceQuery.setDistanceLowerBound(distance[0]);
338
				tpDistanceQuery.setDistanceUpperBound(distance[1]);
339
			}
340
			break;
341
			
342
			// handle time point distance from origin query
343
			case TP_DISTANCE_FROM_ORIGIN : {
344
				
345
				// get query
346
				TimePointDistanceFromOriginQuery tpDistanceQuery = (TimePointDistanceFromOriginQuery) query;
347
				// get time point
348
				TimePoint tp = tpDistanceQuery.getTimePoint();
349
				// get distance to horizon
350
				long[] distance = this.getDistance(this.tn.getOriginTimePoint(), tp);
0 ignored issues
show
Comprehensibility introduced by
The variable distanceshadows a field with the same name declared in line 25. Consider renaming it.
Loading history...
351
				// set information
352
				tpDistanceQuery.setDistance(distance);
353
			}
354
			break;
355
			
356
			// handle time point distance to horizon query
357
			case TP_DISTANCE_TO_HORIZON : {
358
				
359
				// get query 
360
				TimePointDistanceToHorizonQuery tpDistanceQuery = (TimePointDistanceToHorizonQuery) query;
361
				// get time point
362
				TimePoint tp = tpDistanceQuery.getTimePoint();
363
				// get distance to horizon
364
				long[] distance = this.getDistance(tp, this.tn.getHorizonTimePoint());
0 ignored issues
show
Comprehensibility introduced by
The variable distanceshadows a field with the same name declared in line 25. Consider renaming it.
Loading history...
365
				// set information
366
				tpDistanceQuery.setDistance(distance);
367
			}
368
			break;
369
			
370
			default : {
371
				
372
				// not a time point query
373
				throw new RuntimeException("Impossible to process this type of temporal query " + query.getType());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
374
			}
375
		}
376
	}
377
	
378
	/**
379
	 * Returns distance lower and upper bounds of Time Point 
380
	 * tp1 to Time Point tp2 
381
	 * 
382
	 * @param tp1
383
	 * @param tp2
384
	 * @return
385
	 */
386
	protected long[] getDistance(TimePoint tp1, TimePoint tp2) {
387
		
388
		// compute minimal minimal network if needed
389
		if (this.toPropagate) {
390
			// clean distance matrix's data
391
			this.compute();
392
		}
393
		
394
		// default distance bounds - total uncertainty
395
		long[] bounds = new long[] {
396
				0, 
397
				this.tn.getHorizon()
398
		};
399
		
400
		// check if both time points exists
401
		if (this.distance.containsKey(tp1) && this.distance.get(tp1).containsKey(tp2)) {
402
			// set bounds
403
			bounds = new long[] {
404
					-this.distance.get(tp2).get(tp1),		// lower bound
405
					this.distance.get(tp1).get(tp2)			// upper bound
406
				};
407
		}
408
		
409
		// get bounds
410
		return bounds;
411
	}
412
	
413
	/**
414
	 * 
415
	 */
416
	private void compute() {
417
		
418
		// check size of the distance graph
419
		this.distance = new HashMap<TimePoint, Map<TimePoint, Long>>();
420
		// initialize distances to infinity
421
		for (TimePoint i : this.dg.getPoints()) {
422
			
423
			this.distance.put(i, new HashMap<TimePoint, Long>());
424
			for (TimePoint j : this.dg.getPoints()) {
425
				
426
				// initialize
427
				if (i.equals(j)) {
428
					
429
					this.distance.get(i).put(j, 0l);
430
					
431
				} else {
432
					
433
					this.distance.get(i).put(j, this.dg.getInfity());
434
				}
435
			}
436
		}
437
		
438
		// initialize distances using the weights of the distance graph's edges
439
		for (TimePoint point : this.dg.getPoints()) {
440
			
441
			// get adjacent points
442
			for (TimePoint adj : this.dg.getAdjacents(point)) {
443
				// get distance
444
				long distance = this.dg.getDistance(point, adj);
0 ignored issues
show
Comprehensibility introduced by
The variable distanceshadows a field with the same name declared in line 25. Consider renaming it.
Loading history...
445
				// set distance
446
				this.distance.get(point).put(adj, distance);
447
			}
448
		}
449
		
450
		// compute minimum distances - k intermediate node
451
		for (TimePoint k : this.dg.getPoints()) {
452
			// compute shortest paths using intermediate points
453
			for (TimePoint i : this.dg.getPoints()) {
454
				for (TimePoint j : this.dg.getPoints()) {
455
					
456
					// compute the path from i to j through k
457
					long path = this.distance.get(i).get(k) + this.distance.get(k).get(j);
458
					// compare computed distance with the direct path
459
					if (this.distance.get(i).get(j) > path) {
460
						
461
						// update distance
462
						this.distance.get(i).put(j, path);
463
					}
464
				}
465
			}
466
		}
467
		
468
		// update propagation counter
469
		this.propagationCounter++;
470
		// set propagation flag
471
		this.toPropagate = false;
472
	}
473
	
474
	/**
475
	 * 
476
	 */
477
	@Override
478
	public void printDiagnosticData() {
479
		// compute if temporal data
480
		if (this.toPropagate) {
481
			this.compute();
482
		}
483
		
484
		System.out.println("Distance Graph:\n"
485
				+ "" + this.dg + "\n\n"
486
				+ "Distance matrix:\n"
487
				+ "" + this + "\n");
488
	}
489
}
490