aboutsummaryrefslogtreecommitdiffstats
path: root/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca
diff options
context:
space:
mode:
Diffstat (limited to 'Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca')
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Domain.xtend7
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Main.xtend96
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/PartialInterpretationMetric.xtend85
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/PartialInterpretationMetricDistance.xtend216
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/CostDistance.xtend38
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/EuclideanDistance.xtend72
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/JSDistance.xtend88
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/KSDistance.xtend102
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/EMFGraph.xtend124
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/Graph.xtend71
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/GraphStatistic.xtend194
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/PartialInterpretationGraph.xtend134
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/CsvFileWriter.xtend52
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/GraphReader.xtend112
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/RepMetricsReader.xtend100
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/EdgeTypeMetric.xtend41
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/Metric.xtend8
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/MetricSampleGroup.xtend13
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/MultiplexParticipationCoefficientMetric.xtend80
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/NodeActivityMetric.xtend49
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/NodeTypeMetric.xtend42
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/OutDegreeMetric.xtend49
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/TypedClusteringCoefficientMetric.xtend99
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/TypedOutDegree.xtend60
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/predictor/LinearModel.xtend91
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ConstraintCollection.xtend80
-rw-r--r--Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ViolationCheck.xtend66
27 files changed, 2169 insertions, 0 deletions
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Domain.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Domain.xtend
new file mode 100644
index 00000000..c8fd435b
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Domain.xtend
@@ -0,0 +1,7 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app
2
3enum Domain{
4 Yakindumm,
5 Ecore,
6 Github
7} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Main.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Main.xtend
new file mode 100644
index 00000000..dfde6593
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Main.xtend
@@ -0,0 +1,96 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.EMFGraph
4import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io.CsvFileWriter
5import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io.GraphReader
6import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.validation.ViolationCheck
7import hu.bme.mit.inf.dslreasoner.domains.yakindu.sgraph.yakindumm.impl.YakindummPackageImpl
8import java.io.File
9import java.util.ArrayList
10import org.eclipse.emf.ecore.EPackage
11import org.eclipse.emf.ecore.EcorePackage
12import org.eclipse.viatra.query.runtime.rete.matcher.ReteEngine
13import org.eclipse.emf.ecore.impl.EcorePackageImpl
14import org.eclipse.emf.ecore.EReference
15
16//import yakindumm2.impl.Yakindumm2PackageImpl
17
18class Main {
19 var static Domain d = Domain.Yakindumm;
20 val static String suffix = '.xmi'
21 val static String OUTPUT_FOLDER = "Inputs/measurement2/yakindu/Alloy/";
22 val static String INPUT_FOLDER = "outputs/measurement2/yakindu/Alloy/";
23 val static int NUM_RUNS = 1;
24
25 static class RWInformation{
26 public var String inputFolder;
27 public var String outputFolder;
28 public var int numRuns;
29
30 new(String inputFolder, String outputFolder, int numRuns){
31 this.inputFolder = inputFolder;
32 this.outputFolder = outputFolder;
33 this.numRuns = numRuns;
34 }
35 }
36
37 def static void main(String[] args){
38 //init model
39 var EPackage metamodel;
40 //init viatra engine for the violation checker
41 ReteEngine.getClass();
42
43 if(d == Domain.Yakindumm){
44 YakindummPackageImpl.eINSTANCE.eClass;
45 metamodel = YakindummPackageImpl.eINSTANCE;
46 }else if (d == Domain.Ecore){
47 EcorePackage.eINSTANCE.eClass;
48 metamodel = EcorePackageImpl.eINSTANCE;
49 }else if (d == Domain.Github){
50 //TODO: Initialize Github Package
51 }
52
53
54 println("Start Reading Models...");
55 var reader = new GraphReader(metamodel, suffix);
56
57 val models = new RWInformation(OUTPUT_FOLDER, INPUT_FOLDER, NUM_RUNS);
58 calculateAllModels(models.inputFolder, models.outputFolder,models.numRuns, reader);
59 println("finished");
60 }
61
62 static def calculateAllModels(String inputFolder, String outputFolder, int numRuns, GraphReader reader){
63 (new File(outputFolder)).mkdir();
64 for(var i = 1; i <= numRuns; i++){
65 val models = new ArrayList<EMFGraph>();
66 models.addAll(reader.readModels(inputFolder + "run" + i));
67 for(model : models){
68 calculateAndOutputMetrics(model, YakindummPackageImpl.eNAME, outputFolder+model.name+"_run_"+i+".csv");
69 }
70 }
71 println("output results Ended for: " + outputFolder);
72
73
74 }
75
76 static def calculateAndOutputMetrics(EMFGraph model, String metaModel, String fileName){
77 //println("evaluating for " + model.name);
78 model.metaModel = metaModel;
79
80 //remove eGenericType for Ecore domain
81 if(d == Domain.Ecore){
82 var refsToRemove = EcorePackageImpl.eINSTANCE.eAllContents.filter(EReference).filter[
83 it.name.equals('eGenericType') || it.name.equals('eGenericSuperTypes') || it.name.equals('eFactoryInstance')||
84 it.name.equals('eGenericExceptions') || it.name.equals('references') || it.name.equals('contents');
85 ];
86 refsToRemove.forEach[model.removeReference(it)];
87 }
88
89 var outputs = model.evaluateAllMetrics();
90 var violations = ViolationCheck.calculateViolationCounts(model.root, d);
91 println(violations);
92 var violationsOutput = newArrayList('violations', violations+'');
93 outputs.add(violationsOutput);
94 CsvFileWriter.write(outputs, fileName);
95 }
96} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/PartialInterpretationMetric.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/PartialInterpretationMetric.xtend
new file mode 100644
index 00000000..5e62b586
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/PartialInterpretationMetric.xtend
@@ -0,0 +1,85 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance.JSDistance
4import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance.KSDistance
5import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.PartialInterpretationGraph
6import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io.CsvFileWriter
7import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.Metric
8import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MultiplexParticipationCoefficientMetric
9import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.NodeActivityMetric
10import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.OutDegreeMetric
11import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation
12import java.io.File
13import java.io.FileNotFoundException
14import java.io.PrintWriter
15import java.util.ArrayList
16import java.util.List
17import org.eclipse.emf.ecore.util.EcoreUtil
18import org.eclipse.viatra.dse.api.Solution
19
20class PartialInterpretationMetric {
21 var static KSDistance ks;
22 var static JSDistance js;
23
24 def static void initPaths(){
25 new File("debug/metric/").mkdir();
26 new File("debug/metric/trajectories/").mkdir();
27 }
28
29 // calculate the metrics for a state
30 def static void calculateMetric(PartialInterpretation partial, String path, String currentStateId, Integer counter){
31 val metrics = new ArrayList<Metric>();
32 metrics.add(new OutDegreeMetric());
33 metrics.add(new NodeActivityMetric());
34 metrics.add(new MultiplexParticipationCoefficientMetric());
35
36 //make dir since the folder can be none existing
37 new File(path).mkdir();
38 val filename = path + "/state_"+currentStateId+"-"+counter+".csv";
39 val metricCalculator = new PartialInterpretationGraph(partial, metrics, currentStateId);
40
41 CsvFileWriter.write(metricCalculator.evaluateAllMetrics(), filename);
42 }
43
44 def static void outputTrajectories(PartialInterpretation empty, List<Solution> solutions){
45 for(solution : solutions){
46
47 //need to copy the empty solution because the transition directly worked on the graph
48 val emptySolutionCopy = EcoreUtil.copy(empty)
49 val trajectory = solution.shortestTrajectory;
50 trajectory.model = emptySolutionCopy
51
52 // state codes that will record the trajectory
53 val stateCodes = newArrayList()
54 var counter = 0
55
56 //transform and record the state codes for each state
57 while(trajectory.doNextTransformation){
58 //println(trajectory.stateCoder.createStateCode)
59 val stateId = trajectory.stateCoder.createStateCode.toString
60 val interpretation = trajectory.getModel();
61 println(stateId)
62 //calculate metrics of current state
63 calculateMetric(interpretation as PartialInterpretation, "debug/metric/output", stateId, counter)
64 stateCodes.add(stateId)
65 counter++
66 }
67
68
69 //output the trajectory
70 try{
71 new File("debug/metric/trajectories/").mkdir();
72 val path = "debug/metric/trajectories/trajectory"+trajectory.stateCoder.createStateCode.toString+".csv"
73 val PrintWriter writer = new PrintWriter(new File(path))
74 val output = new StringBuilder
75 for(stateCode : stateCodes){
76 output.append(stateCode+'\n')
77 }
78 writer.write(output.toString())
79 writer.close()
80 }catch(FileNotFoundException e) {
81 e.printStackTrace()
82 }
83 }
84 }
85} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/PartialInterpretationMetricDistance.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/PartialInterpretationMetricDistance.xtend
new file mode 100644
index 00000000..697b2639
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/PartialInterpretationMetricDistance.xtend
@@ -0,0 +1,216 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance.EuclideanDistance
4import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance.JSDistance
5import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance.KSDistance
6import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance.StateData
7import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.PartialInterpretationGraph
8import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io.RepMetricsReader
9import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.Metric
10import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MetricSampleGroup
11import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MultiplexParticipationCoefficientMetric
12import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.NodeActivityMetric
13import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.NodeTypeMetric
14import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.OutDegreeMetric
15import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.predictor.LinearModel
16import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation
17import java.util.ArrayList
18import java.util.HashMap
19import java.util.List
20import java.util.Map
21import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression
22import org.eclipse.xtend.lib.annotations.Accessors
23import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.EdgeTypeMetric
24
25class PartialInterpretationMetricDistance {
26
27 var KSDistance ks;
28 var JSDistance js;
29 var EuclideanDistance ed;
30 var Map<Object, StateData> stateAndHistory;
31 var OLSMultipleLinearRegression regression;
32 List<StateData> samples;
33 var MetricSampleGroup g;
34 @Accessors(PUBLIC_GETTER)
35 var LinearModel linearModel;
36
37
38 new(Domain d){
39 var metrics = RepMetricsReader.read(d);
40 this.g = metrics;
41 ks = new KSDistance(g);
42 js = new JSDistance(g);
43 ed = new EuclideanDistance(g);
44 regression = new OLSMultipleLinearRegression();
45 regression.noIntercept = false;
46 stateAndHistory = new HashMap<Object, StateData>();
47 samples = new ArrayList<StateData>();
48 linearModel = new LinearModel(0.01);
49 }
50
51 def MetricDistanceGroup calculateMetricDistanceKS(PartialInterpretation partial){
52 val metrics = new ArrayList<Metric>();
53 metrics.add(new OutDegreeMetric());
54 metrics.add(new NodeActivityMetric());
55 metrics.add(new MultiplexParticipationCoefficientMetric());
56 metrics.add(new NodeTypeMetric());
57 val metricCalculator = new PartialInterpretationGraph(partial, metrics, null);
58 var metricSamples = metricCalculator.evaluateAllMetricsToSamples();
59
60 var mpc = ks.mpcDistance(metricSamples.mpcSamples);
61 var na = ks.naDistance(metricSamples.naSamples);
62 var outDegree = ks.outDegreeDistance(metricSamples.outDegreeSamples);
63 var nodeType = ks.nodeTypeDistance(metricSamples.nodeTypeSamples);
64 //var typedOutDegree = ks.typedOutDegreeDistance(metricSamples.typedOutDegreeSamples);
65 var distance = new MetricDistanceGroup(mpc, na, outDegree, nodeType);
66 distance.nodeTypeInfo = metricSamples.nodeTypeSamples;
67 return distance;
68 }
69
70 def MetricDistanceGroup calculateMetricEuclidean(PartialInterpretation partial){
71 val metrics = new ArrayList<Metric>();
72 metrics.add(new OutDegreeMetric());
73 metrics.add(new NodeActivityMetric());
74 metrics.add(new MultiplexParticipationCoefficientMetric());
75
76 val metricCalculator = new PartialInterpretationGraph(partial, metrics, null);
77 var metricSamples = metricCalculator.evaluateAllMetricsToSamples();
78
79 var mpc = ed.mpcDistance(metricSamples.mpcSamples);
80 var na = ed.naDistance(metricSamples.naSamples);
81 var outDegree = ed.outDegreeDistance(metricSamples.outDegreeSamples);
82
83 return new MetricDistanceGroup(mpc, na, outDegree);
84 }
85
86 def MetricDistanceGroup calculateMetricDistance(PartialInterpretation partial){
87 val metrics = new ArrayList<Metric>();
88 metrics.add(new OutDegreeMetric());
89 metrics.add(new NodeActivityMetric());
90 metrics.add(new MultiplexParticipationCoefficientMetric());
91
92 val metricCalculator = new PartialInterpretationGraph(partial, metrics, null);
93 var metricSamples = metricCalculator.evaluateAllMetricsToSamples();
94
95 var mpc = js.mpcDistance(metricSamples.mpcSamples);
96 var na = js.naDistance(metricSamples.naSamples);
97 var outDegree = js.outDegreeDistance(metricSamples.outDegreeSamples);
98
99 return new MetricDistanceGroup(mpc, na, outDegree);
100 }
101
102 def resetRegression(Object state){
103 samples.clear();
104
105 if(stateAndHistory.containsKey(state)){
106 var data = stateAndHistory.get(state);
107
108 var curState = state;
109
110 samples.add(data);
111
112 while(stateAndHistory.containsKey(data.lastState) && data.lastState != curState){
113 curState = data.lastState;
114 data = stateAndHistory.get(data.lastState);
115 samples.add(data);
116 }
117
118 if(samples.size == 0){
119 println('state: ' + state);
120 println('last state: ' + data.lastState);
121 }
122 }
123 println("trajectory sample size:" + samples.size)
124 }
125
126 def feedData(Object state, double[] features, double value, Object lastState){
127 var data = new StateData(features, value, lastState);
128 stateAndHistory.put(state, data);
129 samples.add(data);
130 }
131
132 def getPredictionForNextDataSample(double[] features, double value, double[] featuresToPredict){
133 if(samples.size <= 4){
134 println('OK');
135 }
136 var data = new StateData(features, value, null);
137 samples.add(data);
138
139 // create training set from current data
140 var double[][] xSamples = samples.map[it.features];
141 var double[] ySamples = samples.map[it.value];
142
143
144 regression.newSampleData(ySamples, xSamples);
145 var prediction = predict(featuresToPredict);
146
147 //remove the last element just added
148 samples.remove(samples.size - 1);
149 return prediction;
150 }
151
152 def private predict(double[] featuresToPredict){
153 var parameters = regression.estimateRegressionParameters();
154 // the regression will add an initial column for 1's, the first parameter is constant term
155 var result = parameters.get(0);
156 for(var i = 0; i < featuresToPredict.length; i++){
157 result += parameters.get(i+1) * featuresToPredict.get(i);
158 }
159 return result;
160 }
161
162 def double[] calculateFeature(int step, int violations){
163 var features = newDoubleArrayOfSize(2);
164 //constant term
165 features.set(0, 1); //a
166 features.set(0, Math.sqrt(step) + 30) // b
167 features.set(1, 1.0 / (step + 30) );// c
168
169
170// features.set(2, violations);
171// features.set(3, Math.pow(violations, 2));
172
173 return features;
174 }
175}
176
177class MetricDistanceGroup{
178 var double mpcDistance;
179 var double naDistance;
180 var double outDegreeDistance;
181 var double nodeTypeDistance;
182 protected var HashMap<String, Double> nodeTypeInfo;
183
184 new(double mpcDistance, double naDistance, double outDegreeDistance, double nodeTypeDistance){
185 this.mpcDistance = mpcDistance;
186 this.naDistance = naDistance;
187 this.outDegreeDistance = outDegreeDistance;
188 this.nodeTypeDistance = nodeTypeDistance;
189 }
190
191 new(double mpcDistance, double naDistance, double outDegreeDistance){
192 this.mpcDistance = mpcDistance;
193 this.naDistance = naDistance;
194 this.outDegreeDistance = outDegreeDistance;
195 }
196
197 def double getNodeTypeDistance(){
198 return this.nodeTypeDistance;
199 }
200
201 def double getMPCDistance(){
202 return this.mpcDistance
203 }
204
205 def double getNADistance(){
206 return this.naDistance
207 }
208
209 def double getOutDegreeDistance(){
210 return this.outDegreeDistance
211 }
212
213 def double getNodeTypePercentage(String typeName){
214 return nodeTypeInfo.getOrDefault(typeName, 0.0);
215 }
216} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/CostDistance.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/CostDistance.xtend
new file mode 100644
index 00000000..613f0f43
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/CostDistance.xtend
@@ -0,0 +1,38 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance
2
3import java.text.DecimalFormat
4import java.util.HashMap
5import java.util.List
6import org.eclipse.xtend.lib.annotations.Accessors
7
8abstract class CostDistance {
9 def abstract double naDistance(List<Double> samples);
10 def abstract double mpcDistance(List<Double> samples);
11 def abstract double outDegreeDistance(List<Double> samples);
12
13 def protected pmfFromSamples(double[] samples, DecimalFormat formatter){
14 var length = samples.length;
15 var pmfMap = new HashMap<String, Double>();
16
17 for(sample : samples){
18 pmfMap.put(formatter.format(sample), pmfMap.getOrDefault(formatter.format(sample), 0.0) + 1.0 / length);
19 }
20
21 return pmfMap;
22 }
23}
24
25class StateData{
26 @Accessors(PUBLIC_GETTER)
27 var double[] features;
28 @Accessors(PUBLIC_GETTER)
29 var double value;
30 @Accessors(PUBLIC_GETTER)
31 var Object lastState;
32
33 new(double[] features, double value, Object lastState){
34 this.features = features;
35 this.value = value
36 this.lastState = lastState;
37 }
38} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/EuclideanDistance.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/EuclideanDistance.xtend
new file mode 100644
index 00000000..d6adcc9a
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/EuclideanDistance.xtend
@@ -0,0 +1,72 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app.Domain
4import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io.RepMetricsReader
5import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MetricSampleGroup
6import com.google.common.collect.Sets
7import java.text.DecimalFormat
8import java.util.ArrayList
9import java.util.HashMap
10import java.util.List
11import java.util.Map
12import java.util.Set
13
14class EuclideanDistance extends CostDistance{
15 var MetricSampleGroup g;
16 var HashMap<String, Double> mpcPMF;
17 var HashMap<String, Double> naPMF;
18 var HashMap<String, Double> outDegreePMF;
19 var DecimalFormat formatter;
20
21 new(MetricSampleGroup g){
22 this.g = g;
23
24 var mpcSamples = g.mpcSamples;
25 var naSamples = g.naSamples.stream.mapToDouble([it]).toArray();
26 var outDegreeSamples = g.outDegreeSamples.stream.mapToDouble([it]).toArray();
27
28 //needs to format the number to string avoid precision issue
29 formatter = new DecimalFormat("#0.00000");
30
31 mpcPMF = pmfFromSamples(mpcSamples, formatter);
32 naPMF = pmfFromSamples(naSamples, formatter);
33 outDegreePMF = pmfFromSamples(outDegreeSamples, formatter);
34 }
35
36 override naDistance(List<Double> samples) {
37 var pmfMap = pmfFromSamples(samples, formatter);
38 return euclideanDistance(pmfMap, naPMF);
39 }
40
41 override mpcDistance(List<Double> samples) {
42 var pmfMap = pmfFromSamples(samples, formatter);
43 return euclideanDistance(pmfMap, mpcPMF);
44 }
45
46 override outDegreeDistance(List<Double> samples) {
47 var pmfMap = pmfFromSamples(samples, formatter);
48 return euclideanDistance(pmfMap, outDegreePMF);
49 }
50
51
52 def private euclideanDistance(HashMap<String, Double> pmf1, HashMap<String, Double> pmf2){
53 var keys = Sets.union(pmf1.keySet(), pmf2.keySet());
54 var pmfList1 = pmfMapToList(pmf1, keys);
55 var pmfList2 = pmfMapToList(pmf2, keys);
56 var distance = 0.0;
57 for(var i = 0; i < pmfList1.size(); i++){
58 distance += Math.pow(pmfList1.get(i) + pmfList2.get(i), 2);
59 }
60
61 return Math.sqrt(distance);
62 }
63
64 def private pmfMapToList(Map<String, Double> map, Set<String> keys){
65 var list = new ArrayList<Double>();
66 for(key : keys){
67 var value = map.getOrDefault(key, 0.0);
68 list.add(value);
69 }
70 return list;
71 }
72} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/JSDistance.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/JSDistance.xtend
new file mode 100644
index 00000000..4a0a0dc3
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/JSDistance.xtend
@@ -0,0 +1,88 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MetricSampleGroup
4import com.google.common.collect.Sets
5import java.text.DecimalFormat
6import java.util.HashMap
7import java.util.List
8
9class JSDistance extends CostDistance {
10 var HashMap<String, Double> mpcPMF;
11 var HashMap<String, Double> naPMF;
12 var HashMap<String, Double> outDegreePMF;
13 var HashMap<String, Double> nodeTypesPMF;
14 var DecimalFormat formatter;
15
16 new(MetricSampleGroup g){
17 var mpcSamples = g.mpcSamples;
18 var naSamples = g.naSamples.stream.mapToDouble([it]).toArray();
19 var outDegreeSamples = g.outDegreeSamples.stream.mapToDouble([it]).toArray();
20
21 //needs to format the number to string avoid precision issue
22 formatter = new DecimalFormat("#0.00000");
23
24 mpcPMF = pmfFromSamples(mpcSamples, formatter);
25 naPMF = pmfFromSamples(naSamples, formatter);
26 outDegreePMF = pmfFromSamples(outDegreeSamples, formatter);
27 nodeTypesPMF = g.nodeTypeSamples;
28 }
29
30 def private combinePMF(HashMap<String, Double> pmf1, HashMap<String, Double> pmf2){
31 var pmfMap = new HashMap<String, Double>();
32
33 var union = Sets.union(pmf1.keySet(), pmf2.keySet());
34
35 for(key : union){
36 // corresponding to M in JS distance
37 var value = 1.0/2 * (pmf1.getOrDefault(key, 0.0) + pmf2.getOrDefault(key, 0.0));
38 pmfMap.put(key, value);
39 }
40 return pmfMap;
41 }
42
43 def private jsDivergence(HashMap<String, Double> p, HashMap<String, Double> q){
44 val m = combinePMF(q, p);
45 var distance = 1.0/2 * klDivergence(p, m) + 1.0/2 * klDivergence(q, m);
46 return distance;
47 }
48
49 def klDivergence(HashMap<String, Double> p, HashMap<String, Double> q){
50 var distance = 0.0;
51 for(key : q.keySet()){
52 //need to convert log e to log 2
53 if(p.containsKey(key)){
54 distance -= p.get(key) * Math.log(q.get(key) / p.get(key)) / Math.log(2);
55 }
56 }
57 return distance;
58 }
59
60 override double mpcDistance(List<Double> samples){
61 // map list to array
62 var map = pmfFromSamples(samples.stream().mapToDouble([it]).toArray(), formatter);
63 //if the size of array is smaller than 2, ks distance cannot be performed, simply return 1
64 if(map.size < 2) return 1;
65 return jsDivergence(map, mpcPMF);
66 }
67
68 override double naDistance(List<Double> samples){
69 // map list to array
70 var map = pmfFromSamples(samples.stream().mapToDouble([it]).toArray(), formatter);
71
72 //if the size of array is smaller than 2, ks distance cannot be performed, simply return 1
73 if(map.size < 2) return 1;
74 return jsDivergence(map, naPMF);
75 }
76
77 override double outDegreeDistance(List<Double> samples){
78 // map list to array
79 var map = pmfFromSamples(samples.stream().mapToDouble([it]).toArray(), formatter);
80 //if the size of array is smaller than 2, ks distance cannot be performed, simply return 1
81 if(map.size < 2) return 1;
82 return jsDivergence(map, outDegreePMF);
83 }
84
85 def nodeTypeDistance(HashMap<String, Double> samples){
86 return klDivergence(samples, nodeTypesPMF);
87 }
88} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/KSDistance.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/KSDistance.xtend
new file mode 100644
index 00000000..c486a328
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/distance/KSDistance.xtend
@@ -0,0 +1,102 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MetricSampleGroup
4import java.util.HashMap
5import java.util.HashSet
6import java.util.List
7import org.apache.commons.math3.stat.inference.KolmogorovSmirnovTest
8
9class KSDistance extends CostDistance {
10 var static ksTester = new KolmogorovSmirnovTest();
11 var MetricSampleGroup g;
12
13 new(MetricSampleGroup g){
14 this.g = g;
15 }
16 override double mpcDistance(List<Double> samples){
17 //if the size of array is smaller than 2, ks distance cannot be performed, simply return 1
18 if(samples.size < 2) return 1;
19 return ksTester.kolmogorovSmirnovStatistic(g.mpcSamples, samples);
20 }
21
22 override double naDistance(List<Double> samples){
23 //if the size of array is smaller than 2, ks distance cannot be performed, simply return 1
24 if(samples.size < 2) return 1;
25 return ksTester.kolmogorovSmirnovStatistic(g.naSamples as double[], samples);
26 }
27
28 override double outDegreeDistance(List<Double> samples){
29 //if the size of array is smaller than 2, ks distance cannot be performed, simply return 1
30 if(samples.size < 2) return 1;
31 return ksTester.kolmogorovSmirnovStatistic(g.outDegreeSamples, samples);
32 }
33
34 def double typedOutDegreeDistance(HashMap<String, List<Integer>> map){
35 var value = 0.0;
36 // map list to array
37 val keySet = new HashSet<String>(map.keySet);
38 keySet.addAll(g.typedOutDegreeSamples.keySet);
39 for(key : keySet){
40 if(!map.containsKey(key) ){
41 value += 1;
42 }else if(!g.typedOutDegreeSamples.containsKey(key)){
43 value += map.get(key).size * 100;
44 }else{
45 var double[] rep = g.typedOutDegreeSamples.get(key).stream().mapToDouble([it|it]).toArray();
46 var double[] ins = map.get(key).stream().mapToDouble([it|it]).toArray();
47 if((rep.size < 2 || ins.size < 2) ){
48 if(rep.size < 2 && rep.containsAll(ins)){
49 value += 0;
50 }else{
51 value += 1;
52 }
53 }else if(rep.size >= 2 && ins.size >= 2){
54 value += ksTester.kolmogorovSmirnovStatistic(rep, ins);
55 }
56 }
57 }
58
59
60 return value;
61 }
62
63 def nodeTypeDistance(HashMap<String, Double> samples){
64 var typesDistMap = g.nodeTypeSamples;
65 var sourceDist = newArrayList();
66 var instanceDist = newArrayList();
67
68 for(key : typesDistMap.keySet()){
69 sourceDist.add(typesDistMap.get(key));
70 instanceDist.add(samples.getOrDefault(key, 0.0));
71 }
72
73 return ks_distance_two_dist(sourceDist, instanceDist);
74 }
75
76 def edgeTypeDistance(HashMap<String, Double> samples){
77 var typesDistMap = g.edgeTypeSamples;
78 var sourceDist = newArrayList();
79 var instanceDist = newArrayList();
80
81 for(key : typesDistMap.keySet()){
82 sourceDist.add(typesDistMap.get(key));
83 instanceDist.add(samples.getOrDefault(key, 0.0));
84 }
85
86 return ks_distance_two_dist(sourceDist, instanceDist);
87 }
88
89 def double ks_distance_two_dist(List<Double> dist1, List<Double> dist2){
90 // Since we already know the pdf, we compute the ks-test manully
91 var ksStatistics = 0.0;
92 var sum1 = 0.0;
93 var sum2 = 0.0;
94 for(var i = 0; i < dist1.size(); i++){
95 sum1 += dist1.get(i);
96 sum2 += dist2.get(i);
97
98 ksStatistics = Math.max(ksStatistics, Math.abs(sum1 - sum2));
99 }
100 return ksStatistics;
101 }
102} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/EMFGraph.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/EMFGraph.xtend
new file mode 100644
index 00000000..8fa29fe6
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/EMFGraph.xtend
@@ -0,0 +1,124 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.Metric
4import java.util.ArrayList
5import java.util.HashSet
6import java.util.List
7import org.eclipse.emf.common.util.EList
8import org.eclipse.emf.ecore.EObject
9import org.eclipse.emf.ecore.EReference
10import org.eclipse.xtend.lib.annotations.Accessors
11
12class EMFGraph extends Graph{
13 @Accessors(PUBLIC_GETTER)
14 var EObject root;
15
16 def void init (EObject root, List<Metric> metrics, String name, List<EReference> referenceTypes){
17 val otherContents = root.eAllContents.toList();
18 this.root = root;
19 otherContents.add(root);
20 init(otherContents, metrics, name, referenceTypes);
21 }
22
23 /**
24 * init the graph with all nodes and reference types in the meta model
25 * @param objects: objects in the instance model (exclude root)
26 * @param metrics: metrics to be evaluated
27 * @param name: name of the instance model
28 * @param ReferenceTypes: reference types defined in the meta model
29 */
30 def void init(List<EObject> objects, List<Metric> metrics, String name, List<EReference> referenceTypes){
31 objects.forEach[it|
32 // TODO: Maybe want to consider all the super types as well
33 var types = new HashSet();
34 types.add(it.eClass.name);
35 statistic.addNodeWithAllTypes(it, types);
36 ]
37
38 referenceTypes.forEach[it|
39 // Only consider the edges that are not derived to preserve the statistical property
40 if(!it.derived){
41 statistic.addEdgeType(it.name);
42 }
43 ];
44
45 objects.forEach[source|
46 source.eClass.EAllReferences.forEach[r|
47 //many references
48 if(r.isMany){
49 source.getNeighbours(r).forEach[target|
50 addEdge(source, target, r);
51 ]
52 }else{
53 //single references
54 val target = source.eGet(r) as EObject;
55 addEdge(source, target, r);
56 }
57 ]
58 ]
59
60 this.metrics = metrics;
61 this.name = name;
62 }
63
64 def void removeReference(EReference r){
65 if (statistic.containsEdgeType(r.name)){
66 statistic.removeReference(r.name, r.containment);
67 }
68 }
69
70 /**
71 * Set basic information for the output
72 */
73 override setBasicInformation(ArrayList<ArrayList<String>> output){
74 val metaInfo = new ArrayList<String>();
75 metaInfo.add(META_MODEL_HEADER);
76 metaInfo.add(this.metaModel);
77
78 val edgeInfo = new ArrayList<String>();
79 edgeInfo.add(NUM_EDGE_TYPE_HEADER);
80 edgeInfo.add(this.statistic.allTypes.size()+"");
81
82 val nodeInfo = new ArrayList<String>();
83 nodeInfo.add(NUM_NODE_HEADER);
84 nodeInfo.add(this.statistic.allNodes.size()+"");
85
86 val stateInfo = new ArrayList<String>();
87 stateInfo.add(STATE_ID_HEADER);
88 stateInfo.add(this.name);
89
90
91 output.add(metaInfo);
92 output.add(edgeInfo);
93 output.add(nodeInfo);
94 output.add(stateInfo);
95 }
96
97 def EList<EObject> getNeighbours(EObject o, EReference r){
98 return (o.eGet(r, true) as EList<EObject>);
99 }
100
101 def addEdge(EObject source, EObject target, EReference r){
102 //Only add the edge if the reference is not derived to preserve the statistical property
103 if(target !== null && r !== null && !r.derived){
104 statistic.addEdge(source, target, r.name);
105 }
106 }
107
108 override GraphStatistic getStatistic(){
109 return this.statistic;
110 }
111
112 override String getName(){
113 return this.name;
114 }
115
116 def void setMetaModel(String model){
117 this.metaModel = model;
118 }
119
120 def String getMetaModel(){
121 return this.metaModel;
122 }
123
124} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/Graph.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/Graph.xtend
new file mode 100644
index 00000000..6b400b0d
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/Graph.xtend
@@ -0,0 +1,71 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.Metric
4import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MetricSampleGroup
5import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MultiplexParticipationCoefficientMetric
6import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.NodeActivityMetric
7import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.OutDegreeMetric
8import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.TypedOutDegree
9import java.util.ArrayList
10import java.util.HashMap
11import java.util.List
12import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.NodeTypeMetric
13import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.EdgeTypeMetric
14
15abstract class Graph {
16
17 protected static val String META_MODEL_HEADER = "Meta Mode"
18 protected static val String NUM_NODE_HEADER = "Number Of Nodes";
19 protected static val String NUM_EDGE_TYPE_HEADER = "Number of Edge types";
20 protected static val String STATE_ID_HEADER = "State Id";
21
22 protected val statistic = new GraphStatistic();
23 protected var List<Metric> metrics;
24 protected var String name = "";
25 protected var String metaModel = "";
26
27 /**
28 * evaluate all metrics for this model
29 * return the result as a two dimentional list
30 */
31 def ArrayList<ArrayList<String>> evaluateAllMetrics(){
32 val result = new ArrayList<ArrayList<String>>();
33 setBasicInformation(result);
34
35 for(metric : this.metrics){
36 val datas = metric.evaluate(this.statistic);
37 for(row : datas){
38 result.add(new ArrayList<String>(row));
39 }
40 }
41 return result;
42 }
43
44 def MetricSampleGroup evaluateAllMetricsToSamples(){
45 var sample = new MetricSampleGroup();
46
47 for(metric : this.metrics){
48 if(metric instanceof MultiplexParticipationCoefficientMetric){
49 sample.mpcSamples = metric.evaluateSamples(this.statistic) as ArrayList<Double>;
50 }else if(metric instanceof NodeActivityMetric){
51 sample.naSamples = metric.evaluateSamples(this.statistic) as ArrayList<Double>;
52 }else if(metric instanceof OutDegreeMetric){
53 sample.outDegreeSamples = metric.evaluateSamples(this.statistic) as ArrayList<Double>;
54 }else if(metric instanceof TypedOutDegree){
55 sample.typedOutDegreeSamples = metric.evaluateSamples(this.statistic) as HashMap<String, List<Integer>>;
56 }else if(metric instanceof NodeTypeMetric){
57 sample.nodeTypeSamples = metric.evaluateSamples(this.statistic) as HashMap<String, Double>;
58 }else if (metric instanceof EdgeTypeMetric){
59 sample.edgeTypeSamples = metric.evaluateSamples(this.statistic) as HashMap<String, Double>;
60 }
61 }
62
63 return sample;
64 }
65
66 def void setBasicInformation(ArrayList<ArrayList<String>> result);
67
68 def GraphStatistic getStatistic();
69
70 def String getName();
71} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/GraphStatistic.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/GraphStatistic.xtend
new file mode 100644
index 00000000..31788bb2
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/GraphStatistic.xtend
@@ -0,0 +1,194 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph
2
3import com.google.common.collect.ArrayListMultimap
4import com.google.common.collect.Multimap
5import java.util.HashMap
6import java.util.HashSet
7import java.util.List
8import java.util.Map
9import java.util.Set
10import org.eclipse.emf.ecore.EObject
11import org.eclipse.emf.ecore.EReference
12
13class GraphStatistic {
14 val incomingEdges = new HashMap<String, Multimap<EObject, EObject>>;
15 val outgoingEdges = new HashMap<String, Multimap<EObject, EObject>>;
16
17 val edgeTypes = new HashSet<String>();
18 val nodeToType = new HashMap<EObject, Set<String>>();
19
20 /**
21 * Add an edge type to to the graph
22 * @param type: type to add
23 */
24 def void addEdgeType(String type){
25 if(edgeTypes.contains(type)){
26 return;
27 }
28
29 edgeTypes.add(type);
30 incomingEdges.put(type, ArrayListMultimap.create());
31 outgoingEdges.put(type, ArrayListMultimap.create());
32 }
33
34 /**
35 * Add a node to the graph with one type in its type hierarchy
36 * @param node: node to add
37 */
38 def void addNodeWithType(EObject n, String Type){
39 var types = nodeToType.getOrDefault(n, new HashSet<String>());
40 types.add(Type);
41 nodeToType.put(n, types);
42 }
43
44 def boolean containsNode(EObject o){
45 return nodeToType.containsKey(o);
46 }
47
48 def Set<String> getTypesForNode(EObject o){
49 return nodeToType.getOrDefault(o, new HashSet<String>());
50 }
51
52 def void overwriteCurrentType(EObject o, String type){
53 var typeSet = nodeToType.getOrDefault(o, new HashSet<String>());
54
55 // clear current types
56 typeSet.clear();
57 typeSet.add(type);
58 nodeToType.put(o, typeSet);
59 }
60
61 /**
62 * Add a node to the graph with all types in its type hierarchy
63 */
64 def void addNodeWithAllTypes(EObject n, Set<String> types){
65 nodeToType.put(n, types);
66 }
67
68 /**
69 * Add an edge to the graph
70 * @param source: source node
71 * @param target: target node
72 * @param type: type of the reference
73 */
74 def void addEdge(EObject source, EObject target, String type){
75 outgoingEdges.get(type).put(source, target);
76 incomingEdges.get(type).put(target, source);
77 }
78
79 /**
80 * check if this graph contains a specific edge type
81 */
82 def boolean containsEdgeType(String typeName){
83 if(outgoingEdges.containsKey(typeName) && incomingEdges.containsKey(typeName)){
84 return true;
85 }
86 return false;
87 }
88
89 /**
90 * remove references from the statistics, potentially remove the nodes associated with it
91 * @Param name: name of the reference
92 * @Param isContainment: if true then the corresponding nodes on the incoming side will also be removed
93 */
94 def removeReference(String name, boolean isContainment){
95 if(!edgeTypes.contains(name)){
96 return;
97 }
98
99 edgeTypes.remove(name);
100 var incomingSet = incomingEdges.remove(name);
101 outgoingEdges.remove(name);
102
103 // if the reference is not a containment, then removing the reference is enough
104 if(!isContainment){
105 return;
106 }
107
108 // else remove all corresponding nodes
109 val nodesToRemove = incomingSet.keySet();
110
111 //remove nodes from node sets
112 nodesToRemove.forEach[nodeToType.remove(it)];
113
114 val removeForMultimap = [Multimap<EObject, EObject> refMap|
115 nodesToRemove.forEach[refMap.removeAll(it)];
116 var values = refMap.values()
117 //remove the values from the list is equavalent to remove it in the multimap
118 values.removeAll(nodesToRemove);
119 return;
120 ];
121
122 //remove nodes from all other references on incomingEdges
123 incomingEdges.values.forEach(removeForMultimap);
124 outgoingEdges.values.forEach(removeForMultimap);
125 }
126
127 /**
128 * calculate the out degree for an object
129 */
130 def int outDegree(EObject o){
131 var count = 0;
132
133 for (String type : edgeTypes){
134 count += outgoingEdges.get(type).get(o).size();
135 }
136 return count;
137 }
138
139 /**
140 * calculate the in degree of an object
141 */
142 def int inDegree(EObject o){
143 var count = 0;
144
145 for (String type : edgeTypes){
146 count += incomingEdges.get(type).get(o).size();
147 }
148 return count;
149 }
150
151 /**
152 * calculate the dimentional degree of a node
153 */
154 def int dimentionalDegree(EObject o, String type){
155 return incomingEdges.get(type).get(o).size() + outgoingEdges.get(type).get(o).size();
156 }
157
158 /**
159 * calculate the number of edge types for a given node.
160 */
161 def int numOfEdgeTypes(EObject o){
162 var count = 0;
163
164 for(String type : edgeTypes){
165 if(dimentionalDegree(o, type) > 0){
166 count++;
167 }
168 }
169
170 return count;
171 }
172
173 def List<String> getAllTypes(){
174 return edgeTypes.toList();
175 }
176
177 def Map<EObject, Set<String>> getNodeToTypesMap(){
178 return nodeToType;
179 }
180
181 def List<EObject> getAllNodes(){
182 return nodeToType.keySet().toList();
183 }
184
185 def HashMap<String, Multimap<EObject, EObject>> getOutgoingEdges(){
186 return outgoingEdges;
187 }
188
189 def HashMap<String, Multimap<EObject, EObject>> incomingEdges(){
190 return incomingEdges;
191 }
192
193}
194
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/PartialInterpretationGraph.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/PartialInterpretationGraph.xtend
new file mode 100644
index 00000000..a2934eb9
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/graph/PartialInterpretationGraph.xtend
@@ -0,0 +1,134 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.Metric
4import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration
5import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type
6import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDefinition
7import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.BinaryElementRelationLink
8import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation
9import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.impl.PartialComplexTypeInterpretationImpl
10import java.util.ArrayList
11import java.util.List
12
13class PartialInterpretationGraph extends Graph{
14 val typeToExclude = "undefinedpart";
15 val classSuffix = " class";
16
17 /**
18 * Define a new PartialInterpretationGraph by parse every element from a PartialInterpretation
19 */
20 new(PartialInterpretation partial, List<Metric> metrics, String name){
21 //the edge types are defined in terms of RelationDeclaration
22 partial.problem.relations.filter(RelationDeclaration).forEach[
23 //only need the name of the reference type (remove everything with and after "reference")
24 var n = it.name.split(" ").get(0);
25 this.statistic.addEdgeType(n);
26 ]
27 // add all elements
28 val typeInterpretations = getTypes(partial);
29 for(type : typeInterpretations){
30 //Only consider the most concrete class
31 if(isConcreteType(type.interpretationOf)){
32 var typeName = type.interpretationOf.name.replace(classSuffix, '');
33 for(node : type.elements){
34 if(!this.statistic.containsNode(node)){
35 this.statistic.addNodeWithType(node, typeName);
36 }else{
37 // if the current type of the node is a super type of the type to check,
38 // substitute the current type with the new type
39 var currentType = statistic.getTypesForNode(node).get(0);
40 if(isSuperType(currentType, type.interpretationOf)){
41 statistic.overwriteCurrentType(node, typeName);
42 }
43 }
44 }
45 }
46 }
47
48 for(relationInterpretation : partial.partialrelationinterpretation) {
49 //only need the name of the reference type (remove everything with and after "reference")
50 val type = relationInterpretation.interpretationOf.name.split(" ").get(0);
51 for(edge : relationInterpretation.relationlinks.filter(BinaryElementRelationLink)){
52 statistic.addEdge(edge.param1, edge.param2, type);
53 }
54 }
55
56 this.name = name;
57 this.metrics = metrics;
58 }
59
60 /**
61 * recursively check if a type is the super type of another
62 */
63 def boolean isSuperType(String typeName, Type subtypeToCheck){
64 var superTypes = subtypeToCheck.supertypes;
65 if(superTypes.size == 0){
66 return false;
67 }else if(subtypeToCheck.supertypes.map[it.name.replace(classSuffix, '')].contains(typeName)){
68 return true;
69 }else{
70 for(superType : superTypes){
71 if(isSuperType(typeName, superType)){
72 return true;
73 }
74 }
75 return false;
76 }
77 }
78
79 /**
80 * Check if a Type object is the class that we want to consider
81 * A type object is to be considered if it satisfy one of the following:
82 * 1. if it is not abstract
83 * 2. if it is abstract but has a subclass of type TypeDefinition (This means the generation is
84 * started with nodes in this type)
85 */
86 def boolean isConcreteType(Type t){
87 if(!t.isAbstract || t.subtypes.findFirst[it instanceof TypeDefinition] !== null){
88 return true;
89 }
90 return false;
91 }
92
93 /**
94 * Set basic information for the output
95 */
96 override setBasicInformation(ArrayList<ArrayList<String>> output){
97 val metaInfo = new ArrayList<String>();
98 metaInfo.add(META_MODEL_HEADER);
99 metaInfo.add(this.metaModel);
100
101 val edgeInfo = new ArrayList<String>();
102 edgeInfo.add(NUM_EDGE_TYPE_HEADER);
103 edgeInfo.add(this.statistic.allTypes.size()+"");
104
105 val nodeInfo = new ArrayList<String>();
106 nodeInfo.add(NUM_NODE_HEADER);
107 nodeInfo.add(this.statistic.allNodes.size()+"");
108
109 val stateInfo = new ArrayList<String>();
110 stateInfo.add(STATE_ID_HEADER);
111 stateInfo.add(this.name);
112
113 output.add(metaInfo);
114 output.add(edgeInfo);
115 output.add(nodeInfo);
116 output.add(stateInfo);
117 }
118
119 private def getTypes(PartialInterpretation partial){
120 //only the complex type interpretations are the ones defined in meta model
121 //do not care about undefined types as it will be included in the class type
122 return partial.partialtypeinterpratation.filter(PartialComplexTypeInterpretationImpl)
123 .filter[!it.interpretationOf.name.toLowerCase.contains(typeToExclude)];
124 }
125
126 override getStatistic() {
127 throw new UnsupportedOperationException("TODO: auto-generated method stub")
128 }
129
130 override getName() {
131 return name;
132 }
133
134} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/CsvFileWriter.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/CsvFileWriter.xtend
new file mode 100644
index 00000000..00b38d90
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/CsvFileWriter.xtend
@@ -0,0 +1,52 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io;
2
3import java.io.File
4import java.io.FileNotFoundException
5import java.io.FileOutputStream
6import java.io.PrintWriter
7import java.util.ArrayList
8import java.util.List
9
10class CsvFileWriter {
11
12 def static void write(ArrayList<ArrayList<String>> datas, String uri) {
13 if(datas.size() <= 0) {
14 return;
15 }
16 val PrintWriter writer = new PrintWriter(new File(uri));
17 output(writer, datas, uri);
18 }
19
20 def static void append(ArrayList<ArrayList<String>> datas, String uri) {
21 if(datas.size() <= 0) {
22 return;
23 }
24 val PrintWriter writer = new PrintWriter(new FileOutputStream(new File(uri), true));
25 output(writer, datas, uri);
26 }
27
28
29 def private static void output(PrintWriter writer, ArrayList<ArrayList<String>> datas, String uri) {
30 //println("Output csv for " + uri);
31 try {
32
33 val output = new StringBuilder;
34 for(List<String> datarow : datas){
35 for(var i = 0; i < datarow.size() - 1; i++){
36 output.append(datarow.get(i) + ',');
37 }
38
39 if(datarow.size >= 1){
40 output.append(datarow.get(datarow.size() - 1));
41 output.append('\n');
42 }
43 }
44
45 writer.write(output.toString());
46 writer.close();
47 //println("Output csv finished");
48 }catch(FileNotFoundException e) {
49 e.printStackTrace();
50 }
51 }
52}
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/GraphReader.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/GraphReader.xtend
new file mode 100644
index 00000000..053e0da3
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/GraphReader.xtend
@@ -0,0 +1,112 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io;
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.EMFGraph
4import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.EdgeTypeMetric
5import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.Metric
6import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MultiplexParticipationCoefficientMetric
7import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.NodeActivityMetric
8import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.NodeTypeMetric
9import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.OutDegreeMetric
10import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.TypedOutDegree
11import java.io.File
12import java.io.FileNotFoundException
13import java.util.ArrayList
14import java.util.List
15import org.eclipse.emf.common.util.URI
16import org.eclipse.emf.ecore.EObject
17import org.eclipse.emf.ecore.EPackage
18import org.eclipse.emf.ecore.EReference
19import org.eclipse.emf.ecore.resource.Resource
20import org.eclipse.emf.ecore.resource.ResourceSet
21import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl
22import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl
23import org.eclipse.emf.ecore.EGenericType
24import org.eclipse.emf.ecore.EStructuralFeature
25import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.TypedClusteringCoefficientMetric
26
27class GraphReader{
28 val ResourceSet resSet = new ResourceSetImpl();
29 val referenceTypes = new ArrayList<EReference>();
30 var String suffix;
31
32 new(EPackage metaModel, String suffix) {
33 Resource.Factory.Registry.INSTANCE.extensionToFactoryMap.put("*",new XMIResourceFactoryImpl)
34 this.suffix = suffix;
35
36 //find all reference types in the meta model
37 metaModel.eAllContents.forEach[
38 if(it instanceof EReference){
39 referenceTypes.add(it);
40 }
41 ]
42 }
43
44 def List<EMFGraph> readModels(String path){
45 val dir = new File(path);
46 if(!dir.isDirectory){
47 throw new Exception("expecting a directory");
48 }
49
50 val graphs = new ArrayList<EMFGraph>();
51
52 val metrics = new ArrayList<Metric>();
53 metrics.add(new OutDegreeMetric());
54 metrics.add(new NodeActivityMetric());
55 metrics.add(new MultiplexParticipationCoefficientMetric());
56 metrics.add(new TypedOutDegree());
57 metrics.add(new NodeTypeMetric());
58 metrics.add(new EdgeTypeMetric());
59 var count = 1
60 //check all files in the directory with suffix
61 for(String name : dir.list.filter[it| it.endsWith(suffix)]){
62 val file = new File(name);
63 val roots = readModel(EObject, path, file.name);
64 //add a list of metrics
65 val g = new EMFGraph();
66 for(root : roots){
67 g.init(root, metrics, name.replaceFirst(suffix, ""), referenceTypes);
68 }
69
70 count ++;
71 graphs.add(g);
72 }
73
74 return graphs;
75 }
76
77 def EMFGraph readModel(String path, String filename){
78 val metrics = new ArrayList<Metric>();
79 metrics.add(new OutDegreeMetric());
80 metrics.add(new NodeActivityMetric());
81 metrics.add(new MultiplexParticipationCoefficientMetric());
82 metrics.add(new TypedOutDegree());
83 metrics.add(new NodeTypeMetric());
84 metrics.add(new EdgeTypeMetric());
85
86 val file = new File(filename);
87 val roots = readModel(EObject, path, file.name);
88 //add a list of metrics
89 val g = new EMFGraph();
90 for(root : roots){
91 g.init(root, metrics, filename.replaceFirst(suffix, ""), referenceTypes);
92 }
93 return g
94 }
95
96 def <RootType extends EObject> List<RootType> readModel(Class<RootType> type, String path, String name) {
97 try {
98 val resource = resSet.getResource(getURI(path, name),true);
99 if(resource === null) throw new FileNotFoundException(getURI(path, name).toString)
100 else {
101 return resource.contents as List<RootType>
102 }
103 } catch(Exception e) {
104 e.printStackTrace();
105 throw new Exception(getURI(path, name).toString());
106 }
107 }
108
109 def static getURI(String path, String name) {
110 URI.createFileURI(path + "/" + name)
111 }
112} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/RepMetricsReader.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/RepMetricsReader.xtend
new file mode 100644
index 00000000..2e7be586
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/io/RepMetricsReader.xtend
@@ -0,0 +1,100 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app.Domain
4import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MetricSampleGroup
5import github.impl.GithubPackageImpl
6import hu.bme.mit.inf.dslreasoner.domains.yakindu.sgraph.yakindumm.impl.YakindummPackageImpl
7import java.util.HashMap
8import org.eclipse.emf.ecore.EReference
9import org.eclipse.emf.ecore.impl.EcorePackageImpl
10
11/**
12 * Read the sample of the distribution of a metric provided the csv file of the metric
13 */
14class RepMetricsReader {
15 static var Domain domain;
16 static def read(Domain d){
17 var GraphReader reader;
18 if(d == Domain.Yakindumm){
19 reader = new GraphReader(YakindummPackageImpl.eINSTANCE, '.xmi');
20 }else if (d == Domain.Ecore){
21 reader = new GraphReader(EcorePackageImpl.eINSTANCE, '.ecore');
22 }else if (d == Domain.Github){
23 reader = new GraphReader(GithubPackageImpl.eINSTANCE, '.githubmodel')
24 }
25
26 domain = d;
27
28 var domainRepPath = DataName.REP_PATH + d.name + '/';
29 var rep = new MetricSampleGroup()
30 var out_d = readMetrics(reader, domainRepPath + DataName.OUT_D_REP);
31 var mpc = readMetrics(reader, domainRepPath + DataName.MPC_REP);
32 rep.mpcSamples = mpc.mpcSamples;
33 rep.outDegreeSamples = out_d.outDegreeSamples;
34 rep.naSamples = readMetrics(reader, domainRepPath + DataName.NA_REP).naSamples;
35 rep.typedOutDegreeSamples = out_d.typedOutDegreeSamples;
36 rep.edgeTypeSamples = mpc.edgeTypeSamples;
37
38 //TODO: Parameterize the prior node distribution
39 var nodeTypeSamples = new HashMap<String, Double>();
40 if(d == Domain.Yakindumm){
41 nodeTypeSamples.put('Entry', 0.04257802080554814);
42 nodeTypeSamples.put('Choice', 0.1267671379034409);
43 nodeTypeSamples.put('State', 0.1596092291277674);
44 nodeTypeSamples.put('Transition', 0.6138636969858629);
45 nodeTypeSamples.put('Statechart', 0.010136036276340358);
46 nodeTypeSamples.put('Region', 0.04467858095492131);
47 nodeTypeSamples.put('Exit', 0.0018338223526273673);
48 nodeTypeSamples.put('FinalState', 0.0005334755934915977);
49 }else if(d ==Domain.Ecore){
50 nodeTypeSamples.put('EAttribute', 0.23539778449144008);
51 nodeTypeSamples.put('EClass', 0.33081570996978854);
52 nodeTypeSamples.put('EReference', 0.30996978851963747);
53 nodeTypeSamples.put('EPackage', 0.012789526686807653);
54 nodeTypeSamples.put('EAnnotation', 0.002517623363544813);
55 nodeTypeSamples.put('EEnumLiteral', 0.07275931520644502);
56 nodeTypeSamples.put('EEnum', 0.013645518630412891);
57 nodeTypeSamples.put('EDataType', 0.004028197381671702);
58 nodeTypeSamples.put('EParameter', 0.005941591137965764);
59 nodeTypeSamples.put('EGenericType', 0.002014098690835851);
60 nodeTypeSamples.put('EOperation', 0.009415911379657605);
61 nodeTypeSamples.put('ETypeParameter', 0.0007049345417925478);
62 }else if (d == Domain.Github){
63 nodeTypeSamples.put('Project', 0.012636538873420432);
64 nodeTypeSamples.put('Commit', 0.5525808524309276);
65 nodeTypeSamples.put('User', 0.05847076461769116);
66 nodeTypeSamples.put('Issue', 0.12743628185907047);
67 nodeTypeSamples.put('PullRequest', 0.07560505461554937);
68 nodeTypeSamples.put('IssueEvent', 0.17327050760334123);
69 }
70
71
72
73 rep.nodeTypeSamples = nodeTypeSamples;
74 return rep;
75 }
76
77 /**
78 * Read representative model
79 */
80 private static def readMetrics(GraphReader r, String path){
81 val model = r.readModels(path).head;
82 if(domain == Domain.Ecore){
83 var refsToRemove = EcorePackageImpl.eINSTANCE.eAllContents.filter(EReference).filter[
84 it.name.equals('eGenericType') || it.name.equals('eGenericSuperTypes') || it.name.equals('eFactoryInstance') ||
85 it.name.equals('eGenericExceptions') || it.name.equals('references') || it.name.equals('contents');
86 ];
87 refsToRemove.forEach[model.removeReference(it)];
88 }
89 return model.evaluateAllMetricsToSamples();
90 }
91
92}
93
94class DataName{
95 public static val REP_PATH = 'data/';
96 public static val MPC_REP = 'mpc_rep';
97 public static val NA_REP = 'na_rep';
98 public static val OUT_D_REP = 'out_d_rep';
99}
100
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/EdgeTypeMetric.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/EdgeTypeMetric.xtend
new file mode 100644
index 00000000..0c0fe3b8
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/EdgeTypeMetric.xtend
@@ -0,0 +1,41 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.GraphStatistic
4import java.util.ArrayList
5import java.util.HashMap
6
7class EdgeTypeMetric extends Metric {
8
9 override evaluate(GraphStatistic g) {
10 var map = evaluateSamples(g) as HashMap<String, Double>;
11 var output = new ArrayList<String[]>();
12 output.add(newArrayList('Edge Type'));
13
14 var keys = map.keySet;
15 var values = newArrayList();
16 for(key : keys){
17 values.add(map.get(key)+'');
18 }
19
20 output.add(keys);
21 output.add(values);
22
23 return output;
24 }
25
26 override evaluateSamples(GraphStatistic g) {
27 val map = new HashMap<String, Double>();
28 var outgoingEdges = g.outgoingEdges;
29
30 //get the total number of edges
31 val edgeCount = outgoingEdges.values.fold(0, [r, t| r + t.asMap.values.fold(0, [r1, t1| r1 + t1.size])]) as double;
32 outgoingEdges.forEach[k, v|
33 var value = v.asMap.values.fold(0, [r, t| r + t.size]) / edgeCount;
34 map.put(k, value);
35 ]
36
37
38 return map;
39 }
40
41} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/Metric.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/Metric.xtend
new file mode 100644
index 00000000..cb242a5b
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/Metric.xtend
@@ -0,0 +1,8 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.GraphStatistic
4
5abstract class Metric {
6 abstract def String[][] evaluate(GraphStatistic g);
7 abstract def Object evaluateSamples(GraphStatistic g);
8} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/MetricSampleGroup.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/MetricSampleGroup.xtend
new file mode 100644
index 00000000..4e25bb86
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/MetricSampleGroup.xtend
@@ -0,0 +1,13 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import java.util.HashMap
4import java.util.List
5
6class MetricSampleGroup{
7 public var List<Double> mpcSamples;
8 public var List<Double> naSamples;
9 public var List<Double> outDegreeSamples;
10 public var HashMap<String, List<Integer>> typedOutDegreeSamples;
11 public var HashMap<String, Double> nodeTypeSamples;
12 public var HashMap<String, Double> edgeTypeSamples;
13} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/MultiplexParticipationCoefficientMetric.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/MultiplexParticipationCoefficientMetric.xtend
new file mode 100644
index 00000000..eafa49b2
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/MultiplexParticipationCoefficientMetric.xtend
@@ -0,0 +1,80 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.GraphStatistic
4import java.text.DecimalFormat
5import java.util.ArrayList
6import java.util.HashMap
7import org.eclipse.emf.ecore.EObject
8
9class MultiplexParticipationCoefficientMetric extends Metric {
10 public static val countName = "MPCCount";
11 public static val valueName = "MPCValue";
12 val formatter = new DecimalFormat("#0.00000");
13
14 override evaluate(GraphStatistic g) {
15 //because the precision issue of double, we translate double values into String to be the key
16
17
18 //get number of different types
19 val typeCounts = g.allTypes.size;
20 val map = new HashMap<String, Integer>();
21 //calculate the metric distribution
22 g.allNodes.forEach[n|
23 var coef = calculateMPC(n, g, typeCounts);
24
25 //format number to String
26 val value = formatter.format(coef);
27 if(!map.containsKey(value)){
28 map.put(value, 1);
29 }else{
30 map.put(value, map.get(value) + 1);
31 }
32
33 ]
34
35 //convert it into a 2 dimentional array
36 val String[][] datas = newArrayOfSize(2, map.size+1);
37 datas.get(0).set(0, valueName);
38 datas.get(1).set(0, countName)
39 var count = 1;
40 for(entry : map.entrySet.sortBy[it.key]){
41 datas.get(0).set(count, entry.key+"");
42 datas.get(1).set(count, entry.value+"");
43 count++;
44 }
45
46 return datas;
47 }
48
49 override evaluateSamples(GraphStatistic g){
50 val samples = new ArrayList<Double>();
51 val typeCounts = g.allTypes.size;
52 //calculate the metric distribution
53 g.allNodes.forEach[
54 samples.add(calculateMPC(it, g, typeCounts));
55 ]
56
57 return samples;
58 }
59
60 def double calculateMPC(EObject n, GraphStatistic g, int typeCounts){
61 val edgeCounts = g.outDegree(n) + g.inDegree(n);
62
63 var coef = 0.0;
64
65 for(type : g.allTypes){
66 val degree = g.dimentionalDegree(n, type) as double;
67 coef += Math.pow(degree / edgeCounts, 2);
68 }
69 coef = 1 - coef;
70 coef = coef * typeCounts / (typeCounts-1);
71
72 //Consider the case that either typeCounts-1 or the edgeCounts could be 0 in some situation
73 //in this case the metric should be evaluated to 0
74 if(Double.isNaN(coef)){
75 coef = 0;
76 }
77
78 return Double.parseDouble(formatter.format(coef));
79 }
80} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/NodeActivityMetric.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/NodeActivityMetric.xtend
new file mode 100644
index 00000000..fbf06c47
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/NodeActivityMetric.xtend
@@ -0,0 +1,49 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.GraphStatistic
4import java.util.ArrayList
5import java.util.HashMap
6
7class NodeActivityMetric extends Metric {
8 public static val countName = "NACount";
9 public static val valueName = "NAValue";
10
11 override evaluate(GraphStatistic g) {
12 val map = new HashMap<Integer, Integer>();
13
14 //calculate the metric distribution
15 g.allNodes.forEach[
16 val value = g.numOfEdgeTypes(it);
17 if(!map.containsKey(value)){
18 map.put(value, 1);
19 }else{
20 map.put(value, map.get(value) + 1);
21 }
22 ]
23
24 //convert it into a 2 dimentional array
25 val String[][] datas = newArrayOfSize(2, map.size+1);
26 datas.get(0).set(0, valueName);
27 datas.get(1).set(0, countName)
28
29 var count = 1;
30 for(entry : map.entrySet.sortBy[it.key]){
31 datas.get(0).set(count, entry.key+"");
32 datas.get(1).set(count, entry.value+"");
33 count++;
34 }
35
36 return datas;
37 }
38
39 override evaluateSamples(GraphStatistic g){
40 val samples = new ArrayList<Double>();
41
42 //calculate the metric distribution
43 g.allNodes.forEach[
44 samples.add(g.numOfEdgeTypes(it) as double);
45 ]
46
47 return samples;
48 }
49} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/NodeTypeMetric.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/NodeTypeMetric.xtend
new file mode 100644
index 00000000..7cec2513
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/NodeTypeMetric.xtend
@@ -0,0 +1,42 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.GraphStatistic
4import java.util.ArrayList
5import java.util.HashMap
6
7class NodeTypeMetric extends Metric {
8
9
10 override evaluate(GraphStatistic g) {
11 var map = evaluateSamples(g) as HashMap<String, Double>;
12 var output = new ArrayList<String[]>();
13 output.add(newArrayList('Node Type'));
14 var keys = map.keySet;
15 var values = newArrayList();
16
17 for(key : keys){
18 values.add(map.get(key)+'');
19 }
20
21 output.add(keys);
22 output.add(values);
23
24 return output;
25 }
26
27 override evaluateSamples(GraphStatistic g) {
28 var map = new HashMap<String, Double>();
29 var nodes = g.allNodes;
30 var single = 1.0 / nodes.size();
31 var nodeToType = g.nodeToTypesMap;
32 for(node : nodes){
33 for(cl : nodeToType.get(node)){
34 var value = map.getOrDefault(cl, 0.0);
35 map.put(cl, value + single);
36 }
37 }
38
39 return map;
40 }
41
42} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/OutDegreeMetric.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/OutDegreeMetric.xtend
new file mode 100644
index 00000000..55046b14
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/OutDegreeMetric.xtend
@@ -0,0 +1,49 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.GraphStatistic
4import java.util.ArrayList
5import java.util.HashMap
6
7class OutDegreeMetric extends Metric {
8 public static val countName = "OutDegreeCount";
9 public static val valueName = "OutDegreeValue";
10
11 override evaluate(GraphStatistic g) {
12 val map = new HashMap<Integer, Integer>();
13
14 //calculate the metric distribution
15 g.allNodes.forEach[
16 val value = g.outDegree(it);
17 if(!map.containsKey(value)){
18 map.put(value, 1);
19 }else{
20 map.put(value, map.get(value) + 1);
21 }
22 ]
23
24 //convert it into a 2 dimentional array
25 val String[][] datas = newArrayOfSize(2, map.size+1);
26 datas.get(0).set(0, valueName);
27 datas.get(1).set(0, countName)
28 var count = 1;
29 for(entry : map.entrySet.sortBy[it.key]){
30 datas.get(0).set(count, entry.key+"");
31 datas.get(1).set(count, entry.value+"");
32 count++;
33 }
34
35 return datas;
36 }
37
38 override evaluateSamples(GraphStatistic g){
39 val samples = new ArrayList<Double>();
40
41 //calculate the metric distribution
42 g.allNodes.forEach[
43 samples.add(g.outDegree(it) as double);
44 ]
45
46 return samples;
47 }
48
49} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/TypedClusteringCoefficientMetric.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/TypedClusteringCoefficientMetric.xtend
new file mode 100644
index 00000000..0b6d61c6
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/TypedClusteringCoefficientMetric.xtend
@@ -0,0 +1,99 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.GraphStatistic
4import java.text.DecimalFormat
5import java.util.ArrayList
6import java.util.HashMap
7import java.util.HashSet
8import org.eclipse.emf.ecore.EObject
9
10class TypedClusteringCoefficientMetric extends Metric {
11 public static val countName = "TCCCount";
12 public static val valueName = "TCCValue";
13 val formatter = new DecimalFormat("#0.00000");
14
15 override evaluate(GraphStatistic g) {
16 //because the precision issue of double, we translate double values into String to be the key
17
18 val map = new HashMap<String, Integer>();
19 //calculate the metric distribution
20 g.allNodes.forEach[n|
21 var coef = calculateTCC1(n, g);
22 if(coef > 0){
23 println(n);
24 }
25 //format number to String
26 val value = formatter.format(coef);
27 if(!map.containsKey(value)){
28 map.put(value, 1);
29 }else{
30 map.put(value, map.get(value) + 1);
31 }
32
33 ]
34
35 //convert it into a 2 dimentional array
36 val String[][] datas = newArrayOfSize(2, map.size+1);
37 datas.get(0).set(0, valueName);
38 datas.get(1).set(0, countName)
39 var count = 1;
40 for(entry : map.entrySet.sortBy[it.key]){
41 datas.get(0).set(count, entry.key+"");
42 datas.get(1).set(count, entry.value+"");
43 count++;
44 }
45
46 return datas;
47 }
48
49 override evaluateSamples(GraphStatistic g){
50 val samples = new ArrayList<Double>();
51 //calculate the metric distribution
52 g.allNodes.forEach[
53 samples.add(calculateTCC1(it, g));
54 ]
55
56 return samples;
57 }
58
59 /**
60 * Compute TCC1 metric for node n
61 */
62 def double calculateTCC1(EObject n, GraphStatistic g){
63 var wedges = 0;
64 var triangles = 0;
65
66 for(type1 : g.allTypes){
67 val typed1RelatedOfN = new HashSet<EObject>(g.outgoingEdges.get(type1).get(n));
68 val type1EdgeSourceNodesOfN = new HashSet<EObject>(g.incomingEdges.get(type1).get(n));
69
70 typed1RelatedOfN.addAll(type1EdgeSourceNodesOfN);
71
72
73
74 // number of wedges
75 val d = typed1RelatedOfN.size
76 wedges += d * (d-1) // we will also count each closed triangle twice
77
78 // pairs of neighbors
79 for (n1: typed1RelatedOfN) {
80 for (n2: typed1RelatedOfN) {
81 for(type2 : g.allTypes){
82 if ((type1 != type2) &&
83 (g.outgoingEdges.get(type2).containsEntry(n1, n2) ||
84 g.outgoingEdges.get(type2).containsEntry(n2, n1)
85 )) {
86 triangles++
87 }
88 }
89 }
90 }
91 }
92
93 if (wedges == 0.0) {
94 return 0.0
95 } else {
96 return (triangles as double)/wedges
97 }
98 }
99} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/TypedOutDegree.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/TypedOutDegree.xtend
new file mode 100644
index 00000000..3b5dbcc5
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/metrics/TypedOutDegree.xtend
@@ -0,0 +1,60 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.GraphStatistic
4import java.util.ArrayList
5import java.util.HashMap
6import java.util.List
7
8class TypedOutDegree extends Metric{
9
10 def private calculateMetric(GraphStatistic g){
11 var outgoingEdges = g.outgoingEdges;
12 //record metric as a list of samples for each node type / edge type pair
13 var metric = new HashMap<String, List<Integer>>();
14 var nodeToTypes = g.nodeToTypesMap;
15
16 for(edgeType : outgoingEdges.keySet){
17 for(node : outgoingEdges.get(edgeType).keySet){
18 //find all classes the node belongs to
19 var classes = nodeToTypes.get(node);
20 for(cl : classes){
21 // get or create entry for node type / edge type pair
22 var key = cl + ' ' + edgeType;
23 var typeCount = metric.get(key);
24 if(typeCount === null){
25 typeCount = new ArrayList<Integer>();
26 metric.put(key, typeCount);
27 }
28
29 // get or create sample list
30 typeCount.add(outgoingEdges.get(edgeType).get(node).size);
31 }
32 }
33 }
34
35 return metric;
36 }
37
38 override evaluate(GraphStatistic g) {
39 var metric = calculateMetric(g);
40 var output = new ArrayList<String[]>();
41
42 output.add(newArrayList('Typed Out Degree'));
43 for(key : metric.keySet){
44 var samples = metric.get(key);
45 var String[] outputForOnePair = newArrayOfSize(samples.size+1);
46 outputForOnePair.set(0, key);
47 for(var i = 0; i < samples.size; i++){
48 outputForOnePair.set(i+1, samples.get(i)+'');
49 }
50 output.add(outputForOnePair);
51 }
52
53 return output;
54 }
55
56 override evaluateSamples(GraphStatistic g) {
57 return calculateMetric(g);
58 }
59
60} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/predictor/LinearModel.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/predictor/LinearModel.xtend
new file mode 100644
index 00000000..f0ded347
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/predictor/LinearModel.xtend
@@ -0,0 +1,91 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.predictor
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.distance.StateData
4import java.util.ArrayList
5import java.util.HashMap
6import java.util.List
7import java.util.Map
8import weka.core.matrix.LinearRegression
9import weka.core.matrix.Matrix
10
11class LinearModel {
12 var double ridge;
13 var Map<Object, StateData> stateAndHistory;
14 List<StateData> samples;
15
16 new(double ridge){
17 this.ridge = ridge;
18 stateAndHistory = new HashMap<Object, StateData>();
19 samples = new ArrayList<StateData>();
20 }
21
22 /**
23 * reset the current train data for regression to a new trajectory
24 * @param state: the last state of the trajectory
25 */
26 def resetRegression(Object state){
27 samples.clear();
28
29 if(stateAndHistory.containsKey(state)){
30 var data = stateAndHistory.get(state);
31 var curState = state;
32
33 samples.add(data);
34
35 //loop through data until the oldest state in the record
36 while(stateAndHistory.containsKey(data.lastState) && data.lastState != curState){
37 curState = data.lastState;
38 data = stateAndHistory.get(data.lastState);
39 samples.add(data);
40 }
41 }
42 }
43
44 /**
45 * Add a new data point to the current training set
46 * @param state: the state on which the new data point is calculated
47 * @param features: the set of feature value(x)
48 * @param value: the value of the state (y)
49 * @param lastState: the state which transformed to current state, used to record the trajectory
50 */
51 def feedData(Object state, double[] features, double value, Object lastState){
52 var data = new StateData(features, value, lastState);
53 stateAndHistory.put(state, data);
54 samples.add(data);
55 }
56
57 /**
58 * get prediction for next state, without storing the data point into the training set
59 * @param features: the feature values of current state
60 * @param value: the value of the current state
61 * @param: featuresToPredict: the features of the state wanted to be predected
62 * @return the value of the state to be predicted
63 */
64 def double getPredictionForNextDataSample(double[] features, double value, double[] featuresToPredict){
65 var data = new StateData(features, value, null);
66 samples.add(data);
67
68 // create training set from current data
69 val double[][] xSamples = samples.map[it.features];
70 val double[] ySamples = samples.map[it.value];
71
72 val x = new Matrix(xSamples);
73 val y = new Matrix(ySamples, ySamples.size());
74
75 val regression = new LinearRegression(x, y, ridge);
76 var prediction = predict(regression.coefficients, featuresToPredict);
77
78 //remove the last element just added
79 samples.remove(samples.size - 1);
80 return prediction;
81 }
82
83 def private predict(double[] parameters, double[] featuresToPredict){
84 // the regression will add an initial column for 1's, the first parameter is constant term
85 var result = parameters.get(0);
86 for(var i = 0; i < featuresToPredict.length; i++){
87 result += parameters.get(i) * featuresToPredict.get(i);
88 }
89 return result;
90 }
91} \ No newline at end of file
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ConstraintCollection.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ConstraintCollection.xtend
new file mode 100644
index 00000000..685c5836
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ConstraintCollection.xtend
@@ -0,0 +1,80 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.validation
2
3import java.util.ArrayList
4import java.util.HashMap
5import java.util.List
6import java.util.Map
7import org.eclipse.emf.common.notify.Notifier
8import org.eclipse.emf.common.util.URI
9import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl
10import org.eclipse.viatra.addon.validation.core.api.IConstraintSpecification
11import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine
12import org.eclipse.viatra.query.runtime.api.impl.BaseGeneratedPatternGroup
13import org.eclipse.viatra.query.runtime.emf.EMFScope
14
15class ConstraintCollection{
16 val constraints = new ArrayList<IConstraintSpecification>();
17 var BaseGeneratedPatternGroup patterns;
18 var List<Notifier> resources = new ArrayList<Notifier>();
19
20
21 new(List<IConstraintSpecification> constraints, List<String> uris, BaseGeneratedPatternGroup patterns){
22 this.constraints.addAll(constraints);
23 this.patterns = patterns;
24 setURIs(uris);
25 }
26
27 new(List<IConstraintSpecification> constraints, BaseGeneratedPatternGroup patterns){
28 this.constraints.addAll(constraints);
29 this.patterns = patterns;
30 }
31
32 def addModel(Notifier n ){
33 resources.add(n);
34 }
35
36 def setURIs(List<String> uris){
37 val resSet = new ResourceSetImpl();
38
39 for(uri : uris){
40 var resource = resSet.getResource(URI.createURI(uri), true);
41 resources.add(resource);
42 }
43
44 println('reading model finished')
45 }
46
47 def List<Integer> calculateViolations(){
48 var results = new ArrayList<Integer>();
49
50 for(resource : resources){
51 val engine = initEngine(resource);
52 var matches = constraints.stream.mapToInt([ele| ele.querySpecification.getMatcher(engine).countMatches]).sum();
53 results.add(matches);
54 }
55
56 return results;
57 }
58
59 def ArrayList<Map<String, Integer>> calculateViolationMaps(){
60 val result = new ArrayList<Map<String, Integer>>()
61
62 for(resource : resources){
63 val map = new HashMap<String, Integer>();
64 val engine = initEngine(resource);
65 constraints.forEach[
66 var count = it.querySpecification.getMatcher(engine).countMatches;
67 map.put(it.querySpecification.simpleName, count);
68 ];
69 result.add(map);
70 }
71 return result;
72 }
73
74 private def initEngine(Notifier r){
75 var engine = ViatraQueryEngine.on(new EMFScope(r));
76 //init patterns with the new engine
77 patterns.prepare(engine);
78 return engine;
79 }
80}
diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ViolationCheck.xtend b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ViolationCheck.xtend
new file mode 100644
index 00000000..4db5f940
--- /dev/null
+++ b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ViolationCheck.xtend
@@ -0,0 +1,66 @@
1package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.validation
2
3import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app.Domain
4import com.google.common.reflect.ClassPath
5import ecore.Ecore
6import hu.bme.mit.inf.dslreasoner.partialsnapshot_mavo.yakindu.Patterns
7import java.util.ArrayList
8import org.eclipse.emf.ecore.EObject
9import org.eclipse.viatra.addon.validation.core.api.IConstraintSpecification
10
11class ViolationCheck {
12 /**
13 * Return the total number of violations
14 */
15 def static int calculateViolationCounts(EObject root, Domain d){
16 var packageName = '';
17 if(d == Domain.Yakindumm){
18 packageName = 'constraints.yakindumm';
19 }else if (d == Domain.Ecore){
20 packageName = 'constraints.ecore';
21 }else if (d == Domain.Github){
22 return -1;
23 }
24
25 var constriants = loadConstraints(packageName);
26 var collections = new ConstraintCollection(constriants, Ecore.instance);
27 collections.addModel(root);
28 var results = collections.calculateViolations();
29 if(results.size > 0){
30 return results.get(0);
31 }else{
32 throw new IllegalArgumentException("Calculate Violation Failed");
33 }
34 }
35
36 /**
37 * return a map contain the count for each type of violation
38 */
39 def static violationMaps(EObject root){
40 var constriants = loadConstraints('hu.bme.mit.inf.dslreasoner.partialsnapshot_mavo.yakindu');
41 var collections = new ConstraintCollection(constriants, Patterns.instance);
42 collections.addModel(root);
43 var results = collections.calculateViolationMaps();
44 if(results.size > 0){
45 return results.get(0);
46 }else{
47 throw new IllegalArgumentException("Calculate Violation Failed");
48 }
49 }
50
51 def static loadConstraints(String packageName){
52 val constraints = new ArrayList<IConstraintSpecification>();
53
54 val classPath = ClassPath.from(ClassLoader.systemClassLoader);
55 val classInfos = classPath.getTopLevelClasses(packageName);
56 for(info : classInfos){
57 if(info.load.interfaces.contains(IConstraintSpecification)){
58 //IConstraintSpecification only has one constructor with empty argument list
59 var constructor = info.load.constructors.get(0);
60 var instance = constructor.newInstance();
61 constraints.add(instance as IConstraintSpecification);
62 }
63 }
64 return constraints
65 }
66}