Passed
Push — master ( ba4614...ebb470 )
by Alessandro
05:51
created

computeCriticalSetSolutions(OverlappingSet)   A

Complexity

Conditions 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 13
rs 10
c 0
b 0
f 0
eloc 7
1
package it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.timeline.scheduling;
2
3
import java.util.ArrayList;
4
import java.util.Collections;
5
import java.util.List;
6
7
import it.cnr.istc.pst.platinum.ai.framework.domain.component.Decision;
8
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.FlawSolutionApplicationException;
9
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.RelationPropagationException;
10
import it.cnr.istc.pst.platinum.ai.framework.domain.component.sv.StateVariable;
11
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.ex.ConsistencyCheckException;
12
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.Flaw;
13
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.FlawSolution;
14
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.RelationType;
15
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.relations.temporal.BeforeRelation;
16
import it.cnr.istc.pst.platinum.ai.framework.microkernel.query.TemporalQueryType;
17
import it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.Resolver;
18
import it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.ResolverType;
19
import it.cnr.istc.pst.platinum.ai.framework.microkernel.resolver.ex.UnsolvableFlawException;
20
import it.cnr.istc.pst.platinum.ai.framework.time.TemporalInterval;
21
import it.cnr.istc.pst.platinum.ai.framework.time.ex.TemporalConstraintPropagationException;
22
import it.cnr.istc.pst.platinum.ai.framework.time.lang.TemporalConstraintType;
23
import it.cnr.istc.pst.platinum.ai.framework.time.lang.allen.BeforeIntervalConstraint;
24
import it.cnr.istc.pst.platinum.ai.framework.time.lang.query.IntervalOverlapQuery;
25
import it.cnr.istc.pst.platinum.ai.framework.utils.properties.FilePropertyReader;
26
27
/**
28
 * 
29
 * @author alessandro
30
 *
31
 */
32
public final class TimelineSchedulingResolver extends Resolver<StateVariable>
33
{
34
	private boolean load;
35
	private double schedulingCost;
36
	
37
	/**
38
	 * 
39
	 */
40
	protected TimelineSchedulingResolver() {
41
		super(ResolverType.TIMELINE_SCHEDULING_RESOLVER.getLabel(), 
42
				ResolverType.TIMELINE_SCHEDULING_RESOLVER.getFlawTypes());
43
		// set load flag
44
		this.load = false;
45
	}
46
	
47
	/**
48
	 * 
49
	 */
50
	private void load() {
51
		// get deliberative property file
52
		FilePropertyReader properties = new FilePropertyReader(
53
				FRAMEWORK_HOME + FilePropertyReader.DEFAULT_DELIBERATIVE_PROPERTY);
54
		// get weight
55
		this.schedulingCost = Double.parseDouble(properties.getProperty("scheduling-cost"));
56
		// set flag
57
		this.load = true;
58
	}
59
	
60
	/**
61
	 * 
62
	 */
63
	@Override
64
	protected void doApply(FlawSolution solution) 
65
			throws FlawSolutionApplicationException {
66
		
67
		// get the flaw solution to consider
68
		OverlappingSetSchedule schedule = (OverlappingSetSchedule) solution;
69
		// list of committed relations
70
		List<BeforeRelation> committed = new ArrayList<>();
71
		
72
		try {
73
			
74
			// apply all precedence constraints
75
			for (PrecedenceConstraint pc : schedule.getConstraints()) {
76
			
77
				// get reference and target decisions
78
				Decision reference = pc.getReference();
79
				Decision target = pc.getTarget();
80
				
81
				// create relation
82
				BeforeRelation before = this.component.create(
83
						RelationType.BEFORE, 
84
						reference, 
85
						target);
86
				
87
				// set bounds
88
				before.setBound(new long[] {
89
						0, 
90
						this.component.getHorizon()});
91
				// add created relation to solution
92
				solution.addCreatedRelation(before);
93
			
94
				// add relation to committed
95
				committed.add(before);
96
				// propagate relations
97
				this.component.activate(before);
98
				// add activated relations to solution
99
				solution.addActivatedRelation(before);
100
				// check feasibility
101
				this.tdb.verify();
102
			}
103
			
104
		} catch (RelationPropagationException | ConsistencyCheckException ex) {
105
			
106
			// write error message
107
			error("Error while applying flaw solution:\n"
108
					+ "- solution: " + solution + "\n");
109
			
110
			// clear data structure by remove all committed relations
111
			for (BeforeRelation before : committed) {
112
				
113
				// deactivate relation
114
				this.component.deactivate(before);
115
				// delete relation
116
				this.component.delete(before);
117
			}
118
			
119
			// not feasible solution
120
			throw new FlawSolutionApplicationException(ex.getMessage());
121
		}
122
	}
123
	
124
	
125
//	protected void doApply(FlawSolution solution) 
126
//			throws FlawSolutionApplicationException 
127
//	{
128
//		// get the flaw solution to consider
129
//		DecisionPrecedenceConstraint pc = (DecisionPrecedenceConstraint) solution;
130
//		// get reference and target decisions
131
//		Decision reference = pc.getReference();
132
//		Decision target = pc.getTarget();
133
//		
134
//		// create relation
135
//		BeforeRelation before = this.component.create(RelationType.BEFORE, reference, target);
136
//		// set bounds
137
//		before.setBound(new long[] {
138
//				0, 
139
//				this.component.getHorizon()});
140
//		// add created relation to solution
141
//		solution.addCreatedRelation(before);
142
//		
143
//		try
144
//		{
145
//			// propagate relations
146
//			this.component.activate(before);
147
//			// add activated relations to solution
148
//			solution.addActivatedRelation(before);
149
//			debug("Precedence constraint successfully created and activated:\n"
150
//					+ "- temporal constraint: " + before + "\n");
151
//			
152
//			// check feasibility
153
//			this.tdb.verify();
154
//		}
155
//		catch (RelationPropagationException | ConsistencyCheckException ex) 
156
//		{
157
//			// write error message
158
//			error("Error while applying flaw solution:\n"
159
//					+ "- solution: " + solution + "\n"
160
//					+ "- unfeasible precedence constraint: " + before + "\n");
161
//
162
//			// deactivate relation
163
//			this.component.deactivate(before);
164
//			// delete relation
165
//			this.component.delete(before);
166
//			// not feasible solution
167
//			throw new FlawSolutionApplicationException(ex.getMessage());
168
//		}
169
//	}
170
	
171
	/**
172
	 * 
173
	 */
174
	@Override
175
	protected List<Flaw> doFindFlaws() {
176
		
177
		// check flag
178
		if (!this.load) {
179
			this.load();
180
		}
181
		
182
		// list of critical sets
183
		List<Flaw> CSs = new ArrayList<>();
184
		// list of active decisions
185
		List<Decision> decisions = this.component.getActiveDecisions();
186
		// sort decisions
187
		Collections.sort(decisions);
188
		
189
		// look for critical sets
190
		for (int index = 0; index < decisions.size() - 1; index++) {
191
			
192
			// get active decision  
193
			Decision activity = decisions.get(index);
194
			// prepare a critical set
195
			OverlappingSet cs = new OverlappingSet(
196
					FLAW_COUNTER.getAndIncrement(), 
197
					this.component);
198
			// add current activity
199
			cs.add(activity);
200
			
201
			// find possibly overlapping decisions
202
			for (int jndex = index + 1; jndex < decisions.size(); jndex++) {
203
				
204
				// get another activity of the component
205
				Decision other = decisions.get(jndex);
206
				
207
				// check overlapping condition with the critical set
208
				if (this.conflict(cs, other)) {
209
					
210
					// add the activity to the critical set
211
					cs.add(other);
212
				}
213
				
214
			}
215
			
216
			// check the size of the critical set
217
			if (cs.size() > 1) {
218
				
219
				// the critical set actually represents a flaw of the component
220
				CSs.add(cs);
221
			}
222
		}
223
		
224
		// get the list of critical sets found
225
		return CSs;
226
	}
227
	
228
	/**
229
	 * Check if an activity overlaps ALL the activities composing a Critical Set
230
	 * 
231
	 * @param cs
232
	 * @param activity
233
	 * @return
234
	 */
235
	private boolean conflict(OverlappingSet cs, Decision activity) {
236
		
237
		// conflicting flag
238
		boolean conflict = true;
239
		// get events of the critical set
240
		List<Decision> activities = cs.getDecisions();
241
		// check set of events
242
		for (int index = 0; index < activities.size() && conflict; index++) {
243
			
244
			// get an activity of the critical set
245
			Decision csActivity = activities.get(index);
246
			// check overlapping condition
247
			IntervalOverlapQuery query = this.tdb.createTemporalQuery(TemporalQueryType.INTERVAL_OVERLAP);
248
			// set intervals
249
			query.setReference(csActivity.getToken().getInterval());
250
			query.setTarget(activity.getToken().getInterval());
251
			// process query
252
			this.tdb.process(query);
253
			
254
			// check whether the (flexible) temporal interval can overlap or not
255
			conflict = query.canOverlap();
256
		}
257
		
258
		// get result
259
		return conflict;
260
	}
261
	
262
	
263
//	@Override
264
//	protected List<Flaw> doFindFlaws() {
265
//		
266
//		// check flag
267
//		if (!this.load) {
268
//			this.load();
269
//		}
270
//		
271
//		// list of critical sets
272
//		List<Flaw> flaws = new ArrayList<>();
273
//		// list of active decisions
274
//		List<Decision> decisions = this.component.getActiveDecisions();
275
//		// sort decisions
276
//		Collections.sort(decisions);
277
//		
278
//		
279
//		// look for peaks
280
//		for (int index = 0; index < decisions.size() - 1; index++) {
281
//			// get active decision  
282
//			Decision reference = decisions.get(index);
283
//			// find possibly overlapping decisions
284
//			for (int jndex = index + 1; jndex < decisions.size(); jndex++)
285
//			{
286
//				// get another active decision
287
//				Decision target = decisions.get(jndex);
288
//				// check if intervals can overlap
289
//				IntervalOverlapQuery query = this.tdb.createTemporalQuery(
290
//						TemporalQueryType.INTERVAL_OVERLAP);
291
//				
292
//				// set time points
293
//				query.setReference(reference.getToken().getInterval());
294
//				query.setTarget(target.getToken().getInterval());
295
//				// process query
296
//				this.tdb.process(query);
297
//				// check overlapping 
298
//				if (query.canOverlap())
299
//				{
300
//					// conflict found
301
//					BinaryDecisionConflict c = new BinaryDecisionConflict(
302
//							FLAW_COUNTER.getAndIncrement(), 
303
//							this.component);
304
//
305
//					// set overlapping decisions
306
//					c.setDecisions(new Decision[] {
307
//							reference,
308
//							target
309
//					});
310
//					
311
//					// check if decisions overlaps
312
//					debug("Overlapping tokens:\n"
313
//							+ "- component: " + this.component + "\n"
314
//							+ "- reference token: " + reference + "\n"
315
//							+ "- target token: " + target + "\n");
316
//					
317
//					// add conflict
318
//					flaws.add(c);
319
//					
320
//					
321
//				} else {
322
//					
323
//					// check if decisions overlaps
324
//					debug("NOT overlapping tokens:\n"
325
//							+ "- component: " + this.component + "\n"
326
//							+ "- reference token: " + reference + "\n"
327
//							+ "- target token: " + target + "\n");
328
//				}
329
//			}
330
//		}
331
//		
332
//		// get the list
333
//		return flaws;
334
//	}
335
	
336
	/**
337
	 * 
338
	 */
339
	@Override
340
	protected void doComputeFlawSolutions(Flaw flaw) 
341
			throws UnsolvableFlawException {
342
		
343
		// get the critical set
344
		OverlappingSet cs = (OverlappingSet) flaw;
345
		
346
		/*
347
		 * A state variable does not allow any pair of overlapping of its activities. 
348
		 * 
349
		 * Each total ordering of the activities that compose a critical set may represent a solution
350
		 * 
351
		 */
352
		
353
		// compute all possible solutions of the critical set
354
		this.computeCriticalSetSolutions(cs);
355
	}
356
	
357
	/**
358
	 * 
359
	 * @param cs
360
	 * @throws UnsolvableFlawException
361
	 */
362
	private void computeCriticalSetSolutions(OverlappingSet cs) 
363
			throws UnsolvableFlawException {
364
		
365
		// get the list of overlapping activities
366
		List<Decision> activities = new ArrayList<>(cs.getDecisions());
367
		// compute feasible schedules
368
		this.doFindFeasibleSchedule(new ArrayList<>(), activities, cs);
369
		// check if no feasible solution exists
370
		if (cs.getSolutions().isEmpty()) {
371
			
372
			// unsolvable flaw
373
			throw new UnsolvableFlawException("Unsolvable flaw found on componnet \"" + this.component + "\"\n"
374
					+ "- flaw: " + cs + "\n\n");
375
		}
376
	}
377
	
378
	/**
379
	 * A solution to a critical set on a State Variable is a total ordering of the activities of the critical set.
380
	 * 
381
	 *  This method computes all possible orderings of the activities that are part of a critical set (i.e., the
382
	 *  permutations). The permutations that represent valid temporal constraints are considered as valid 
383
	 *  solutions to the critical set
384
	 * 
385
	 * @param schedule
386
	 * @param cs
387
	 * @param flaw
388
	 */
389
	private void doFindFeasibleSchedule(List<Decision> schedule, List<Decision> cs, OverlappingSet flaw) {
390
		
391
		// check if a schedule is ready for temporal checking
392
		if (cs.isEmpty()) {
393
			
394
			// check schedule resource feasibility first and then temporal feasibility
395
			if (this.checkTemporalFeasibility(schedule)) {
396
				
397
				// create flaw solution
398
				OverlappingSetSchedule solution = new OverlappingSetSchedule(flaw, this.schedulingCost);
399
				// set resulting constraints
400
				for (int i= 0; i < schedule.size() - 1; i++) {
401
					
402
					// add precedence constraint
403
					solution.addConstraint(schedule.get(i), schedule.get(i + 1));
404
				}
405
				
406
				// add solution to the flaw
407
				flaw.addSolution(solution);
408
			}
409
			
410
		} else {
411
			
412
			// check possible schedules until no solution is found 
413
			for (int index = 0; index < cs.size(); index++) {
414
				
415
				// get an activity from the critical set
416
				Decision activity = cs.remove(index);
417
				// add the activity to the possible schedule
418
				schedule.add(activity);
419
				
420
				// recursively build the permutation
421
				this.doFindFeasibleSchedule(schedule, cs, flaw);
422
				
423
				// remove event from the permutation
424
				schedule.remove(activity);
425
				// restore data of the critical set
426
				cs.add(index, activity);
427
			}
428
		}
429
	}
430
	
431
	/**
432
	 * 
433
	 * @param schedule
434
	 * @return
435
	 */
436 View Code Duplication
	private boolean checkTemporalFeasibility(List<Decision> schedule) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
437
		
438
		// feasibility flag
439
		boolean feasible = true;
440
		// list of propagated constraints
441
		List<BeforeIntervalConstraint> committed = new ArrayList<>();
442
		
443
		// check pairs of events 
444
		for (int index = 0; index < schedule.size() - 1 && feasible; index++) {
445
			
446
			try {
447
				
448
				// get activities
449
				Decision a1 = schedule.get(index);
450
				Decision a2 = schedule.get(index + 1);
451
				
452
				// get associated tokens and temporal intervals to check schedule feasibility
453
				TemporalInterval i1 = a1.getToken().getInterval();
454
				TemporalInterval i2 = a2.getToken().getInterval();
455
				
456
				// create precedence constraint "i1 < i2"
457
				BeforeIntervalConstraint before = this.tdb.createTemporalConstraint(
458
						TemporalConstraintType.BEFORE);
459
				
460
				// set constraint data
461
				before.setReference(i1);
462
				before.setTarget(i2);
463
				before.setLowerBound(0);
464
				before.setUpperBound(this.tdb.getHorizon());
465
				
466
				// add constraints to committed
467
				committed.add(before);
468
				// propagate constraint
469
				this.tdb.propagate(before);
470
				// check temporal feasibility
471
				this.tdb.verify();
472
				
473
			} catch (TemporalConstraintPropagationException | ConsistencyCheckException ex) {
474
				
475
				// not feasible schedule
476
				feasible = false;
477
				// log data
478
				debug("Component [" + this.label + "] temporally unfeasible schedule:\n"
479
						+ "- potential schedule critical set: " + schedule + "\n");
480
				
481
			} finally  {
482
				
483
				// retract all committed constraints
484
				for (BeforeIntervalConstraint before : committed) {
485
					// retract temporal constraint
486
					this.tdb.retract(before);
487
				}
488
			}
489
		}
490
		
491
		// get feasibility flag
492
		return feasible;
493
		
494
	}
495
	
496
//	@Override
497
//	protected void doComputeFlawSolutions(Flaw flaw) 
498
//		throws UnsolvableFlawException 
499
//	{
500
//		// get detected conflict
501
//		BinaryDecisionConflict conflict = (BinaryDecisionConflict) flaw;
502
//
503
//		// check possible precedence constraints
504
//		Decision reference = conflict.getDecisions()[0];
505
//		Decision target = conflict.getDecisions()[1];
506
//		// create possible solutions
507
//		DecisionPrecedenceConstraint pc1 = new DecisionPrecedenceConstraint(conflict, reference, target, this.schedulingCost);
508
//		DecisionPrecedenceConstraint pc2 = new DecisionPrecedenceConstraint(conflict, target, reference, this.schedulingCost);
509
//		
510
//		// temporal constraints
511
//		BeforeIntervalConstraint before1 = null;
512
//		BeforeIntervalConstraint before2 = null;
513
//		
514
//		try {
515
//
516
//			// create temporal constraint
517
//			before1 = this.tdb.createTemporalConstraint(TemporalConstraintType.BEFORE);
518
//			before1.setLowerBound(0);
519
//			before1.setUpperBound(this.component.getHorizon());
520
//			before1.setReference(reference.getToken().getInterval());
521
//			before1.setTarget(target.getToken().getInterval());
522
//			
523
//			// propagate interval constraint
524
//			this.tdb.propagate(before1);
525
//			// check consistency
526
//			this.tdb.verify();
527
//			
528
//			// add solution and deactivate relation
529
//			conflict.addSolution(pc1);
530
//		}
531
//		catch (TemporalConstraintPropagationException | ConsistencyCheckException ex) {
532
//			// discard relation
533
//			debug("Unfeasible precedence constraint:\n"
534
//					+ "\t- reference: " + reference + "\n"
535
//					+ "\t- target: " + target + "\n");
536
//		}
537
//		finally {
538
//			
539
//			// remove constraint
540
//			if (before1 != null) {
541
//				// retract constraint
542
//				this.tdb.retract(before1);
543
//				// clear constraint
544
//				before1.clear();
545
//			}
546
//		}
547
//		
548
//		
549
//		try {
550
//			
551
//			// create temporal constraint
552
//			before2 = this.tdb.createTemporalConstraint(TemporalConstraintType.BEFORE);
553
//			before2.setLowerBound(0);
554
//			before2.setUpperBound(this.component.getHorizon());
555
//			before2.setReference(target.getToken().getInterval());
556
//			before2.setTarget(reference.getToken().getInterval());
557
//			
558
//			// propagate interval constraint
559
//			this.tdb.propagate(before2);
560
//			// check consistency
561
//			this.tdb.verify();
562
//			
563
//			// add solution and deactivate relation
564
//			conflict.addSolution(pc2);
565
//		}
566
//		catch (TemporalConstraintPropagationException | ConsistencyCheckException ex) {
567
//			// discard relation
568
//			debug("Unfeasible precedence constraint:\n"
569
//					+ "\t- reference: " + target + "\n"
570
//					+ "\t- target: " + reference + "\n");
571
//		}
572
//		finally {
573
//			
574
//			// remove constraint
575
//			if (before2 != null) {
576
//				// retract constraint
577
//				this.tdb.retract(before2);
578
//				// clear constraint
579
//				before2.clear();
580
//			}
581
//		}
582
//		
583
//		
584
//		// check if any solution has been found
585
//		if (conflict.getSolutions().isEmpty()) {
586
//			throw new UnsolvableFlawException("Unsolvable decision conflict on timeline:\n"
587
//					+ "\t- component: " + this.component.getName() + "\n"
588
//					+ "\t- decisions: " + conflict.getDecisions()[0] + ", " + conflict.getDecisions()[1] + "\n");
589
//		}
590
//	}
591
}
592
593