package i5.las2peer.services.ocd.algorithms; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecuteResultHandler; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.lang3.SystemUtils; import java.util.Scanner; import i5.las2peer.services.ocd.algorithms.utils.OcdAlgorithmException; import i5.las2peer.services.ocd.benchmarks.OcdBenchmarkException; import i5.las2peer.services.ocd.graphs.Cover; import i5.las2peer.services.ocd.graphs.CoverCreationType; import i5.las2peer.services.ocd.graphs.CustomGraph; import i5.las2peer.services.ocd.graphs.GraphType; import y.base.Edge; import y.base.EdgeCursor; import org.la4j.matrix.Matrix; import org.la4j.matrix.sparse.CCSMatrix; /* * @author YLi */ public class SignedProbabilisticMixtureAlgorithm implements OcdAlgorithm { /* * Path of the directory reserved for the application. */ private static final String DirectoryPath = "ocd/spm/"; /* * Used for synchronization purposes. Executes the application execution. */ private static DefaultExecutor executor = new DefaultExecutor(); /* * Path of the application for Linux based on the source codes of Chen et. al. */ private static String linuxApplicationPath = "./SpmLinux"; /* * Path of the application for Windows based on the source codes of Chen et * al. */ private static String windowsApplicationPath = DirectoryPath + "SpmWindows.exe"; /* * Path of tuple file. */ private static final String graphPath = DirectoryPath + "network.tuple"; /* * Name of tuple file. */ private static final String graphName = "network.tuple"; /* * Path of the output of last generation. */ private static String LastResultPath = DirectoryPath + "result.txt"; /** * The number of trials. The default value is 3. Must be greater than 0. */ private int n = 3; /* * PARAMETER NAMES */ protected final String TRIALCOUNT_NAME = "n"; @Override public CoverCreationType getAlgorithmType() { return CoverCreationType.SIGNED_PROBABILISTIC_MIXTURE_ALGORITHM; } @Override public void setParameters(Map<String, String> parameters) { if (parameters.containsKey(TRIALCOUNT_NAME)) { n = Integer.parseInt(parameters.get(TRIALCOUNT_NAME)); parameters.remove(TRIALCOUNT_NAME); if (n < 0) { throw new IllegalArgumentException(); } } if (parameters.size() > 0) { throw new IllegalArgumentException(); } } @Override public Map<String, String> getParameters() { Map<String, String> parameters = new HashMap<String, String>(); parameters.put(TRIALCOUNT_NAME, Integer.toString(n)); return parameters; } @Override public Set<GraphType> compatibleGraphTypes() { Set<GraphType> compatibilities = new HashSet<GraphType>(); compatibilities.add(GraphType.NEGATIVE_WEIGHTS); compatibilities.add(GraphType.WEIGHTED); return compatibilities; } /** * Creates a standard instance of the algorithm. All attributes are assigned * their default values. */ public SignedProbabilisticMixtureAlgorithm() { } public SignedProbabilisticMixtureAlgorithm(int n) { this.n = n; } @Override public Cover detectOverlappingCommunities(CustomGraph graph) throws OcdAlgorithmException, InterruptedException { synchronized (executor) { try { String executorFilename; if (SystemUtils.IS_OS_LINUX) { executorFilename = linuxApplicationPath; } else if (SystemUtils.IS_OS_WINDOWS) { executorFilename = windowsApplicationPath; } /* * Benchmark not implemented for this operating system. */ else { throw new OcdAlgorithmException(); } writeNetworkFile(graph); CommandLine cmdLine = new CommandLine(executorFilename); cmdLine.addArgument(graphName); cmdLine.addArgument(Integer.toString(n)); File workingDirectory = new File(DirectoryPath); executor.setWorkingDirectory(workingDirectory); DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); executor.execute(cmdLine, resultHandler); resultHandler.waitFor(); if (resultHandler.getExitValue() != 0) { System.out.println(resultHandler.getException()); throw new OcdBenchmarkException("MEA Process exit value: " + resultHandler.getExitValue()); } // read result file and generate membershipMatrix File resultFile = new File(LastResultPath); Integer nodeCount = graph.nodeCount(); Matrix membershipMatrix = getMembershipMatrix(resultFile, nodeCount); Cover cover = new Cover(graph, membershipMatrix); return cover; } catch (InterruptedException e) { throw e; } catch (Exception e) { e.printStackTrace(); if (Thread.interrupted()) { throw new InterruptedException(); } throw new OcdAlgorithmException(e); } } } // translate graph into tuple file protected void writeNetworkFile(CustomGraph graph) throws IOException, InterruptedException { FileWriter networkFile = new FileWriter(graphPath); try { networkFile.write(Integer.toString(graph.nodeCount())); networkFile.write(System.lineSeparator()); EdgeCursor edges = graph.edges(); Edge edge; while (edges.ok()) { if (Thread.interrupted()) { throw new InterruptedException(); } edge = edges.edge(); /* * The algorithm reads network files starting with node 1. */ if (edge.source().index() <= edge.target().index()) { networkFile.write(Integer.toString(edge.source().index() + 1)); networkFile.write("\t"); networkFile.write(Integer.toString(edge.target().index() + 1)); networkFile.write("\t"); networkFile.write(Double.toString(graph.getEdgeWeight(edge))); networkFile.write(System.lineSeparator()); } edges.next(); } } finally { networkFile.close(); } } //Transform the results written by the executable file into the membership matrix. protected Matrix getMembershipMatrix(File resultFile, int nodeCount) throws IOException, InterruptedException { Scanner communityResult = new Scanner(resultFile); int communityCount = 0; try { if (communityResult.next().equals("theta:")) { if (communityResult.hasNextInt()) { communityResult.next(); while (!communityResult.hasNextInt()) { communityCount++; communityResult.next(); } } } Matrix membershipMatrix = new CCSMatrix(nodeCount, communityCount); while (communityResult.hasNext()) { if (communityResult.next().equals("alpha/beta:")) { for (int i = 0; i < nodeCount; i++) { int nodeID = communityResult.nextInt(); for (int j = 0; j < communityCount; j++) { /* * result file of the executable file with nodes starting from 1 */ membershipMatrix.set(nodeID - 1, j, communityResult.nextDouble()); } } } } return membershipMatrix; } catch (Exception e) { throw new IOException(e); } finally { try { communityResult.close(); } catch (Exception e) { } } } }