Passed
Push — master ( bc2940...3ad1e4 )
by Alessandro
06:51
created

setPartialPlan(Plan)   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
dl 0
loc 2
rs 10
1
package it.cnr.istc.pst.platinum.ai.deliberative.solver;
2
3
import java.util.ArrayList;
4
import java.util.Collections;
5
import java.util.HashMap;
6
import java.util.HashSet;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.Set;
10
import java.util.concurrent.atomic.AtomicInteger;
11
12
import it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponent;
13
import it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponentType;
14
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.Flaw;
15
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.flaw.FlawType;
16
import it.cnr.istc.pst.platinum.ai.framework.microkernel.lang.plan.Plan;
17
18
/**
19
 * 
20
 * @author alessandro
21
 *
22
 */
23
public class SearchSpaceNode implements Comparable<SearchSpaceNode> {
24
	
25
	private static final AtomicInteger ID_COUNTER = new AtomicInteger(0);
26
	
27
	private int id;												// node unique ID
28
	private List<Operator> operators;							// node generation trace
29
	
30
	private Plan plan;											// associated (partial) plan
31
	
32
//	private Map<DomainComponent, List<DecisionVariable>> plan;	// partial plan
33
// 	private Map<DomainComponent, List<Flaw>> agenda; 			// flaws associated to the resulting partial plan
34
// 	
35
// 	// consolidated information about a partial plan 
36
// 	private Map<DomainComponent, Double[]> makespan;			// consolidated makespan of SVs
37
 	private Map<DomainComponent, Double> cost;					// consolidated planning cost of SVs
38
 	
39
 	// heuristic information about a partial plan 
40
 	private Map<DomainComponent, Double[]> heuristicMakespan;		// estimated makespan of SVs
41
 	private Map<DomainComponent, Double[]> heuristicCost;			// estimated planning cost of SVs
42
 	
43
	private Object domainSpecificMetric;						// node domain specific metric
44
	
45
	/**
46
	 * 
47
	 */
48
	protected SearchSpaceNode() 
49
	{
50
		// set node's id
51
		this.id = ID_COUNTER.getAndIncrement();
52
		// set operators
53
		this.operators = new ArrayList<>();
54
		
55
		// initialize (partial) plan
56
//		this.plan = new Plan();
57
		
58
		// set agenda
59
//		this.agenda = new HashMap<>();
60
		// set additional metric
61
		this.domainSpecificMetric = null;
62
//		this.makespan = new HashMap<>();
63
		this.cost = new HashMap<>();
64
		this.heuristicMakespan = new HashMap<>();
65
		this.heuristicCost = new HashMap<>();
66
	}
67
	
68
	/**
69
	 * Create a child node generated by means of the specified operator
70
	 * 
71
	 * @param parent
72
	 * @param op
73
	 */
74
	protected SearchSpaceNode(SearchSpaceNode parent, Operator op) 
75
	{
76
		this();
77
		// set operators
78
		this.operators = new ArrayList<>(parent.getOperators());
79
		// add generator
80
		this.operators.add(op);
81
		
82
		// set (partial) plan
83
		this.plan = parent.getPlan();
84
		
85
		// set agenda
86
//		this.agenda = new HashMap<>();
87
		
88
		// set additional metric
89
		this.domainSpecificMetric = null;
90
		
91
		// set cost
92
		this.cost = new HashMap<>(parent.getCost());
93
		// update cost according to the operator
94
		if (!this.cost.containsKey(op.getFlaw().getComponent())) {
95
			// set cost
96
			this.cost.put(op.getFlaw().getComponent(), op.getCost());
97
		}
98
		else {
99
			// update cost
100
			this.cost.put(op.getFlaw().getComponent(),
101
					this.cost.get(op.getFlaw().getComponent()) + op.getCost());
102
		}
103
		
104
		
105
		// set makespan 
106
//		this.makespan = new HashMap<>();
107
		this.heuristicCost = new HashMap<>();
108
		this.heuristicMakespan = new HashMap<>();
109
	}
110
	
111
	
112
	/**
113
	 * 
114
	 * @return
115
	 */
116
	public int getId() {
117
		return id;
118
	}
119
	
120
	/**
121
	 * 
122
	 * @return
123
	 */
124
	public Plan getPlan() {
125
		return new Plan(this.plan);
126
	}
127
	
128
	/**
129
	 * 
130
	 * @param metric
131
	 */
132
	public void setDomainSpecificMetric(Object metric) {
133
		this.domainSpecificMetric = metric;
134
	}
135
	
136
	/**
137
	 * 
138
	 * @return
139
	 */
140
	public Object getDomainSpecificMetric() {
141
		return domainSpecificMetric;
142
	}
143
	
144
	/**
145
	 * 
146
	 * @param flaw
147
	 */
148
	public void addFlaw(Flaw flaw) {
149
		// add the flaw to the underlying plan description
150
		this.plan.add(flaw.getComponent(), flaw);
151
//		if (!this.agenda.containsKey(flaw.getComponent())) {
152
//			this.agenda.put(flaw.getComponent(), new ArrayList<>());
153
//		}
154
//		
155
//		// add the flaw
156
//		this.agenda.get(flaw.getComponent()).add(flaw);
157
	}
158
	
159
	/**
160
	 * 
161
	 * @return
162
	 */
163
	public Set<Flaw> getFlaws() {
164
		// get flaws from the underlying plan description
165
		return new HashSet<>(this.plan.getFlaws());
166
		
167
//		Set<Flaw> list = new HashSet<>();
168
//		for (DomainComponent comp : this.agenda.keySet()) {
169
//			list.addAll(this.agenda.get(comp));
170
//		}
171
//		
172
//		return list;
173
	}
174
	
175
	/**
176
	 * 
177
	 * @return
178
	 */
179
	public Set<Flaw> getFlaws(FlawType type) {
180
		Set<Flaw> list = new HashSet<>();
181
//		for (DomainComponent comp : this.agenda.keySet()) {
182
		for (Flaw flaw : this.plan.getFlaws()) {
183
			// check flaw type
184
			if (flaw.getType().equals(type)) {
185
				// add the flaw
186
				list.add(flaw);
187
			}
188
		}
189
//		}
190
		
191
		return list;
192
	}
193
	
194
	/**
195
	 * 
196
	 * @return
197
	 */
198
	public int getNumberOfFlaws() {
199
//		int number = 0;
200
//		for (List<Flaw> list : this.agenda.values()) {
201
//			number += list.size();
202
//		}
203
		return this.getFlaws().size();
204
	}
205
	
206
	
207
	/**
208
	 * 
209
	 * @param comp
210
	 * @return
211
	 */
212
	public Set<Flaw> getFlaws(DomainComponent comp) {
213
		return new HashSet<>(this.plan.getFlaws(comp));
214
	}
215
	
216
	/**
217
	 * 
218
	 * @return
219
	 */
220
	public int getDepth() {
221
		return this.operators.size();
222
	}
223
		
224
	/**
225
	 * 
226
	 * @return
227
	 */
228
	public Map<DomainComponent, Double[]> getHeuristicCost() {
229
		return new HashMap<>(this.heuristicCost);
230
	}
231
	
232
	/**
233
	 * 
234
	 * @param hCost
235
	 */
236
	public void setHeuristicCost(Map<DomainComponent, Double[]> hCost) {
237
		this.heuristicCost = hCost;
238
	}
239
	
240
	/**
241
	 * 
242
	 * @return
243
	 */
244
	public Map<DomainComponent, Double[]> getHeuristicMakespan() {
245
		return new HashMap<>(this.heuristicMakespan);
246
	}
247
	
248
	/**
249
	 * 
250
	 * @param makespanHeuristic
251
	 */
252
	public void setHeuristicMakespan(Map<DomainComponent, Double[]> hMakespan) {
253
		this.heuristicMakespan = hMakespan;
254
	}
255
	
256
	/**
257
	 * 
258
	 * @param plan
259
	 */
260
	public void setPartialPlan(Plan plan) {
261
		this.plan = plan;
262
	}
263
	
264
	/**
265
	 * 
266
	 * @param partialPlan
267
	 */
268
//	public void setPartialPlan(Plan partialPlan) 
269
//	{
270
//		// set the partial plan 
271
//		this.plan = new HashMap<>();
272
//		// set of components 
273
//		Set<DomainComponent> cset = new HashSet<>();
274
//		
275
//		// check decisions
276
//		for (Decision dec : partialPlan.getDecisions()) 
277
//		{
278
//			// add component entry 
279
//			if (!this.plan.containsKey(dec.getComponent())) {
280
//				// add entry 
281
//				this.plan.put(dec.getComponent(), new ArrayList<>());
282
//			}
283
//			
284
//			// add decision variable
285
//			this.plan.get(dec.getComponent()).add(new DecisionVariable(dec));
286
//			
287
//			// check if primitive component
288
//			if (dec.getComponent().getType().equals(DomainComponentType.SV_PRIMITIVE)) {
289
//				// add component 
290
//				cset.add(dec.getComponent());
291
//			}
292
//		}
293
//		
294
//		
295
//		
296
//		// set makespan 
297
//		for (DomainComponent c : cset) 
298
//		{
299
//			// get component's decisions
300
//			if (this.plan.containsKey(c) && !this.plan.get(c).isEmpty()) 
301
//			{
302
//				// check last decision
303
//				DecisionVariable last = this.plan.get(c).get(0);
304
//				for (int index = 1; index < this.plan.get(c).size(); index++) {
305
//					// get current decision 
306
//					DecisionVariable d = this.plan.get(c).get(index);
307
//					
308
//					// check if last
309
//					if (d.getEnd()[0] > last.getEnd()[0]) {
310
//						// update last decision
311
//						last = d;
312
//					}
313
//				}
314
//				
315
//				
316
//				
317
//				// set component makespan according to end time bounds of the last decision
318
//				this.makespan.put(c, new Double[] {
319
//						(double) last.getEnd()[0],
320
//						(double) last.getEnd()[1]
321
//				});
322
//			}
323
//			else {
324
//				// no decision 
325
//				this.makespan.put(c, new Double[] {
326
//					(double) 0,
327
//					(double) 0
328
//				});
329
//			}
330
//		}
331
//	}
332
	
333
	/**
334
	 * 
335
	 * @return
336
	 */
337
//	public Map<DomainComponent, List<DecisionVariable>> getPartialPlan() {
338
//		// set the partial plan 
339
//		return new HashMap<>(this.plan);
340
//	}
341
	
342
	/**
343
	 * 
344
	 * @return
345
	 */
346
	public Map<DomainComponent, Double> getCost() {
347
		// get cost by components
348
		return new HashMap<>(this.cost);
349
	}
350
	
351
	/**
352
	 * 
353
	 * @return
354
	 */
355
	public double getPlanCost() {
356
		double cost = 0;
0 ignored issues
show
Comprehensibility introduced by
The variable costshadows a field with the same name declared in line 37. Consider renaming it.
Loading history...
357
		for (DomainComponent c : this.cost.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...
358
			cost += this.cost.get(c);
359
		}
360
		
361
		return cost;
362
	}
363
	
364
	/**
365
	 * 
366
	 * @return
367
	 */
368
	public double[] getPlanHeuristicCost() {
369
		// set cost
370
		double[] cost = new double[] {
0 ignored issues
show
Comprehensibility introduced by
The variable costshadows a field with the same name declared in line 37. Consider renaming it.
Loading history...
371
				0, 0
372
		};
373
		
374
		// set optimistic and pessimistic costs
375
		for (DomainComponent c : this.heuristicCost.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...
376
			cost[0] += this.heuristicCost.get(c)[0];
377
			cost[1] += this.heuristicCost.get(c)[1];
378
		}
379
		
380
		// get cost
381
		return cost;
382
	}
383
	
384
	/**
385
	 * Return the minimum and maximum makespan of the timelines of a plan
386
	 * 
387
	 * @return
388
	 */
389 View Code Duplication
	public double[] getPlanMakespan() {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
390
		
391
		// set the makespan
392
		double[] mk = new double[] {
393
				Double.MIN_VALUE + 1,  
394
				Double.MAX_VALUE - 1
395
		};
396
		
397
		
398
		
399
		// set update flag
400
		boolean update = false;
401
		// compute makespan bounds
402
		for (DomainComponent c : this.plan.getMakespan().keySet()) {
403
			// check primitive components only
404
			if (c.getType().equals(DomainComponentType.SV_PRIMITIVE)) {
405
				// update min and max
406
				mk[0] = Math.max(mk[0], this.plan.getMakespan().get(c)[0]);
407
				// update max
408
				mk[1] = Math.min(mk[1], this.plan.getMakespan().get(c)[1]);
409
				// change update flag
410
				update = true;
411
			}
412
		}
413
		
414
		// check update flag
415
		if (!update) {
416
			// set default data 
417
			mk = new double[] {
418
					0, 
419
					Double.MAX_VALUE - 1
420
			};
421
		}
422
		
423
		// get plan makespan 
424
		return mk;
425
	}
426
	
427
	/**
428
	 * 
429
	 * @return
430
	 */
431 View Code Duplication
	public double[] getPlanHeuristicMakespan() {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
432
		
433
		// set heuristic makespan
434
		double[] mk = new double[] {
435
				Double.MAX_VALUE - 1,
436
				Double.MIN_VALUE + 1 
437
		};
438
		
439
		// set update flag
440
		boolean update = false;
441
		// check heuristic makespan bounds of components 
442
		for (DomainComponent c : this.heuristicMakespan.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...
443
			// consider primitive components only 
444
			if (c.getType().equals(DomainComponentType.SV_PRIMITIVE)) {
445
				// update min and max
446
				mk[0] = Math.min(mk[0], this.heuristicMakespan.get(c)[0]);
447
				// update max
448
				mk[1] = Math.max(mk[1], this.heuristicMakespan.get(c)[1]);
449
				// change update flag
450
				update = true;
451
			}
452
		}
453
		
454
		// check update flag
455
		if (!update) {
456
			// set default data 
457
			mk = new double[] {
458
					0, 
459
					Double.MAX_VALUE - 1
460
			};
461
		}
462
		
463
		// get plan makespan 
464
		return mk;
465
	}
466
	
467
	/**
468
	 * Compute the estimated makespan as the sum of the consolidated and heuristic makespan
469
	 * 
470
	 * @param component
471
	 * @return
472
	 */
473
	public double[] getEstimatedMakespan(DomainComponent component) {
474
		
475
		// set heuristic makespan
476
		double[] mk = this.plan.getMakespan(component);
477
		
478
		// add heuristic value
479
		if (this.heuristicMakespan.containsKey(component)) {
480
			// increment
481
			mk[0] += this.heuristicMakespan.get(component)[0];
482
			mk[1] += this.heuristicMakespan.get(component)[1];
483
		}
484
485
		// get makespan
486
		return mk;
487
	}
488
	
489
	/**
490
	 * 
491
	 * @return
492
	 */
493
	public Map<DomainComponent, Double[]> getEstimatedMakespan() {
494
		
495
		// set data
496
		Map<DomainComponent, Double[]> mk = this.plan.getMakespan();
497
		// consider heuristic values
498
		for (DomainComponent comp : this.heuristicMakespan.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...
499
		{
500
			// add heuristic values
501
			double min = mk.containsKey(comp) ? mk.get(comp)[0] : 0;
502
			double max = mk.containsKey(comp) ? mk.get(comp)[1] : 0;
503
			
504
			// add heuristic value
505
			mk.put(comp, new Double[] {
506
				min + this.heuristicMakespan.get(comp)[0],
507
				max + this.heuristicMakespan.get(comp)[1]
508
			});
509
		}
510
		
511
		// get data
512
		return mk;
513
	}
514
	
515
	/**
516
	 * 
517
	 * @return
518
	 */
519
	public Map<DomainComponent, Double[]> getMakespan() {
520
		return new HashMap<>(this.plan.getMakespan());
521
	}
522
	
523
	/**
524
	 * Get the flaw that has been solved to generate the node 
525
	 * 
526
	 * @return
527
	 */
528
	public Flaw getGeneratingFlaw() {
529
		// verify whether the node is root
530
		return this.isRootNode() ? null : this.getGenerator().getFlaw();
531
	}
532
	
533
	/**
534
	 * Verify whether the node is root, i.e. not generator operator has been applied.
535
	 * 
536
	 * @return
537
	 */
538
	public boolean isRootNode() {
539
		// check if root node
540
		return this.getGenerator() == null;
541
	}
542
	
543
	/**
544
	 * The method returns the order list of operators that have been applied to generated the node. 
545
	 * 
546
	 * The last operator of the list is the node generator operator (i.e. the last applied operator).
547
	 * 
548
	 * @return
549
	 */
550
	public List<Operator> getOperators() {
551
		// get list of operators
552
		return new ArrayList<>(this.operators);
553
	}
554
	
555
	/**
556
	 * The method returns the node generator operator.
557
	 * 
558
	 * The method returns null for the root node of the search space
559
	 * 
560
	 * @return
561
	 */
562
	public Operator getGenerator() 
563
	{
564
		// get generator
565
		Operator operator = null;
566
		if (!this.operators.isEmpty()) {
567
			// get last applied operator
568
			operator = this.operators.get(this.operators.size() - 1);
569
		}
570
		
571
		// get generator operator
572
		return operator;
573
	}
574
	
575
	/**
576
	 * Get the list of applied operators from the more recent to the specified one (not included).
577
	 * 
578
	 * The method returns the list of operators that have been applied after the specified one starting with the more recent. The first
579
	 * element of the list is the node generator operator.
580
	 * 
581
	 * @param operator
582
	 * @return
583
	 */
584
	public List<Operator> getOperatorsUpTo(Operator operator) {
585
		// list of operators
586
		List<Operator> list = new ArrayList<>();
587
		if (operator == null) {
588
			// add all operators
589
			list.addAll(this.operators);
590
			// reverse order
591
			Collections.reverse(list);
592
		}
593
		else {
594
			// get index of the operator
595
			int index = this.operators.indexOf(operator);
596
			for (int i = this.operators.size() - 1; i > index; i--) {
597
				// add operator
598
				list.add(this.operators.get(i));
599
			}
600
		}
601
		// get list of operators
602
		return list;
603
	}
604
	
605
	/**
606
	 * Get the list of applied operators starting from the selected operator (not included).
607
	 * 
608
	 * The method returns the orderer list of operators that have been applied after the specified one. The 
609
	 * last operator of the list is the node generator operator.
610
	 * 
611
	 * 
612
	 * @param operator
613
	 * @return
614
	 */
615
	public List<Operator> getOperatorsFrom(Operator operator) {
616
		// list of operators
617
		List<Operator> list = new ArrayList<>();
618
		if (operator == null) {
619
			// add all operators
620
			list.addAll(this.operators);
621
		}
622
		else {
623
			// get index of the operator
624
			for (int index = this.operators.indexOf(operator) + 1; index < this.operators.size(); index++) {
625
				// add operator
626
				list.add(this.operators.get(index));
627
			}
628
		}
629
		// get list of operators
630
		return list;
631
	}
632
	
633
	/**
634
	 * 
635
	 */
636
	@Override
637
	public int hashCode() {
638
		final int prime = 31;
639
		int result = 1;
640
		result = prime * result + id;
641
		return result;
642
	}
643
644
	/**
645
	 * 
646
	 */
647
	@Override
648
	public boolean equals(Object obj) {
649
		if (this == obj)
650
			return true;
651
		if (obj == null)
652
			return false;
653
		if (getClass() != obj.getClass())
654
			return false;
655
		SearchSpaceNode other = (SearchSpaceNode) obj;
656
		if (id != other.id)
657
			return false;
658
		return true;
659
	}
660
	
661
	/**
662
	 * 
663
	 */
664
	@Override
665
	public int compareTo(SearchSpaceNode o) {
666
		// compare nodes by their ID
667
		return this.id < o.id ? -1 : this.id > o.id ? 1 : 0;
668
	}
669
	
670
	/**
671
	 * 
672
	 */
673
	@Override
674
	public String toString() {
675
		// JSON style description of node
676
		return "{ "
677
				+ "\"id\": " + this.id + ", "
678
				+ "\"depth\": " + this.getDepth() + ", "
679
				+ "\"cost\": " + this.getPlanCost() + ", "
680
				+ "\"makespan\": [" + this.getPlanMakespan()[0] + ", " + this.getPlanMakespan()[1] + "], "
681
				+ "\"heuristic-cost\": [" + this.getPlanHeuristicCost()[0] +", " + this.getPlanHeuristicCost()[1] + "], "
682
				+ "\"heuristic-makespan\": [" + this.getPlanHeuristicMakespan()[0] + ", " + this.getPlanHeuristicMakespan()[1] + "] "
683
				+ " }";
684
	}
685
}
686