Passed
Push — master ( ae3765...c7eba3 )
by Alessandro
06:32
created

getDirectPredecessors(ComponentValue)   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
package it.cnr.istc.pst.platinum.ai.framework.domain.component.sv;
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.domain.component.ComponentValue;
11
import it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponent;
12
import it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponentType;
13
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.TransitionNotFoundException;
14
15
/**
16
 * 
17
 * @author alessandro
18
 *
19
 */
20
public abstract class StateVariable extends DomainComponent {
0 ignored issues
show
Bug introduced by
Override the "equals" method in this class.
Loading history...
21
	
22
	protected List<StateVariableValue> values;							
23
	// SV's transition function
24
	protected Map<StateVariableValue, Map<StateVariableValue, Transition>> transitions;
25
	
26
	protected Map<StateVariableValue, Map<StateVariableValue, Transition>> inverseTransitions;
27
	
28
	/**
29
	 * 
30
	 * @param name
31
	 * @param type
32
	 */
33
	protected StateVariable(String name, DomainComponentType type) {
34
		super(name, type);
35
		// initialize the list of values
36
		this.values = new ArrayList<StateVariableValue>();
37
		// initialize transition function
38
		this.transitions = new HashMap<>();
39
		// initialize transition function
40
		this.inverseTransitions = new HashMap<>();
41
	}
42
	
43
	/**
44
	 * 
45
	 * @param label
46
	 * @param duration
47
	 * @param controllable
48
	 * @return
49
	 */
50
	public StateVariableValue addStateVariableValue(String label, long[] duration, boolean controllable) {
51
		// create and add value
52
		StateVariableValue value = new StateVariableValue(label, duration, controllable, this);
53
		// add to available values
54
		this.values.add(value);
55
		// initialize transition data structure
56
		this.transitions.put(value, new HashMap<>());
57
		// initialize inverse transition data structure
58
		this.inverseTransitions.put(value, new HashMap<>());
59
		// get value
60
		return value;
61
	}
62
	
63
	/**
64
	 * State variable values without duration bounds are implicitly treated as controllable
65
	 * 
66
	 * @param label
67
	 * @return
68
	 */
69
	public StateVariableValue addStateVariableValue(String label) {
70
		return this.addStateVariableValue(label, new long [] {1l, this.tdb.getHorizon()}, true);
71
	}
72
	
73
	
74
75
	/**
76
	 * 
77
	 * @param reference
78
	 * @param target
79
	 * @return
80
	 */
81
	public Transition addValueTransition(StateVariableValue reference, StateVariableValue target) {
82
		// check values
83
		if (!this.values.contains(reference) || !this.values.contains(target)) {
84
			throw new RuntimeException("One or both StateVariable values not found [reference= " + reference + " target= " + target + "]");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
85
		}
86
		
87
		// create transition
88
		Transition t = new Transition(reference, target);
89
		
90
		// check transition
91
		if (!this.transitions.containsKey(reference)) {
92
			this.transitions.put(reference, new HashMap<>());
93
		}
94
		
95
		// add transition
96
		this.transitions.get(reference).put(target, t);
97
		
98
		// check inverse transition
99
		if (!this.inverseTransitions.containsKey(target) ) {
100
			this.inverseTransitions.put(target, new HashMap<>());
101
		}
102
		// add inverse transition
103
		this.inverseTransitions.get(target).put(reference, t);
104
		
105
		// get transition
106
		return t;
107
	}
108
	
109
	/**
110
	 * 
111
	 * @param reference
112
	 * @param target
113
	 * @return
114
	 */
115
	public Transition getTransition(ComponentValue reference, ComponentValue target)  throws TransitionNotFoundException {
116
		
117
		// check if transition exists
118
		if (!this.transitions.containsKey(reference) || !this.transitions.get(reference).containsKey(target)) {
119
			// transition not found
120
			throw new TransitionNotFoundException("No transition found between values [reference= " + reference + " target= " + target + "]");
121
		}
122
		
123
		// check transitions
124
		return this.transitions.get(reference).get(target);
125
	}
126
	
127
	/**
128
	 * Returns the direct successors of the value according to
129
	 * the transition function of the State Variable
130
	 * 
131
	 * @param value
132
	 * @return
133
	 */
134
	public List<ComponentValue> getDirectSuccessors(ComponentValue value) {
135
		// get successors as a list
136
		return new ArrayList<>(this.transitions.get(value).keySet());
137
	}
138
	
139
	/**
140
	 * Returns the direct predecessors of the value according to 
141
	 * the transition function of the State Variable
142
	 * 
143
	 * @param value
144
	 * @return
145
	 */
146
	public List<ComponentValue> getDirectPredecessors(ComponentValue value) {
147
		// get predecessors as a list
148
		return new ArrayList<>(this.inverseTransitions.get(value).keySet());
149
	}
150
	
151
	/**
152
	 * Analyze the state machine of the SV to extract the shortest acyclic path between two values.
153
	 * 
154
	 * @param source
155
	 * @param target
156
	 * @return
157
	 */
158
	public ValuePath getShortestPath(ComponentValue source, ComponentValue target) {
159
		
160
		// call recursive method to unfold state variable description and build possible paths
161
		ValuePath path = this.bfs(source, target);
162
		// get the shortest path
163
		return path;
164
	}
165
	
166
	/**
167
	 * Compute the shortest path from a source to the target through Breadth-First search
168
	 * 
169
	 * @param source
170
	 * @param target
171
	 * @param path
172
	 * @param fringe
173
	 * @return
174
	 */
175
	private ValuePath bfs(ComponentValue source, ComponentValue target) {
176
		
177
		// initialize fringe
178
		List<ComponentValue> fringe = new ArrayList<>();
179
		// visited values
180
		Set<ComponentValue> visited = new HashSet<>();
181
		// initialize the associative map to keep track of parents
182
		Map<ComponentValue, ComponentValue> parents = new HashMap<>();
183
		// set the fringe
184
		for (ComponentValue succ : this.getDirectSuccessors(source) ) {
185
			// add to fringe
186
			fringe.add(succ);
187
			// update parent index
188
			parents.put(succ, source);
189
			
190
		}
191
		
192
		// add the first step
193
		visited.add(source);
194
		// initialize parent map
195
		parents.put(source, null);
196
		// set last value
197
		ComponentValue last = source;
198
		ComponentValue lastParent = source;
0 ignored issues
show
Unused Code Code Smell introduced by
Remove this useless assignment to local variable "lastParent".
Loading history...
199
		
200
		// explore the fringe
201
		while (!fringe.isEmpty()) {
202
			
203
			// get the first value from the fringe
204
			ComponentValue value = fringe.remove(0);
205
			// check value
206
			if (value.equals(target)) {
207
				
208
				// update last value and stop the search
209
				last = value;
210
				// stop the search
211
				break;
212
				
213
			} else {
214
				
215
				// check if already visited
216
				if (!visited.contains(value) ) {
217
					
218
					// add the value to the set of visited ones
219
					visited.add(value);
220
					lastParent = value;
221
					for (ComponentValue succ : this.getDirectSuccessors(value)) {
222
						
223
						// add to fringe
224
						fringe.add(succ);
225
						// set visited parent
226
						parents.put(succ, lastParent);
227
					}
228
					
229
					// update last value
230
					last = value;
231
				}
232
			}
233
		}
234
		
235
		
236
		// prepare the path to reconstruct
237
		ValuePath path = new ValuePath();
238
		
239
		do {
240
			
241
			// add to the head to reconstruct the path from the back
242
			path.addFirstStep(last);
243
			// update to the next step by retrieving the parent
244
			last = parents.get(last);
245
			
246
		} while (last != null);
247
		
248
		// get computed (shortest) path
249
		return path;
250
	}
251
	
252
	/**
253
	 * 
254
	 */
255
	@SuppressWarnings("unchecked")
256
	@Override
257
	public List<StateVariableValue> getValues() {
258
		return new ArrayList<StateVariableValue>(this.values);
259
	}
260
	
261
	/**
262
	 * 
263
	 */
264
	@Override
265
	public StateVariableValue getValueByName(String name) {
266
		StateVariableValue value = null;
267
		for (StateVariableValue v : this.values) {
268
			if (v.getLabel().equals(name)) {
269
				value = v;
270
				break;
271
			}
272
		}
273
		
274
		// check if value has been found
275
		if (value == null) {
276
			throw new RuntimeException("Value \"" + name + "\" not found on state variable \"" + this.name + "\"");
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
277
		}
278
		
279
		// get value
280
		return value;
281
	}
282
	
283
	/**
284
	 * 
285
	 */
286
	@Override
287
	public String toString() {
288
		return "{ \"name\": \"" + this.name + "\", \"label\": \"" + this.type.getLabel()+ "\" }";
289
	}
290
	
291
}
292