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

addStateVariableValue(String,long[],boolean)   A

Complexity

Conditions 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
dl 0
loc 9
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.Collections;
5
import java.util.HashMap;
6
import java.util.List;
7
import java.util.Map;
8
9
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ComponentValue;
10
import it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponent;
11
import it.cnr.istc.pst.platinum.ai.framework.domain.component.DomainComponentType;
12
import it.cnr.istc.pst.platinum.ai.framework.domain.component.ex.TransitionNotFoundException;
13
14
/**
15
 * 
16
 * @author anacleto
17
 *
18
 */
19
public abstract class StateVariable extends DomainComponent 
0 ignored issues
show
Bug introduced by
Override the "equals" method in this class.
Loading history...
20
{
21
	protected List<StateVariableValue> values;							
22
	// SV's transition function
23
	protected Map<StateVariableValue, Map<StateVariableValue, Transition>> transitions;
24
	
25
	/**
26
	 * 
27
	 * @param name
28
	 * @param type
29
	 */
30
	protected StateVariable(String name, DomainComponentType type) {
31
		super(name, type);
32
		// initialize the list of values
33
				this.values = new ArrayList<StateVariableValue>();
34
		// initialize transition function
35
		this.transitions = new HashMap<>();
36
	}
37
	
38
	/**
39
	 * 
40
	 * @param label
41
	 * @param duration
42
	 * @param controllable
43
	 * @return
44
	 */
45
	public StateVariableValue addStateVariableValue(String label, long[] duration, boolean controllable) {
46
		// create and add value
47
		StateVariableValue value = new StateVariableValue(label, duration, controllable, this);
48
		// add to available values
49
		this.values.add(value);
50
		// add transition
51
		this.transitions.put(value, new HashMap<StateVariableValue, Transition>());
52
		// get value
53
		return value;
54
	}
55
	
56
	/**
57
	 * State variable values without duration bounds are implicitly treated as controllable
58
	 * 
59
	 * @param label
60
	 * @return
61
	 */
62
	public StateVariableValue addStateVariableValue(String label) {
63
		return this.addStateVariableValue(label, new long [] {1l, this.tdb.getHorizon()}, true);
64
	}
65
	
66
	
67
68
	/**
69
	 * 
70
	 * @param reference
71
	 * @param target
72
	 * @return
73
	 */
74
	public Transition addValueTransition(StateVariableValue reference, StateVariableValue target) {
75
		// check values
76
		if (!this.values.contains(reference) || !this.values.contains(target)) {
77
			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...
78
		}
79
		
80
		// create transition
81
		Transition t = new Transition(reference, target);
82
		// add transition
83
		this.transitions.get(reference).put(target, t);
84
		// get transition
85
		return t;
86
	}
87
	
88
	/**
89
	 * 
90
	 * @param reference
91
	 * @param target
92
	 * @return
93
	 */
94
	public Transition getTransition(ComponentValue reference, ComponentValue target) 
95
			throws TransitionNotFoundException 
96
	{
97
		// check if transition exists
98
		if (!this.transitions.containsKey(reference) || !this.transitions.get(reference).containsKey(target)) {
99
			// transition not found
100
			throw new TransitionNotFoundException("No transition found between values [reference= " + reference + " target= " + target + "]");
101
		}
102
		
103
		// check transitions
104
		return this.transitions.get(reference).get(target);
105
	}
106
	
107
	/**
108
	 * Returns the direct successors of the value according to
109
	 * the transition function of the State Variable
110
	 * 
111
	 * @param value
112
	 * @return
113
	 */
114
	public List<ComponentValue> getDirectSuccessors(ComponentValue value) {
115
		// get successors as a list
116
		return new ArrayList<>(this.transitions.get(value).keySet());
117
	}
118
	
119
	/**
120
	 * Analyze the state machine of the SV to extract all possible "acyclic" 
121
	 * paths between two values.
122
	 * 
123
	 * Please note that "acyclic" paths do not consider the case in which the 
124
	 * source is the same value as the target of the path. Indeed, it could be 
125
	 * necessary to find acyclic paths that starts and ends with the same state
126
	 * variable value
127
	 * 
128
	 * @param source
129
	 * @param target
130
	 * @return
131
	 */
132
	public List<ValuePath> getPaths(ComponentValue source, ComponentValue target) 
133
	{
134
		// list of all acyclic paths that start from the source value and end to the target value
135
		List<ValuePath> result = new ArrayList<>();
136
		// check the case in which the source value is equal to the target value
137
		if (source.equals(target))
138
		{
139
			// just start the search starting from the direct successors of the current value
140
			for (ComponentValue successor : this.getDirectSuccessors(source))
141
			{
142
				// just avoid reflexive transition (that should not be allowed in the domain specification)
143
				if (!source.equals(successor)) {
144
					// get list of paths
145
					for (ValuePath path : this.computePaths(successor, target, new ArrayList<>())) {
146
						// add the source value in front of the path
147
						path.addFirstStep(source);
148
						// add the path to the result list
149
						result.add(path);
150
					}
151
				}
152
			}
153
		}
154
		else {
155
			// call recursive function to compute all acyclic paths between state variable values
156
			result = this.computePaths(source, target, new ArrayList<>());
157
		}
158
		
159
		// sort paths according to their length
160
		Collections.sort(result);
161
		// get the result list
162
		return result;
163
	}
164
	
165
	/**
166
	 * 
167
	 * @param source
168
	 * @param target
169
	 * @param visited
170
	 * @return
171
	 */
172
	private List<ValuePath> computePaths(ComponentValue source, ComponentValue target, List<ComponentValue> visited)
173
	{
174
		// result list
175
		List<ValuePath> result = new ArrayList<>();
176
		
177
		// compare source value and target value
178
		if (source.equals(target)) {
179
			// create value path
180
			ValuePath path = new ValuePath();
181
			// add last step
182
			path.addLastStep(source);
183
			// add to result
184
			result.add(path);
185
		}
186
		else
187
		{
188
			// add current node to visited list
189
			visited.add(source);
190
			// navigate the state variable towards the target value
191
			for (ComponentValue value : this.getDirectSuccessors(source))
192
			{
193
				// check cycle
194
				if (!visited.contains(value))
195
				{
196
					// get partial paths found through recursive call
197
					List<ValuePath> paths = this.computePaths(value, target, visited);
198
					// aggregate and build the result
199
					for (ValuePath path : paths) 
200
					{
201
						// add current value the current (partial) path 
202
						path.addFirstStep(source);
203
						// add the current (partial) path to the result list
204
						result.add(path);
205
					}
206
				}
207
			}
208
			
209
			// remove visited value
210
			visited.remove(source);
211
		}
212
		
213
		// get list of paths
214
		return result;
215
	}
216
	
217
	/**
218
	 * 
219
	 */
220
	@SuppressWarnings("unchecked")
221
	@Override
222
	public List<StateVariableValue> getValues() {
223
		return new ArrayList<StateVariableValue>(this.values);
224
	}
225
	
226
	/**
227
	 * 
228
	 */
229
	@Override
230
	public StateVariableValue getValueByName(String name) {
231
		StateVariableValue value = null;
232
		for (StateVariableValue v : this.values) {
233
			if (v.getLabel().equals(name)) {
234
				value = v;
235
				break;
236
			}
237
		}
238
		
239
		// check if value has been found
240
		if (value == null) {
241
			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...
242
		}
243
		
244
		// get value
245
		return value;
246
	}
247
	
248
	/**
249
	 * 
250
	 */
251
	@Override
252
	public String toString() {
253
		return "{ \"name\": \"" + this.name + "\", \"label\": \"" + this.type.getLabel()+ "\" }";
254
	}
255
	
256
}
257