Added Tag annotating from spectral clustering

parent 7331af39
package de.monticore.lang.monticar.generator.middleware.helpers;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.*;
import de.monticore.lang.embeddedmontiarc.tagging.middleware.ros.RosConnectionSymbol;
import de.monticore.symboltable.CommonScope;
import de.monticore.symboltable.MutableScope;
import de.monticore.symboltable.Symbol;
......@@ -10,6 +11,7 @@ import org.jgrapht.Graph;
import org.jgrapht.alg.ConnectivityInspector;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.SimpleGraph;
import smile.clustering.SpectralClustering;
import java.util.*;
import java.util.stream.Collectors;
......@@ -146,33 +148,43 @@ public class ClusterHelper {
}
public static double[][] createAdjacencyMatrix(ExpandedComponentInstanceSymbol component) {
// Nodes = subcomponents
// Verts = connectors between subcomponents
Collection<ExpandedComponentInstanceSymbol> subcomps = component.getSubComponents().stream()
public static List<ExpandedComponentInstanceSymbol> getSubcompsOrderedByName(ExpandedComponentInstanceSymbol componentInstanceSymbol){
return componentInstanceSymbol.getSubComponents().stream()
.sorted(Comparator.comparing(ExpandedComponentInstanceSymbol::getFullName))
.collect(Collectors.toList());
}
public static Collection<ConnectorSymbol> getInnerConnectors(ExpandedComponentInstanceSymbol componentInstanceSymbol){
String superCompName = componentInstanceSymbol.getFullName();
return componentInstanceSymbol.getConnectors().stream()
//filter out all connectors to super component
.filter(con -> !con.getSourcePort().getComponentInstance().get().getFullName().equals(superCompName)
&& !con.getTargetPort().getComponentInstance().get().getFullName().equals(superCompName))
.collect(Collectors.toList());
}
public static Map<String, Integer> getLabelsForSubcomps(List<ExpandedComponentInstanceSymbol> subcomps) {
Map<String, Integer> componentIndecies = new HashMap<>();
String superCompName = component.getFullName();
int[] i = {0};
subcomps.forEach(sc -> componentIndecies.put(sc.getFullName(), i[0]++));
return componentIndecies;
}
public static double[][] createAdjacencyMatrix(List<ExpandedComponentInstanceSymbol> subcomps, Collection<ConnectorSymbol> connectors, Map<String, Integer> subcompLabels) {
// Nodes = subcomponents
// Verts = connectors between subcomponents
double[][] res = new double[subcomps.size()][subcomps.size()];
Collection<ConnectorSymbol> connectors = component.getConnectors().stream()
//filter out all connectors to super component
.filter(con -> !con.getSourcePort().getComponentInstance().get().getFullName().equals(superCompName)
&& !con.getTargetPort().getComponentInstance().get().getFullName().equals(superCompName))
.collect(Collectors.toList());
connectors.forEach(con -> {
Optional<ExpandedComponentInstanceSymbol> sourceCompOpt = con.getSourcePort().getComponentInstance();
Optional<ExpandedComponentInstanceSymbol> targetCompOpt = con.getTargetPort().getComponentInstance();
if (sourceCompOpt.isPresent() && targetCompOpt.isPresent()) {
int index1 = componentIndecies.get(sourceCompOpt.get().getFullName());
int index2 = componentIndecies.get(targetCompOpt.get().getFullName());
int index1 = subcompLabels.get(sourceCompOpt.get().getFullName());
int index2 = subcompLabels.get(targetCompOpt.get().getFullName());
res[index1][index2] = 1.0d;
res[index2][index1] = 1.0d;
......@@ -185,4 +197,60 @@ public class ClusterHelper {
return res;
}
public static List<Set<ExpandedComponentInstanceSymbol>> createClusters(ExpandedComponentInstanceSymbol component,int numberOfClusters,ClustererKind clustererKind){
//TODO: create wrapper for clusterer for easy exchange
List<ExpandedComponentInstanceSymbol> subcompsOrderedByName = ClusterHelper.getSubcompsOrderedByName(component);
Map<String, Integer> labelsForSubcomps = ClusterHelper.getLabelsForSubcomps(subcompsOrderedByName);
double[][] adjMatrix = ClusterHelper.createAdjacencyMatrix(subcompsOrderedByName,
ClusterHelper.getInnerConnectors(component),
labelsForSubcomps);
SpectralClustering clustering = new SpectralClustering(adjMatrix,numberOfClusters);
int[] labels = clustering.getClusterLabel();
List<Set<ExpandedComponentInstanceSymbol>> res = new ArrayList<>();
for(int i = 0; i < numberOfClusters; i++){
res.add(new HashSet<>());
}
subcompsOrderedByName.forEach(sc -> {
int curClusterLabel = labels[labelsForSubcomps.get(sc.getFullName())];
res.get(curClusterLabel).add(sc);
});
return res;
}
public static void annotateComponentWithRosTagsForClusters(ExpandedComponentInstanceSymbol componentInstanceSymbol, List<Set<ExpandedComponentInstanceSymbol>> clusters) {
Collection<ConnectorSymbol> connectors = componentInstanceSymbol.getConnectors();
connectors.forEach(con -> {
// -1 = super comp
int sourceClusterLabel = -1;
int targetClusterLabel = -1;
ExpandedComponentInstanceSymbol sourceComp = con.getSourcePort().getComponentInstance().get();
ExpandedComponentInstanceSymbol targetComp = con.getTargetPort().getComponentInstance().get();
for(int i = 0; i < clusters.size(); i++){
if(clusters.get(i).contains(sourceComp)){
sourceClusterLabel = i;
}
if(clusters.get(i).contains(targetComp)){
targetClusterLabel = i;
}
}
if(sourceClusterLabel != targetClusterLabel){
con.getSourcePort().setMiddlewareSymbol(new RosConnectionSymbol());
con.getTargetPort().setMiddlewareSymbol(new RosConnectionSymbol());
}
});
}
}
package de.monticore.lang.monticar.generator.middleware.helpers;
public enum ClustererKind {
SPECTRAL_CLUSTERER
}
package de.monticore.lang.monticar.generator.middleware;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
import de.monticore.lang.embeddedmontiarc.tagging.middleware.ros.RosToEmamTagSchema;
import de.monticore.lang.monticar.emadl.generator.EMADLAbstractSymtab;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.PortSymbol;
import de.monticore.lang.monticar.generator.middleware.helpers.ClusterHelper;
import de.monticore.lang.monticar.generator.roscpp.helper.TagHelper;
import de.monticore.lang.monticar.generator.middleware.impls.CPPGenImpl;
import de.monticore.lang.monticar.generator.middleware.impls.RosCppGenImpl;
import de.monticore.lang.tagging._symboltable.TaggingResolver;
import de.monticore.symboltable.CommonSymbol;
import org.junit.Test;
import smile.clustering.SpectralClustering;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
......@@ -24,7 +33,10 @@ public class AutomaticClusteringTest extends AbstractSymtabTest{
ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.<ExpandedComponentInstanceSymbol>resolve("lab.system", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentInstanceSymbol);
double[][] matrix = ClusterHelper.createAdjacencyMatrix(componentInstanceSymbol);
List<ExpandedComponentInstanceSymbol> subcompsOrderedByName = ClusterHelper.getSubcompsOrderedByName(componentInstanceSymbol);
double[][] matrix = ClusterHelper.createAdjacencyMatrix(subcompsOrderedByName,
ClusterHelper.getInnerConnectors(componentInstanceSymbol),
ClusterHelper.getLabelsForSubcomps(subcompsOrderedByName));
//sorted by full name: alex, combine, dinhAn, michael, philipp
......@@ -42,6 +54,131 @@ public class AutomaticClusteringTest extends AbstractSymtabTest{
}
@Test
public void testSpectralClustering(){
// 0 1 0 0
// 1 0 0 0
// 0 0 0 1
// 0 0 1 0
//zu 2 cluster -> (a,b) (c,d)
double[][] adjMatrix = {{0, 1, 0, 0},
{1, 0, 0, 0},
{0, 0, 0, 1},
{0, 0, 1, 0}};
SpectralClustering clustering = new SpectralClustering(adjMatrix,2);
int[] labels = clustering.getClusterLabel();
for (int label : labels) {
System.out.println(label);
}
assertEquals(4, labels.length);
assertTrue(labels[0] == labels[1]);
assertTrue(labels[2] == labels[3]);
assertTrue( labels[0] != labels[2]);
assertTrue( labels[0] != labels[3]);
assertTrue( labels[1] != labels[2]);
assertTrue( labels[1] != labels[3]);
}
@Test
public void testCreateClusters(){
//UnambiguousCluster
TaggingResolver taggingResolver = AbstractSymtabTest.createSymTabAndTaggingResolver(TEST_PATH);
ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.<ExpandedComponentInstanceSymbol>resolve("clustering.unambiguousCluster", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentInstanceSymbol);
List<Set<ExpandedComponentInstanceSymbol>> clusters = ClusterHelper.createClusters(componentInstanceSymbol, 2, null);
assertTrue(clusters.size() == 2);
Set<ExpandedComponentInstanceSymbol> cluster1 = clusters.get(0);
Set<ExpandedComponentInstanceSymbol> cluster2 = clusters.get(1);
assertTrue(cluster1.size() == 2);
assertTrue(cluster2.size() == 2);
List<String> cluster1Names = cluster1.stream()
.map(CommonSymbol::getFullName)
.collect(Collectors.toList());
List<String> cluster2Names = cluster2.stream()
.map(CommonSymbol::getFullName)
.collect(Collectors.toList());
if(cluster1Names.get(0).endsWith("compA") || cluster1Names.get(0).endsWith("compB")){
assertTrue(cluster1Names.contains("clustering.unambiguousCluster.compA"));
assertTrue(cluster1Names.contains("clustering.unambiguousCluster.compB"));
assertTrue(cluster2Names.contains("clustering.unambiguousCluster.compC"));
assertTrue(cluster2Names.contains("clustering.unambiguousCluster.compD"));
}else{
assertTrue(cluster1Names.contains("clustering.unambiguousCluster.compC"));
assertTrue(cluster1Names.contains("clustering.unambiguousCluster.compD"));
assertTrue(cluster2Names.contains("clustering.unambiguousCluster.compA"));
assertTrue(cluster2Names.contains("clustering.unambiguousCluster.compB"));
}
}
@Test
public void testClusterToRosConnections() throws IOException {
TaggingResolver taggingResolver = AbstractSymtabTest.createSymTabAndTaggingResolver(TEST_PATH);
//ClustersWithSingleConnection
ExpandedComponentInstanceSymbol componentInstanceSymbol = taggingResolver.<ExpandedComponentInstanceSymbol>resolve("clustering.clustersWithSingleConnection", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentInstanceSymbol);
//Force cluster; spectral would not cluster this way!
List<Set<ExpandedComponentInstanceSymbol>> clusters = new ArrayList<>();
HashSet<ExpandedComponentInstanceSymbol> cluster1 = new HashSet<>();
cluster1.add(componentInstanceSymbol.getSubComponent("outComp1").get());
cluster1.add(componentInstanceSymbol.getSubComponent("inOutComp").get());
clusters.add(cluster1);
HashSet<ExpandedComponentInstanceSymbol> cluster2 = new HashSet<>();
cluster2.add(componentInstanceSymbol.getSubComponent("outComp2").get());
cluster2.add(componentInstanceSymbol.getSubComponent("doubleInComp").get());
clusters.add(cluster2);
ClusterHelper.annotateComponentWithRosTagsForClusters(componentInstanceSymbol, clusters);
List<String> rosPortsSuper = componentInstanceSymbol.getPortsList().stream()
.filter(PortSymbol::isRosPort)
.map(PortSymbol::getFullName)
.collect(Collectors.toList());
List<String> rosPortsSubComps = componentInstanceSymbol.getSubComponents().stream()
.flatMap(subc -> subc.getPortsList().stream())
.filter(PortSymbol::isRosPort)
.map(PortSymbol::getFullName)
.collect(Collectors.toList());
//No Ports in super comp
assertTrue(rosPortsSuper.size() == 0);
assertTrue(rosPortsSubComps.size() == 2);
assertTrue(rosPortsSubComps.contains("clustering.clustersWithSingleConnection.inOutComp.out1"));
assertTrue(rosPortsSubComps.contains("clustering.clustersWithSingleConnection.doubleInComp.in2"));
DistributedTargetGenerator distributedTargetGenerator = new DistributedTargetGenerator();
distributedTargetGenerator.setGenerationTargetPath("./target/generated-sources-clustering/ClusterToRosConnections/src/");
distributedTargetGenerator.add(new CPPGenImpl(),"cpp");
distributedTargetGenerator.add(new RosCppGenImpl(),"roscpp");
distributedTargetGenerator.generate(componentInstanceSymbol,taggingResolver);
}
}
package clustering;
component ClustersWithSingleConnection{
component InOutComp{
ports in Q in1,
out Q out1;
}
component DoubleInComp{
port in Q in1,
in Q in2;
}
instance OutComp outComp1;
instance OutComp outComp2;
instance DoubleInComp doubleInComp;
instance InOutComp inOutComp;
connect outComp1.out1 -> inOutComp.in1;
connect outComp2.out1 -> doubleInComp.in1;
connect inOutComp.out1 -> doubleInComp.in2;
}
\ No newline at end of file
package clustering;
component InComp{
port in Q in1;
}
\ No newline at end of file
package clustering;
component OutComp{
port out Q out1;
}
\ No newline at end of file
package clustering;
component UnambiguousCluster{
// compA -> compB; compC -> compD
instance OutComp compA;
instance InComp compB;
instance OutComp compC;
instance InComp compD;
connect compA.out1 -> compB.in1;
connect compC.out1 -> compD.in1;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment