-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathWekaFaultLocalizer.java
More file actions
194 lines (164 loc) · 6.38 KB
/
WekaFaultLocalizer.java
File metadata and controls
194 lines (164 loc) · 6.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
* This file is part of the "STARDUST" project.
*
* (c) Fabian Keller <hello@fabian-keller.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package fk.stardust.localizer.machinelearn;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import weka.classifiers.AbstractClassifier;
import weka.classifiers.Classifier;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;
import fk.stardust.localizer.IFaultLocalizer;
import fk.stardust.localizer.Ranking;
import fk.stardust.traces.INode;
import fk.stardust.traces.ISpectra;
import fk.stardust.traces.ITrace;
/**
* Machine learning based fault localization approach using Weka as ML backend.
*
* ML algorithms can be configured.
*
* @param <T>
* type used to identify nodes in the system
*/
public class WekaFaultLocalizer<T> implements IFaultLocalizer<T> {
/** classifier name */
private final String classifierName;
/** options for the classifier */
private final String[] classifierOptions;
/**
* Construct Weka fault localizer
*
* @param classifierName
* name of the Weka classifier to use
*/
public WekaFaultLocalizer(final String classifierName) {
this(classifierName, new String[0]);
}
/**
* Construct Weka fault localizer
*
* @param classifierName
* name of the Weka classifier to use
* @param options
* options to pass to the classifier
*/
public WekaFaultLocalizer(final String classifierName, final String[] options) {
super();
this.classifierName = classifierName;
if (options == null) {
this.classifierOptions = new String[0];
} else {
this.classifierOptions = Arrays.copyOf(options, options.length);
}
}
/**
* Returns the name of the used classifier
*
* @return classifier name
*/
public String getClassifierName() {
return this.classifierName;
}
@Override
public Ranking<T> localize(final ISpectra<T> spectra) {
// == 1. Create Weka training instance
final List<INode<T>> nodes = new ArrayList<>(spectra.getNodes());
// nominal true/false values
final List<String> tf = new ArrayList<String>();
tf.add("t");
tf.add("f");
// create an attribute for each component
final Map<INode<T>, Attribute> attributeMap = new HashMap<>();
final ArrayList<Attribute> attributeList = new ArrayList<>(); // NOCS: Weka needs ArrayList..
for (final INode<T> node : nodes) {
final Attribute attribute = new Attribute(node.toString(), tf);
attributeList.add(attribute);
attributeMap.put(node, attribute);
}
// create class attribute (trace success)
final Attribute successAttribute = new Attribute("success", tf);
attributeList.add(successAttribute);
// create weka training instance
final Instances trainingSet = new Instances("TraceInfoInstances", attributeList, 1);
trainingSet.setClassIndex(attributeList.size() - 1);
// == 2. add traces to training set
// add an instance for each trace
for (final ITrace<T> trace : spectra.getTraces()) {
final Instance instance = new DenseInstance(nodes.size() + 1);
instance.setDataset(trainingSet);
for (final INode<T> node : nodes) {
instance.setValue(attributeMap.get(node), trace.isInvolved(node) ? "t" : "f");
}
instance.setValue(successAttribute, trace.isSuccessful() ? "t" : "f");
trainingSet.add(instance);
}
// == 3. use prediction to localize faults
// build classifier
try {
final Classifier classifier = this
.buildClassifier(this.classifierName, this.classifierOptions, trainingSet);
final Ranking<T> ranking = new Ranking<>();
System.out.println("begin classifying");
int classified = 0;
final Instance instance = new DenseInstance(nodes.size() + 1);
instance.setDataset(trainingSet);
for (final INode<T> node : nodes) {
instance.setValue(attributeMap.get(node), "f");
}
instance.setValue(successAttribute, "f");
for (final INode<T> node : nodes) {
classified++;
if (classified % 1000 == 0) {
System.out.println(String.format("Classified %d nodes.", classified));
}
// contain only the current node in the network
instance.setValue(attributeMap.get(node), "t");
// predict with which probability this setup leads to a failing network
final double[] distribution = classifier.distributionForInstance(instance);
ranking.rank(node, distribution[1]);
// reset involvment for node
instance.setValue(attributeMap.get(node), "f");
}
return ranking;
} catch (final Exception e) { // NOCS: Weka throws only raw exceptions
throw new RuntimeException(e);
}
}
/**
* Builds and trains a classifier.
*
* @param name
* FQCN of the classifier
* @param options
* options to pass to the classifier
* @param trainingSet
* training set to build the classifier with
* @return trained classifier
*/
public Classifier buildClassifier(final String name, final String[] options, final Instances trainingSet) {
try {
final Classifier classifier = AbstractClassifier.forName(this.classifierName, options);
classifier.buildClassifier(trainingSet);
return classifier;
} catch (final Exception e1) { // NOCS: Weka throws only raw exceptions
System.err.println("Unable to create classifier " + this.classifierName);
throw new RuntimeException(e1);
}
}
@Override
public String getName() {
assert !this.classifierName.endsWith(".");
return "weka-" + this.classifierName.substring(this.classifierName.lastIndexOf(".") + 1);
}
}