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

getConstraints(TimePoint,TimePoint)   A

Complexity

Conditions 5

Size

Total Lines 26
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
dl 0
loc 26
rs 9.3333
c 0
b 0
f 0
1
package it.cnr.istc.pst.platinum.ai.framework.time.tn;
2
3
import java.util.ArrayList;
4
import java.util.HashMap;
5
import java.util.HashSet;
6
import java.util.List;
7
import java.util.Map;
8
import java.util.Set;
9
10
import it.cnr.istc.pst.platinum.ai.framework.time.tn.ex.InconsistentDistanceConstraintException;
11
import it.cnr.istc.pst.platinum.ai.framework.time.tn.ex.IntervalDisjunctionException;
12
import it.cnr.istc.pst.platinum.ai.framework.time.tn.ex.NotCompatibleConstraintsFoundException;
13
import it.cnr.istc.pst.platinum.ai.framework.time.tn.ex.TimePointNotFoundException;
14
15
/**
16
 * 
17
 * @author alessandro
18
 *
19
 */
20
public final class SimpleTemporalNetworkWithUncertainty extends TemporalNetwork 
21
{
22
	private Map<Integer, TimePoint> points;
23
	// set of all constraints added to the network
24
	private Map<TimePoint, Map<TimePoint, Set<TimePointDistanceConstraint>>> requirements;
25
	// contingent links
26
	private Map<TimePoint, Map<TimePoint, TimePointDistanceConstraint>> contingents;
27
	
28
	/**
29
	 * 
30
	 * @param origin
31
	 * @param horizon
32
	 */
33
	public SimpleTemporalNetworkWithUncertainty(long origin, long horizon) {
34
		super(origin, horizon);
35
		
36
		// initialize data structures
37
		this.points = new HashMap<>();
38
		this.requirements = new HashMap<>();
39
		this.contingents = new HashMap<>();
40
			
41
		// add the origin to the network
42
		this.points.put(this.tpOrigin.getId(), this.tpOrigin);
43
		this.contingents.put(this.tpOrigin, new HashMap<TimePoint, TimePointDistanceConstraint>());
44
		this.requirements.put(this.tpOrigin, new HashMap<TimePoint, Set<TimePointDistanceConstraint>>());
45
		
46
		// add the horizon to the network
47
		this.points.put(this.tpHorizion.getId(), this.tpHorizion);
48
		this.contingents.put(this.tpHorizion, new HashMap<TimePoint, TimePointDistanceConstraint>());
49
		this.requirements.put(this.tpHorizion, new HashMap<TimePoint, Set<TimePointDistanceConstraint>>());
50
		
51
		try {
52
			
53
			// create constraint
54
			TimePointDistanceConstraint oh = this.createDistanceConstraint(
55
					this.tpOrigin, 
56
					this.tpHorizion, 
57
					new long[] {horizon,  horizon}, 
58
					true);
59
			
60
			// add constraint
61
			this.doAddConstraint(oh);
62
		} 
63
		catch (InconsistentDistanceConstraintException ex) {
64
			throw new RuntimeException(ex.getMessage());
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
65
		}
66
	}
67
68
	/**
69
	 * 
70
	 */
71
	@Override
72
	public int size() {
73
		return this.points.size(); 
74
	}
75
76
	/**
77
	 * 
78
	 */
79
	@Override
80
	public TimePoint getTimePoint(int id) 
81
			throws TimePointNotFoundException {
82
		
83
		// check network 
84
		if (!this.points.containsKey(id)) {
85
			throw new TimePointNotFoundException("The network does not contain any time point with id= " + id);
86
		}
87
		
88
		// get time point
89
		return this.points.get(id);
90
	}
91
92
	/**
93
	 * 
94
	 */
95
	@Override
96
	public List<TimePoint> getTimePoints() {
97
		// get all time points
98
		return new ArrayList<>(this.points.values());
99
	}
100
101
	/**
102
	 * Get the list of all constraints concerning the time point.
103
	 * 
104
	 * The method returns the list of all requirement and contingent constraints starting from the time point.
105
	 */
106
	@Override
107
	public List<TimePointDistanceConstraint> getConstraints(TimePoint point) {
108
109
		// set of constraints
110
		Set<TimePointDistanceConstraint> set = new HashSet<>();
111
		// check requirement constraints
112
		if (this.requirements.containsKey(point)) {
113
			// get all requirement constraints
114
			for (Set<TimePointDistanceConstraint> outs : this.requirements.get(point).values()) {
115
				// add constraints
116
				set.addAll(outs);
117
			}
118
		}
119
		
120
		// check contingent constraints
121
		if (this.contingents.containsKey(point)) {
122
			// get all contingent constraints
123
			for (TimePointDistanceConstraint contingent : this.contingents.get(point).values()) {
124
				// add constraints
125
				set.add(contingent);
126
			}
127
		}
128
		
129
		// get the list of outgoing constraints
130
		return new ArrayList<>(set); 
131
	}
132
133
	/**
134
	 * Get the list of all constraints concerning the two time points.
135
	 * 
136
	 * The method returns the list of all requirement or contingent 
137
	 * constraints concerning between the time points. Indeed only one 
138
	 * type of constraint is allowed between two time points. Namely two 
139
	 * time points are connected by a requirement constraint or a contingent
140
	 * constraint
141
	 */
142
	@Override
143
	public List<TimePointDistanceConstraint> getConstraints(TimePoint tp1, TimePoint tp2) {
144
		
145
		// list of constraints between the two time points
146
		Set<TimePointDistanceConstraint> set = new HashSet<>();
147
		
148
		// check contingent constraints
149
		if (this.contingents.containsKey(tp1) && this.contingents.get(tp1).containsKey(tp2)) {
150
			
151
			// add requirement constraint
152
			set.add(this.contingents.get(tp1).get(tp2));
153
				
154
		}
155
		else if (this.requirements.containsKey(tp1) && this.requirements.get(tp1).containsKey(tp2)) {
156
			
157
			// add requirement constraint
158
			set.addAll(this.requirements.get(tp1).get(tp2));
159
			
160
		} else {
161
			
162
			// no constraint between time points
163
		}
164
		
165
		
166
		// get the list
167
		return new ArrayList<>(set);
168
	}
169
170
	/**
171
	 * Return the constraint between the origin and the time point.
172
	 * 
173
	 * Note that only requirement constraints can be specified between the origin
174
	 * and a time point.
175
	 */
176 View Code Duplication
	@Override
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
177
	public List<TimePointDistanceConstraint> getConstraintFromOrigin(TimePoint point) {
178
		
179
		// prepare list of constraints
180
		Set<TimePointDistanceConstraint> set = new HashSet<>();
181
		// check contingencies
182
		if (this.contingents.containsKey(this.tpOrigin) && this.contingents.get(this.tpOrigin).containsKey(point)) {
183
			
184
			// add contingent constraint
185
			set.add(this.contingents.get(this.tpOrigin).get(point));
186
			
187
		} else if (this.requirements.containsKey(this.tpOrigin) && this.requirements.get(this.tpOrigin).containsKey(point)) {
188
			
189
			// add all requirement constraints
190
			set.addAll(this.requirements.get(this.tpOrigin).get(point));
191
			
192
		} else {
193
			
194
			// no constraints
195
		}
196
		
197
		// get list of constraints
198
		return new ArrayList<>(set);
199
	}
200
	
201
	/**
202
	 * 
203
	 */
204 View Code Duplication
	@Override
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
205
	public List<TimePointDistanceConstraint> getConstraintToHorizon(TimePoint point) {
206
		
207
		// prepare list of constraints
208
		Set<TimePointDistanceConstraint> set = new HashSet<>();
209
		// check contingencies
210
		if (this.contingents.containsKey(point) && this.contingents.get(point).containsKey(this.tpHorizion)) {
211
			
212
			// add contingent constraint
213
			set.add(this.contingents.get(point).get(this.tpHorizion));
214
			
215
		} else if (this.requirements.containsKey(point) && this.requirements.get(point).containsKey(this.tpHorizion)) {
216
			
217
			// add all requirement constraints
218
			set.addAll(this.requirements.get(point).get(this.tpHorizion));
219
			
220
		} else {
221
			
222
			// no constraints
223
		}
224
		
225
		// get list of constraints
226
		return new ArrayList<>(set);
227
	}
228
	
229
	/**
230
	 * 
231
	 * @return
232
	 */
233
	public List<TimePointDistanceConstraint> getContingentConstraints() {
234
		// set of constraints
235
		Set<TimePointDistanceConstraint> set = new HashSet<>();
236
		for (TimePoint point : this.points.values()) {
237
			// add contingent constraints if any
238
			if (this.contingents.containsKey(point)) {
239
				// add all (outgoing) contingent constraints
240
				set.addAll(this.contingents.get(point).values());
241
			}
242
		}
243
		
244
		// get the list
245
		return new ArrayList<>(set);
246
	}
247
248
	
249
	/**
250
	 * 
251
	 */
252
	@Override
253
	public String toString() {
254
		String str = "{\n"
255
				+ "\ttype: \"stnu\",\n"
256
				+ "\tnetwork: [\n";
257
		
258
		// print data about points and links
259
		for (TimePoint tp : this.points.values()) {
260
			// print data about current time point
261
			str += "\t\t{\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...
262
					+ "\t\t\tpoint: " + tp.getId() + ",\n";
263
			if (this.requirements.containsKey(tp)) {
264
				str += "\t\t\trequirements: [\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...
265
				for (Set<TimePointDistanceConstraint> rels : this.requirements.get(tp).values()) {
266
					for (TimePointDistanceConstraint rel : rels) {
267
						str += "\t\t\t\t{ point: " + rel.getTarget().getId() + ", lb: " + rel.getDistanceLowerBound() + ", ub: " + rel.getDistanceUpperBound() + "}\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...
268
					}
269
				}	
270
			}
271
			
272
			str += "\t\t\t],\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...
273
			str += "\t\t\tcontingencies: [\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...
274
			if (this.contingents.containsKey(tp)) {
275
				for (TimePointDistanceConstraint rel : this.contingents.get(tp).values()) {
276
						str += "\t\t\t\t{ point: " + rel.getTarget().getId()+ ", lb: " + rel.getDistanceLowerBound() + ", ub: " + rel.getDistanceUpperBound() +"}, \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...
277
				}	
278
			}
279
			
280
			str += "\t\t\t]\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...
281
					+ "\t\t},\n";
282
		}
283
		
284
		// close network description
285
		str += "\t]\n"
286
				+ "}\n";
287
		// print network 
288
		return str;
289
	}
290
291
	/**
292
	 */
293
	@Override
294
	protected void doAddTimePoint(TimePoint tp) 
295
			throws InconsistentDistanceConstraintException {
296
		
297
		// add the point to the network
298
		this.points.put(tp.getId(), tp);
299
		// create constraint from the origin
300
		TimePointDistanceConstraint c0p = this.createDistanceConstraint(
301
				this.tpOrigin, 
302
				tp, 
303
				new long[] {
304
					tp.getDomLb(), 
305
					tp.getDomUb()
306
				}, 
307
				true);
308
		
309
		// add distance constraint
310
		this.doAddConstraint(c0p);
311
		
312
		// create constraint to horizon
313
		TimePointDistanceConstraint cpH = this.createDistanceConstraint(
314
				tp, 
315
				this.tpHorizion, 
316
				new long[] {
317
					this.horizon - tp.getDomUb(),
318
					this.horizon - tp.getDomLb()
319
				}, 
320
				true);
321
		
322
		// add distance constraint
323
		this.doAddConstraint(cpH);		
324
	}
325
326
	/**
327
	 * 
328
	 */
329
	@Override
330
	protected List<TimePointDistanceConstraint> doRemoveTimePoint(TimePoint point) 
331
	{
332
		// list of removed constraints
333
		Set<TimePointDistanceConstraint> removed = new HashSet<>();
334
		
335
		// check time point constraints
336
		if (this.requirements.containsKey(point)) {
337
			
338
			// get related network
339
			Map<TimePoint, Set<TimePointDistanceConstraint>> net = this.requirements.get(point);
340
			// add constraints to remove
341
			for (Set<TimePointDistanceConstraint> set : net.values()) {
342
				// add constraints
343
				removed.addAll(set);
344
			}
345
			
346
			// remove entry from the network
347
			this.requirements.remove(point);
348
			
349
			// check other associated constraints
350
			for (TimePoint other : this.requirements.keySet()) {
0 ignored issues
show
Performance introduced by
When you need both the keys and the value of a Map, iterating over entrySet() instead of keySet() is more readable.
Loading history...
351
				// check constraints to the point
352
				if (this.requirements.get(other).containsKey(point)) {
353
					
354
					// get constraints
355
					removed.addAll(this.requirements.get(other).get(point));
356
					// remove data
357
					this.requirements.get(other).remove(point);
358
				}
359
			}
360
		}
361
		
362
		// check contingent constraints
363
		if (this.contingents.containsKey(point)) {
364
			
365
			// get constraints
366
			removed.addAll(this.contingents.get(point).values());
367
			// clear data 
368
			this.contingents.remove(point);
369
			
370
			// check other constraints
371
			for (TimePoint other : this.contingents.keySet()) {
0 ignored issues
show
Performance introduced by
When you need both the keys and the value of a Map, iterating over entrySet() instead of keySet() is more readable.
Loading history...
372
				// check constraints to the point
373
				if (this.contingents.get(other).containsKey(point)) {
374
					
375
					// get constraint
376
					removed.add(this.contingents.get(other).get(point));
377
					// remove data
378
					this.contingents.get(other).remove(point);
379
					
380
				}
381
			}
382
			
383
		}
384
		
385
		// finally remove point
386
		this.points.remove(point.getId());
387
		// get the list
388
		return new ArrayList<>(removed);
389
	}
390
391
	/**
392
	 * The STNU can handle only one contingent constraint for each  pair of time points.
393
	 * 
394
	 * The method throws an exception when trying to override an existing contingent 
395
	 * constraint either by adding a contingent or a requirement constraint. 
396
	 */
397
	@Override
398
	protected boolean doAddConstraint(TimePointDistanceConstraint constraint) 
399
			throws InconsistentDistanceConstraintException 
400
	{
401
		// change flag
402
		boolean change = false;
403
		// get reference and target time points
404
		TimePoint reference = constraint.getReference();
405
		TimePoint target = constraint.getTarget();
406
		
407
		// check if related time points exits
408
		if (!this.points.containsKey(reference.getId()) || !this.points.containsKey(target.getId())) {
409
			// unknown time points
410
			throw new InconsistentDistanceConstraintException("Unknown time points:\n"
411
					+ "- reference= " + reference + "\n"
412
					+ "- target= " + target + "\n");
413
		}
414
		
415
		// check controllability of the constraint to add
416
		if (constraint.isControllable())
417
		{
418
			// check if the definition of a contingent constraint between the two time points
419
			if (this.contingents.containsKey(reference) && this.contingents.get(reference).containsKey(target)) {
420
				// a contingent link exists
421
				throw new NotCompatibleConstraintsFoundException("A contingent constraint already exist between time points:\n"
422
						+ "- reference time point= " + reference + "\n"
423
						+ "- target time point= " + target + "\n"
424
						+ "- constraint= " + constraint + "\n"
425
						+ "- contingent constraint= " + this.contingents.get(reference).get(target) + "\n");
426
			}
427
			
428
			// get current constraint bounds
429
			long[] bounds = this.getConstraintBounds(reference, target);
430
			// check the feasibility of the current constraint
431
			if (bounds != null && (constraint.getDistanceLowerBound() > bounds[1] || constraint.getDistanceUpperBound() < bounds[0])) {
432
				// not feasible constraint
433
				throw new IntervalDisjunctionException("Disjunctive interval bounds are not allowed\n"
434
						+ "- current bound intersection= [" + bounds[0] + ", " + bounds[1] + "]\n"
435
						+ "- constraint bounds= [" + constraint.getDistanceLowerBound() + ", " + constraint.getDistanceUpperBound() + "]\n"
436
						+ "- constraint= " + constraint + "\n");
437
			}
438
			
439
			
440
			// check structures
441
			if (!this.requirements.containsKey(reference)) {
442
				this.requirements.put(reference, new HashMap<>());
443
			}
444
			
445
			if (!this.requirements.get(reference).containsKey(target)) {
446
				this.requirements.get(reference).put(target, new HashSet<>());
447
			}
448
			
449
			// the requirement constraint can be safely added to the network
450
			this.requirements.get(reference).get(target).add(constraint);
451
			// check if the new constraint entail a change in the distance bound between the time points
452
			change = bounds == null || constraint.getDistanceLowerBound() > bounds[0] || 
453
					constraint.getDistanceUpperBound() < bounds[1];
454
			
455
		} else {
456
			
457
			// check if a contingent constraint already exists
458
			if (this.contingents.containsKey(reference) && this.contingents.get(reference).containsKey(target)) {
459
				// contingent constraint cannot be overwritten
460
				throw new NotCompatibleConstraintsFoundException("Contingent constraints cannot be overwritten:\n"
461
						+ "- reference time point= " + reference + "\n"
462
						+ "- target time point= " + target + "\n"
463
						+ "- existing contingent constraint= " + this.contingents.get(reference).get(target) + "\n"
464
						+ "- invalid constraint= " + constraint + "\n");
465
			}
466
			
467
			// check structures
468
			if (!this.contingents.containsKey(reference)) {
469
				this.contingents.put(reference, new HashMap<>());
470
			}
471
			
472
			// add contingent constraint
473
			this.contingents.get(reference).put(target, constraint);
474
			// set change flag
475
			change = true;
476
		}
477
		
478
		// get flag
479
		return change;
480
	}
481
482
	/**
483
	 * 
484
	 */
485
	@Override
486
	protected boolean doRemoveDistanceConstraint(TimePointDistanceConstraint c) {
487
		
488
		// change flag
489
		boolean change = false;
490
		// get time points involved
491
		TimePoint reference = c.getReference();
492
		TimePoint target = c.getTarget();
493
		
494
		// check if requirement constraint
495
		if (c.isControllable()) {
496
			
497
			// remove requirement constraint
498
			if (this.requirements.containsKey(reference) && this.requirements.get(reference).containsKey(target)) {
499
				
500
				// check intersection constraint 
501
				long[] bound1 = this.getConstraintBounds(reference, target);
502
				// remove requirement constraint
503
				this.requirements.get(reference).get(target).remove(c);
504
				// check again intersection constraint 
505
				long[] bound2 = this.getConstraintBounds(reference, target);
506
				
507
				// set change flag
508
				change = bound2 == null || bound1[0] != bound2[0] || bound1[1] != bound2[1];
0 ignored issues
show
Security Bug introduced by
A "NullPointerException" could be thrown; "bound1" is nullable here.
Loading history...
509
				
510
				// clear data structure if necessary
511
				if (this.requirements.get(reference).get(target).isEmpty()) {
512
					// remove entry 
513
					this.requirements.get(reference).remove(target);
514
				}
515
			}
516
			
517
		} else {
518
			
519
			// remove contingent constraint
520
			if (this.contingents.containsKey(reference) && this.contingents.get(reference).containsKey(target)) {
521
			
522
				// remove contingent constraint
523
				this.contingents.get(reference).remove(target);
524
				// set change flag
525
				change = true;
526
			}
527
		}
528
529
		// get change flag
530
		return change;
531
	}
532
533
	/**
534
	 * 
535
	 */
536
	@Override
537
	public long[] getConstraintBounds(TimePoint reference, TimePoint target) {
538
		
539
		// set default bounds
540
		long[] bounds = new long[] {
541
				0,
542
				this.horizon
543
		};
544
		
545
		// check constraints between time points
546
		if (this.contingents.containsKey(reference) && this.contingents.get(reference).containsKey(target)) {
547
			
548
			// get constraint
549
			TimePointDistanceConstraint constraint = this.contingents.get(reference).get(target);
550
			// get bounds
551
			bounds[0] = constraint.getDistanceLowerBound();
552
			bounds[1] = constraint.getDistanceUpperBound();
553
			
554
		} else if (this.requirements.containsKey(reference) && this.requirements.get(reference).containsKey(target)) {
555
			
556
			// compute bound intersections
557
			for (TimePointDistanceConstraint constraint : this.requirements.get(reference).get(target)) {
558
				
559
				// update intersection
560
				bounds[0] = Math.max(bounds[0], constraint.getDistanceLowerBound());
561
				bounds[1] = Math.min(bounds[1], constraint.getDistanceUpperBound());
562
			}
563
			
564
		} else {
565
			
566
			// no constraint, no bound can be computed
567
			bounds = null;
568
		}
569
		
570
		// get bounds
571
		return bounds;
572
	}
573
	
574
	/**
575
	 * 
576
	 */
577
	@Override
578
	public void printDiagnosticData() {
579
		// print temporal network
580
		System.out.println("Temporal Network:\n"
581
				+ this + "\n");
582
	}
583
	
584
}
585