From c33f0b9c4e112ee573d1b26d205a253cc0e487f8 Mon Sep 17 00:00:00 2001 From: 20001LastOrder Date: Thu, 8 Aug 2019 16:45:45 -0400 Subject: Configurations for generation and new domain for generation ecore model --- .../realistic/metrics/calculator/app/Domain.xtend | 4 +- .../realistic/metrics/calculator/app/Main.xtend | 71 ++++++++++++------- .../app/PartialInterpretationMetricDistance.xtend | 10 ++- .../realistic/metrics/calculator/app/Test.java | 31 --------- .../metrics/calculator/distance/KSDistance.xtend | 23 ++++++- .../metrics/calculator/graph/EMFGraph.xtend | 38 +++++----- .../metrics/calculator/graph/GraphStatistic.xtend | 79 ++++++++++++++++++--- .../graph/PartialInterpretationGraph.xtend | 60 +++++++++++++--- .../metrics/calculator/io/GraphReader.xtend | 9 ++- .../metrics/calculator/io/RepMetricsReader.xtend | 59 ++++++++++++---- .../MultiplexParticipationCoefficientMetric.xtend | 6 +- .../validation/ConstraintCollection.xtend | 80 ++++++++++++++++++++++ .../calculator/validation/ViolationCheck.xtend | 69 +++++++++++++++++++ 13 files changed, 420 insertions(+), 119 deletions(-) delete mode 100644 Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Test.java create mode 100644 Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ConstraintCollection.xtend create mode 100644 Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/validation/ViolationCheck.xtend (limited to 'Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic') 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 index 8351e96b..c8fd435b 100644 --- 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 @@ -1,5 +1,7 @@ package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app enum Domain{ - Yakinduum + Yakindumm, + Ecore, + Github } \ 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 index 062d69fa..ab187b3a 100644 --- 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 @@ -3,13 +3,25 @@ package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph.EMFGraph import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io.CsvFileWriter import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.io.GraphReader +import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.validation.ViolationCheck import hu.bme.mit.inf.dslreasoner.domains.yakindu.sgraph.yakindumm.impl.YakindummPackageImpl +import java.io.File import java.util.ArrayList +import org.eclipse.emf.ecore.EPackage import org.eclipse.emf.ecore.EcorePackage +import org.eclipse.viatra.query.runtime.rete.matcher.ReteEngine +import org.eclipse.emf.ecore.impl.EcorePackageImpl +import org.eclipse.emf.ecore.EReference //import yakindumm2.impl.Yakindumm2PackageImpl class Main { + var static Domain d = Domain.Ecore; + val static String suffix = '.ecore' + val static String OUTPUT_FOLDER = "Inputs/human/"; + val static String INPUT_FOLDER = "outputs/human/"; + val static int NUM_RUNS = 1; + static class RWInformation{ public var String inputFolder; public var String outputFolder; @@ -24,36 +36,32 @@ class Main { def static void main(String[] args){ //init model - YakindummPackageImpl.eINSTANCE.eClass; - EcorePackage.eINSTANCE.eClass; -// Yakindumm2PackageImpl.eINSTANCE.eClass; - //val infos = initData(); - - println("Start Reading Models..."); - var reader = new GraphReader(EcorePackage.eINSTANCE, ".xmi"); -// for(info : infos){ -// calculateAllModels(info.inputFolder, info.outputFolder,info.numRuns, reader); -// } + var EPackage metamodel; - //human input has different package declaration -// reader = new GraphReader(Yakindumm2PackageImpl.eINSTANCE); - val human = new RWInformation("Inputs/viatra75/", "outputs/", 50); - calculateAllModels(human.inputFolder, human.outputFolder,human.numRuns, reader); + //init viatra engine for the violation checker + ReteEngine.getClass(); + if(d == Domain.Yakindumm){ + YakindummPackageImpl.eINSTANCE.eClass; + metamodel = YakindummPackageImpl.eINSTANCE; + }else if (d == Domain.Ecore){ + EcorePackage.eINSTANCE.eClass; + metamodel = EcorePackageImpl.eINSTANCE; + }else if (d == Domain.Github){ + //TODO: Initialize Github Package + } + + println("Start Reading Models..."); + var reader = new GraphReader(metamodel, suffix); + + val models = new RWInformation(OUTPUT_FOLDER, INPUT_FOLDER, NUM_RUNS); + calculateAllModels(models.inputFolder, models.outputFolder,models.numRuns, reader); println("finished"); } - static def initData(){ - val infos = new ArrayList(); - infos.add(new RWInformation("inputs/alloyInput/models/", "../plot/statistics/alloyOutput/", 20)); - infos.add(new RWInformation("inputs/randomInput/models/", "../plot/statistics/randomOutput/", 20)); - infos.add(new RWInformation("inputs/viatraInput30/", "../plot/statistics/viatraOutput30/", 20)); - infos.add(new RWInformation("inputs/viatraInput100/", "../plot/statistics/viatraOutput100/", 10)); - return infos; - } - static def calculateAllModels(String inputFolder, String outputFolder, int numRuns, GraphReader reader){ + (new File(outputFolder)).mkdir(); for(var i = 1; i <= numRuns; i++){ val models = new ArrayList(); models.addAll(reader.readModels(inputFolder + "run" + i)); @@ -67,8 +75,21 @@ class Main { } static def calculateAndOutputMetrics(EMFGraph model, String metaModel, String fileName){ - //println("evaluating for " + model.name); + //println("evaluating for " + model.name); model.metaModel = metaModel; - CsvFileWriter.write(model.evaluateAllMetrics(), fileName); + + //remove eGenericType for Ecore domain + if(d == Domain.Ecore){ + var refsToRemove = EcorePackageImpl.eINSTANCE.eAllContents.filter(EReference).filter[ + it.name.equals('eGenericType') || it.name.equals('eGenericSuperTypes') || it.name.equals('eFactoryInstance')|| + it.name.equals('eGenericExceptions') || it.name.equals('references') || it.name.equals('contents'); + ]; + refsToRemove.forEach[model.removeReference(it)]; + } + + var outputs = model.evaluateAllMetrics(); + var violationsOutput = newArrayList('violations', ViolationCheck.calculateViolationCounts(model.root, d)+''); + outputs.add(violationsOutput); + CsvFileWriter.write(outputs, fileName); } } \ 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 index 66dcdff6..b2288f52 100644 --- 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 @@ -20,6 +20,7 @@ import java.util.List import java.util.Map import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression import org.eclipse.xtend.lib.annotations.Accessors +import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.EdgeTypeMetric class PartialInterpretationMetricDistance { @@ -34,8 +35,8 @@ class PartialInterpretationMetricDistance { var LinearModel linearModel; - new(){ - var metrics = RepMetricsReader.read(Domain.Yakinduum); + new(Domain d){ + var metrics = RepMetricsReader.read(d); this.g = metrics; ks = new KSDistance(g); js = new JSDistance(g); @@ -53,6 +54,7 @@ class PartialInterpretationMetricDistance { metrics.add(new NodeActivityMetric()); metrics.add(new MultiplexParticipationCoefficientMetric()); metrics.add(new NodeTypeMetric()); + metrics.add(new EdgeTypeMetric()); val metricCalculator = new PartialInterpretationGraph(partial, metrics, null); var metricSamples = metricCalculator.evaluateAllMetricsToSamples(); @@ -63,6 +65,7 @@ class PartialInterpretationMetricDistance { //var typedOutDegree = ks.typedOutDegreeDistance(metricSamples.typedOutDegreeSamples); var distance = new MetricDistanceGroup(mpc, na, outDegree, nodeType); distance.nodeTypeInfo = metricSamples.nodeTypeSamples; + distance.edgeTypeDistance = ks.edgeTypeDistance(metricSamples.edgeTypeSamples); return distance; } @@ -177,7 +180,8 @@ class MetricDistanceGroup{ var double outDegreeDistance; var double nodeTypeDistance; protected var HashMap nodeTypeInfo; - + public var double edgeTypeDistance; + new(double mpcDistance, double naDistance, double outDegreeDistance, double nodeTypeDistance){ this.mpcDistance = mpcDistance; this.naDistance = naDistance; diff --git a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Test.java b/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Test.java deleted file mode 100644 index f06b377f..00000000 --- a/Metrics/Metrics-Calculation/ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator/src/ca/mcgill/ecse/dslreasoner/realistic/metrics/calculator/app/Test.java +++ /dev/null @@ -1,31 +0,0 @@ -package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app; - -import java.util.ArrayList; -import java.util.List; - -import weka.core.matrix.LinearRegression; -import weka.core.matrix.Matrix; - -public class Test { - public static void main(String[] args) { - linearRegressionTest(); - } - - public static void linearRegressionTest() { - double[][] x = {{1,1,2,3}, {1,2,3,4}, {1,3,5,7}, {1,1,5,7}}; - double[] y = {10, 13, 19, 17}; - double[] valueToPredict = {1,1,1,1}; - Matrix m = new Matrix(x); - Matrix n = new Matrix(y, y.length); - - LinearRegression regression = new LinearRegression(m, n, 0); - double[] coef = regression.getCoefficients(); - - //predict - double a = 0; - for(int i = 0; i < coef.length; i++) { - a += coef[i] * valueToPredict[i]; - } - System.out.println(a); - } -} 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 index 08d8704a..c486a328 100644 --- 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 @@ -70,13 +70,30 @@ class KSDistance extends CostDistance { instanceDist.add(samples.getOrDefault(key, 0.0)); } + return ks_distance_two_dist(sourceDist, instanceDist); + } + + def edgeTypeDistance(HashMap samples){ + var typesDistMap = g.edgeTypeSamples; + var sourceDist = newArrayList(); + var instanceDist = newArrayList(); + + for(key : typesDistMap.keySet()){ + sourceDist.add(typesDistMap.get(key)); + instanceDist.add(samples.getOrDefault(key, 0.0)); + } + + return ks_distance_two_dist(sourceDist, instanceDist); + } + + def double ks_distance_two_dist(List dist1, List dist2){ // Since we already know the pdf, we compute the ks-test manully var ksStatistics = 0.0; var sum1 = 0.0; var sum2 = 0.0; - for(var i = 0; i < sourceDist.size(); i++){ - sum1 += sourceDist.get(i); - sum2 += instanceDist.get(i); + for(var i = 0; i < dist1.size(); i++){ + sum1 += dist1.get(i); + sum2 += dist2.get(i); ksStatistics = Math.max(ksStatistics, Math.abs(sum1 - sum2)); } 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 index 959006f4..8fa29fe6 100644 --- 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 @@ -7,10 +7,15 @@ import java.util.List import org.eclipse.emf.common.util.EList import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.EReference +import org.eclipse.xtend.lib.annotations.Accessors class EMFGraph extends Graph{ + @Accessors(PUBLIC_GETTER) + var EObject root; + def void init (EObject root, List metrics, String name, List referenceTypes){ val otherContents = root.eAllContents.toList(); + this.root = root; otherContents.add(root); init(otherContents, metrics, name, referenceTypes); } @@ -30,17 +35,11 @@ class EMFGraph extends Graph{ statistic.addNodeWithAllTypes(it, types); ] - referenceTypes.forEach[it| - var typeToAdd = it; - - // TODO: Here is to only consider one part of opposite edges -// if(it.upperBound != -1 && it.EOpposite !== null && -// (it.EOpposite.upperBound == -1 || it.EOpposite.upperBound > it.upperBound -// )){ -// typeToAdd = it.EOpposite; -// } -// - statistic.addEdgeType(typeToAdd.name); + referenceTypes.forEach[it| + // Only consider the edges that are not derived to preserve the statistical property + if(!it.derived){ + statistic.addEdgeType(it.name); + } ]; objects.forEach[source| @@ -62,6 +61,12 @@ class EMFGraph extends Graph{ this.name = name; } + def void removeReference(EReference r){ + if (statistic.containsEdgeType(r.name)){ + statistic.removeReference(r.name, r.containment); + } + } + /** * Set basic information for the output */ @@ -94,15 +99,8 @@ class EMFGraph extends Graph{ } def addEdge(EObject source, EObject target, EReference r){ - // TODO: Here is to only consider one part of opposite edges - //check for the opposite reference and do not add if its opposite will be added -// if(r.upperBound != -1 && r.EOpposite !== null && -// (r.EOpposite.upperBound == -1 || r.EOpposite.upperBound > r.upperBound -// )){ -// return; -// } - - if(target !== null && r !== null){ + //Only add the edge if the reference is not derived to preserve the statistical property + if(target !== null && r !== null && !r.derived){ statistic.addEdge(source, target, r.name); } } 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 index 84071176..af05a1cd 100644 --- 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 @@ -12,7 +12,7 @@ import org.eclipse.emf.ecore.EReference class GraphStatistic { val incomingEdges = new HashMap>; - val outcomingEdges = new HashMap>; + val outgoingEdges = new HashMap>; val edgeTypes = new HashSet(); val nodeToType = new HashMap>(); @@ -22,15 +22,13 @@ class GraphStatistic { * @param type: type to add */ def void addEdgeType(String type){ - - if(edgeTypes.contains(type)){ return; } edgeTypes.add(type); incomingEdges.put(type, ArrayListMultimap.create()); - outcomingEdges.put(type, ArrayListMultimap.create()); + outgoingEdges.put(type, ArrayListMultimap.create()); } /** @@ -43,6 +41,23 @@ class GraphStatistic { nodeToType.put(n, types); } + def boolean containsNode(EObject o){ + return nodeToType.containsKey(o); + } + + def Set getTypesForNode(EObject o){ + return nodeToType.getOrDefault(o, new HashSet()); + } + + def void overwriteCurrentType(EObject o, String type){ + var typeSet = nodeToType.getOrDefault(o, new HashSet()); + + // clear current types + typeSet.clear(); + typeSet.add(type); + nodeToType.put(o, typeSet); + } + /** * Add a node to the graph with all types in its type hierarchy */ @@ -57,10 +72,58 @@ class GraphStatistic { * @param type: type of the reference */ def void addEdge(EObject source, EObject target, String type){ - outcomingEdges.get(type).put(source, target); + outgoingEdges.get(type).put(source, target); incomingEdges.get(type).put(target, source); } + /** + * check if this graph contains a specific edge type + */ + def boolean containsEdgeType(String typeName){ + if(outgoingEdges.containsKey(typeName) && incomingEdges.containsKey(typeName)){ + return true; + } + return false; + } + + /** + * remove references from the statistics, potentially remove the nodes associated with it + * @Param name: name of the reference + * @Param isContainment: if true then the corresponding nodes on the incoming side will also be removed + */ + def removeReference(String name, boolean isContainment){ + if(!edgeTypes.contains(name)){ + return; + } + + edgeTypes.remove(name); + var incomingSet = incomingEdges.remove(name); + outgoingEdges.remove(name); + + // if the reference is not a containment, then removing the reference is enough + if(!isContainment){ + return; + } + + // else remove all corresponding nodes + val nodesToRemove = incomingSet.keySet(); + + //remove nodes from node sets + nodesToRemove.forEach[nodeToType.remove(it)]; + + val removeForMultimap = [Multimap refMap| + nodesToRemove.forEach[refMap.removeAll(it)]; + var values = refMap.values() + //remove the values from the list is equavalent to remove it in the multimap + values.removeAll(nodesToRemove); + return; + ]; + + //remove nodes from all other references on incomingEdges + incomingEdges.values.forEach(removeForMultimap); + outgoingEdges.values.forEach(removeForMultimap); + } + /** * calculate the out degree for an object */ @@ -68,7 +131,7 @@ class GraphStatistic { var count = 0; for (String type : edgeTypes){ - count += outcomingEdges.get(type).get(o).size(); + count += outgoingEdges.get(type).get(o).size(); } return count; } @@ -89,7 +152,7 @@ class GraphStatistic { * calculate the dimentional degree of a node */ def int dimentionalDegree(EObject o, String type){ - return incomingEdges.get(type).get(o).size() + outcomingEdges.get(type).get(o).size(); + return incomingEdges.get(type).get(o).size() + outgoingEdges.get(type).get(o).size(); } /** @@ -120,7 +183,7 @@ class GraphStatistic { } def HashMap> getOutgoingEdges(){ - return outcomingEdges; + return outgoingEdges; } } 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 index ef68f366..a2934eb9 100644 --- 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 @@ -2,6 +2,8 @@ package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.graph import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.Metric import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration +import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type +import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDefinition import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.BinaryElementRelationLink import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.impl.PartialComplexTypeInterpretationImpl @@ -20,19 +22,25 @@ class PartialInterpretationGraph extends Graph{ partial.problem.relations.filter(RelationDeclaration).forEach[ //only need the name of the reference type (remove everything with and after "reference") var n = it.name.split(" ").get(0); - // TODO: Here is to only consider one part of opposite edges - if(!n.equals('target') && !n.equals('source') /* && !n.equals('incomingTransitions')*/){ this.statistic.addEdgeType(n); - } ] // add all elements val typeInterpretations = getTypes(partial); for(type : typeInterpretations){ //Only consider the most concrete class - if(type.interpretationOf.subtypes.size == 0){ + if(isConcreteType(type.interpretationOf)){ var typeName = type.interpretationOf.name.replace(classSuffix, ''); for(node : type.elements){ - this.statistic.addNodeWithType(node, typeName); + if(!this.statistic.containsNode(node)){ + this.statistic.addNodeWithType(node, typeName); + }else{ + // if the current type of the node is a super type of the type to check, + // substitute the current type with the new type + var currentType = statistic.getTypesForNode(node).get(0); + if(isSuperType(currentType, type.interpretationOf)){ + statistic.overwriteCurrentType(node, typeName); + } + } } } } @@ -40,18 +48,48 @@ class PartialInterpretationGraph extends Graph{ for(relationInterpretation : partial.partialrelationinterpretation) { //only need the name of the reference type (remove everything with and after "reference") val type = relationInterpretation.interpretationOf.name.split(" ").get(0); - // TODO: Here is to only consider one part of opposite edges - if(!type.equals('target') && !type.equals('source') /*&& !type.equals('incomingTransitions')*/){ - for(edge : relationInterpretation.relationlinks.filter(BinaryElementRelationLink)){ - statistic.addEdge(edge.param1, edge.param2, type); - } - } + for(edge : relationInterpretation.relationlinks.filter(BinaryElementRelationLink)){ + statistic.addEdge(edge.param1, edge.param2, type); + } } this.name = name; this.metrics = metrics; } + /** + * recursively check if a type is the super type of another + */ + def boolean isSuperType(String typeName, Type subtypeToCheck){ + var superTypes = subtypeToCheck.supertypes; + if(superTypes.size == 0){ + return false; + }else if(subtypeToCheck.supertypes.map[it.name.replace(classSuffix, '')].contains(typeName)){ + return true; + }else{ + for(superType : superTypes){ + if(isSuperType(typeName, superType)){ + return true; + } + } + return false; + } + } + + /** + * Check if a Type object is the class that we want to consider + * A type object is to be considered if it satisfy one of the following: + * 1. if it is not abstract + * 2. if it is abstract but has a subclass of type TypeDefinition (This means the generation is + * started with nodes in this type) + */ + def boolean isConcreteType(Type t){ + if(!t.isAbstract || t.subtypes.findFirst[it instanceof TypeDefinition] !== null){ + return true; + } + return false; + } + /** * Set basic information for the output */ 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 index 491501b0..858113e9 100644 --- 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 @@ -20,6 +20,8 @@ import org.eclipse.emf.ecore.resource.Resource import org.eclipse.emf.ecore.resource.ResourceSet import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl +import org.eclipse.emf.ecore.EGenericType +import org.eclipse.emf.ecore.EStructuralFeature class GraphReader{ val ResourceSet resSet = new ResourceSetImpl(); @@ -53,9 +55,11 @@ class GraphReader{ metrics.add(new TypedOutDegree()); metrics.add(new NodeTypeMetric()); metrics.add(new EdgeTypeMetric()); - + var count = 1 //check all files in the directory with suffix for(String name : dir.list.filter[it| it.endsWith(suffix)]){ + println(name) + println(count) val file = new File(name); val roots = readModel(EObject, path, file.name); //add a list of metrics @@ -63,7 +67,8 @@ class GraphReader{ for(root : roots){ g.init(root, metrics, name.replaceFirst(suffix, ""), referenceTypes); } - + + count ++; graphs.add(g); } 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 index 6af0b6c7..06e88efc 100644 --- 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 @@ -4,34 +4,62 @@ import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app.Domain import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.metrics.MetricSampleGroup import hu.bme.mit.inf.dslreasoner.domains.yakindu.sgraph.yakindumm.impl.YakindummPackageImpl import java.util.HashMap +import org.eclipse.emf.ecore.EReference +import org.eclipse.emf.ecore.impl.EcorePackageImpl /** * Read the sample of the distribution of a metric provided the csv file of the metric */ class RepMetricsReader { + static var Domain domain; static def read(Domain d){ - var reader = new GraphReader(YakindummPackageImpl.eINSTANCE, '.xmi'); + var GraphReader reader; + if(d == Domain.Yakindumm){ + reader = new GraphReader(YakindummPackageImpl.eINSTANCE, '.xmi'); + }else if (d == Domain.Ecore){ + reader = new GraphReader(EcorePackageImpl.eINSTANCE, '.ecore'); + }else if (d == Domain.Github){ + // Initialize the reader with github package + } + domain = d; var domainRepPath = DataName.REP_PATH + d.name + '/'; var rep = new MetricSampleGroup() var out_d = readMetrics(reader, domainRepPath + DataName.OUT_D_REP); - rep.mpcSamples = readMetrics(reader, domainRepPath + DataName.MPC_REP).mpcSamples; + var mpc = readMetrics(reader, domainRepPath + DataName.MPC_REP); + rep.mpcSamples = mpc.mpcSamples; rep.outDegreeSamples = out_d.outDegreeSamples; rep.naSamples = readMetrics(reader, domainRepPath + DataName.NA_REP).naSamples; rep.typedOutDegreeSamples = out_d.typedOutDegreeSamples; - rep.edgeTypeSamples = out_d.edgeTypeSamples; + rep.edgeTypeSamples = mpc.edgeTypeSamples; //TODO: Parameterize the prior node distribution var nodeTypeSamples = new HashMap(); - nodeTypeSamples.put('Entry', 0.04257802080554814); - nodeTypeSamples.put('Choice', 0.1267671379034409); - nodeTypeSamples.put('State', 0.1596092291277674); - nodeTypeSamples.put('Transition', 0.6138636969858629); - nodeTypeSamples.put('Statechart', 0.010136036276340358); - nodeTypeSamples.put('Region', 0.04467858095492131); - nodeTypeSamples.put('Exit', 0.0018338223526273673); - nodeTypeSamples.put('FinalState', 0.0005334755934915977); + if(d == Domain.Yakindumm){ + nodeTypeSamples.put('Entry', 0.04257802080554814); + nodeTypeSamples.put('Choice', 0.1267671379034409); + nodeTypeSamples.put('State', 0.1596092291277674); + nodeTypeSamples.put('Transition', 0.6138636969858629); + nodeTypeSamples.put('Statechart', 0.010136036276340358); + nodeTypeSamples.put('Region', 0.04467858095492131); + nodeTypeSamples.put('Exit', 0.0018338223526273673); + nodeTypeSamples.put('FinalState', 0.0005334755934915977); + }else if(d ==Domain.Ecore){ + nodeTypeSamples.put('EAttribute', 0.23539778449144008); + nodeTypeSamples.put('EClass', 0.33081570996978854); + nodeTypeSamples.put('EReference', 0.30996978851963747); + nodeTypeSamples.put('EPackage', 0.012789526686807653); + nodeTypeSamples.put('EAnnotation', 0.002517623363544813); + nodeTypeSamples.put('EEnumLiteral', 0.07275931520644502); + nodeTypeSamples.put('EEnum', 0.013645518630412891); + nodeTypeSamples.put('EDataType', 0.004028197381671702); + nodeTypeSamples.put('EParameter', 0.005941591137965764); + nodeTypeSamples.put('EGenericType', 0.002014098690835851); + nodeTypeSamples.put('EOperation', 0.009415911379657605); + nodeTypeSamples.put('ETypeParameter', 0.0007049345417925478); + } + rep.nodeTypeSamples = nodeTypeSamples; @@ -42,7 +70,14 @@ class RepMetricsReader { * Read representative model */ private static def readMetrics(GraphReader r, String path){ - var model = r.readModels(path).head; + val model = r.readModels(path).head; + if(domain == Domain.Ecore){ + var refsToRemove = EcorePackageImpl.eINSTANCE.eAllContents.filter(EReference).filter[ + it.name.equals('eGenericType') || it.name.equals('eGenericSuperTypes') || it.name.equals('eFactoryInstance') || + it.name.equals('eGenericExceptions') || it.name.equals('references') || it.name.equals('contents'); + ]; + refsToRemove.forEach[model.removeReference(it)]; + } return model.evaluateAllMetricsToSamples(); } 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 index d9c88bb4..eafa49b2 100644 --- 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 @@ -9,11 +9,11 @@ import org.eclipse.emf.ecore.EObject class MultiplexParticipationCoefficientMetric extends Metric { public static val countName = "MPCCount"; public static val valueName = "MPCValue"; - + val formatter = new DecimalFormat("#0.00000"); override evaluate(GraphStatistic g) { //because the precision issue of double, we translate double values into String to be the key - val formatter = new DecimalFormat("#0.00000"); + //get number of different types val typeCounts = g.allTypes.size; @@ -75,6 +75,6 @@ class MultiplexParticipationCoefficientMetric extends Metric { coef = 0; } - return coef; + return Double.parseDouble(formatter.format(coef)); } } \ 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 @@ +package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.validation + +import java.util.ArrayList +import java.util.HashMap +import java.util.List +import java.util.Map +import org.eclipse.emf.common.notify.Notifier +import org.eclipse.emf.common.util.URI +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl +import org.eclipse.viatra.addon.validation.core.api.IConstraintSpecification +import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine +import org.eclipse.viatra.query.runtime.api.impl.BaseGeneratedPatternGroup +import org.eclipse.viatra.query.runtime.emf.EMFScope + +class ConstraintCollection{ + val constraints = new ArrayList(); + var BaseGeneratedPatternGroup patterns; + var List resources = new ArrayList(); + + + new(List constraints, List uris, BaseGeneratedPatternGroup patterns){ + this.constraints.addAll(constraints); + this.patterns = patterns; + setURIs(uris); + } + + new(List constraints, BaseGeneratedPatternGroup patterns){ + this.constraints.addAll(constraints); + this.patterns = patterns; + } + + def addModel(Notifier n ){ + resources.add(n); + } + + def setURIs(List uris){ + val resSet = new ResourceSetImpl(); + + for(uri : uris){ + var resource = resSet.getResource(URI.createURI(uri), true); + resources.add(resource); + } + + println('reading model finished') + } + + def List calculateViolations(){ + var results = new ArrayList(); + + for(resource : resources){ + val engine = initEngine(resource); + var matches = constraints.stream.mapToInt([ele| ele.querySpecification.getMatcher(engine).countMatches]).sum(); + results.add(matches); + } + + return results; + } + + def ArrayList> calculateViolationMaps(){ + val result = new ArrayList>() + + for(resource : resources){ + val map = new HashMap(); + val engine = initEngine(resource); + constraints.forEach[ + var count = it.querySpecification.getMatcher(engine).countMatches; + map.put(it.querySpecification.simpleName, count); + ]; + result.add(map); + } + return result; + } + + private def initEngine(Notifier r){ + var engine = ViatraQueryEngine.on(new EMFScope(r)); + //init patterns with the new engine + patterns.prepare(engine); + return engine; + } +} 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..72239e22 --- /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,69 @@ +package ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.validation + +import ca.mcgill.ecse.dslreasoner.realistic.metrics.calculator.app.Domain +import com.google.common.reflect.ClassPath +import hu.bme.mit.inf.dslreasoner.partialsnapshot_mavo.yakindu.Patterns +import java.util.ArrayList +import org.eclipse.emf.ecore.EObject +import org.eclipse.viatra.addon.validation.core.api.IConstraintSpecification + +class ViolationCheck { + /** + * Return the total number of violations + */ + def static int calculateViolationCounts(EObject root, Domain d){ + var packageName = ''; + if(d == Domain.Yakindumm){ + packageName = 'constraints.yakindumm'; + }else if (d == Domain.Ecore){ + //TODO: put constraints package names for ecore and github models + return -1; + }else if (d == Domain.Github){ + return -1; + } + + + var constriants = loadConstraints(packageName); + var collections = new ConstraintCollection(constriants, Patterns.instance); + collections.addModel(root); + var results = collections.calculateViolations(); + if(results.size > 0){ + return results.get(0); + }else{ + throw new IllegalArgumentException("Calculate Violation Failed"); + } + } + + /** + * return a map contain the count for each type of violation + */ + def static violationMaps(EObject root){ + var constriants = loadConstraints('hu.bme.mit.inf.dslreasoner.partialsnapshot_mavo.yakindu'); + var collections = new ConstraintCollection(constriants, Patterns.instance); + collections.addModel(root); + var results = collections.calculateViolationMaps(); + if(results.size > 0){ + return results.get(0); + }else{ + throw new IllegalArgumentException("Calculate Violation Failed"); + } + } + + def static loadConstraints(String packageName){ + val constraints = new ArrayList(); + + val classPath = ClassPath.from(ClassLoader.systemClassLoader); + val classInfos = classPath.getTopLevelClasses(packageName); + + for(info : classInfos){ + if(info.load.interfaces.contains(IConstraintSpecification)){ + //IConstraintSpecification only has one constructor with empty argument list + var constructor = info.load.constructors.get(0); + var instance = constructor.newInstance(); + constraints.add(instance as IConstraintSpecification); + } + } + + return constraints + } +} -- cgit v1.2.3-54-g00ecf