package i5.las2peer.services.ocd.algorithms;
import java.io.File;
//import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
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 org.la4j.matrix.Matrix;
import org.la4j.matrix.sparse.CCSMatrix;
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 y.base.Node;
import y.base.NodeCursor;
/*
* @author YLi
*/
public class EvolutionaryAlgorithmBasedOnSimilarity implements OcdAlgorithm {
/*
* Path of the directory reserved for the application.
*/
private static final String DirectoryPath = "ocd/mea/";
/*
* 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 Liu et al.
*/
private static String linuxMeaApplicationPath = "./MeaLinux";
/*
* Path of the application for Windows based on the source codes of Liu et
* al.
*/
private static String windowsMeaApplicationPath = DirectoryPath + "MeaWindows.exe";
/*
* Path of paj file.
*/
private static final String graphPath = DirectoryPath + "network.paj";
private static final String graphName = "network.paj";
/*
* Path of the output of last generation.
*/
private static String LastResultPath = DirectoryPath + "network.paj.0099.pop";
private int minNodeIndex = 0;
@Override
public CoverCreationType getAlgorithmType() {
return CoverCreationType.EVOLUTIONARY_ALGORITHM_BASED_ON_SIMILARITY;
}
@Override
public void setParameters(Map<String, String> parameters) {
}
@Override
public Map<String, String> getParameters() {
return new HashMap<String, String>();
}
@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 EvolutionaryAlgorithmBasedOnSimilarity() {
}
@Override
public Cover detectOverlappingCommunities(CustomGraph graph) throws OcdAlgorithmException, InterruptedException {
synchronized (executor) {
try {
String executorFilename;
if (SystemUtils.IS_OS_LINUX) {
executorFilename = linuxMeaApplicationPath;
} else if (SystemUtils.IS_OS_WINDOWS) {
executorFilename = windowsMeaApplicationPath;
}
/*
* Benchmark not implemented for this operating system.
*/
else {
throw new OcdAlgorithmException();
}
/*
* The source code of this algorithm requires the first node of
* the network file to have the index 1. If not, the input file
* should be adapted.
*/
NodeCursor nodes = graph.nodes();
Node node;
int count = 0;
while (nodes.ok()) {
node = nodes.node();
if (count == 0) {
minNodeIndex = node.index();
} else {
if (node.index() < minNodeIndex) {
minNodeIndex = node.index();
}
}
count++;
nodes.next();
}
writeNetworkFile(graph);
CommandLine cmdLine = new CommandLine(executorFilename);
cmdLine.addArgument(graphName);
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());
}
int nodeCount = graph.nodeCount();
Matrix membershipMatrix = translateCommunityFile(LastResultPath, 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 paj file
protected void writeNetworkFile(CustomGraph graph) throws IOException, InterruptedException {
FileWriter networkFile = new FileWriter(graphPath);
try {
networkFile.write(String.format("*Vertices "));
networkFile.write("\t");
networkFile.write(Integer.toString(graph.nodeCount()));
networkFile.write(System.lineSeparator());
networkFile.write(String.format("*Edges"));
networkFile.write(System.lineSeparator());
EdgeCursor edges = graph.edges();
Edge edge;
while (edges.ok()) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
edge = edges.edge();
if (edge.source().index() <= edge.target().index()) {
networkFile.write(Integer.toString(edge.source().index() + (1 - minNodeIndex)));// networkFile.write(Integer.toString(edge.source().index()+1));
networkFile.write("\t");
networkFile.write(Integer.toString(edge.target().index() + (1 - minNodeIndex)));// networkFile.write(Integer.toString(edge.source().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 translateCommunityFile(String LastResultPath, int nodeCount)
throws IOException, InterruptedException {
File resultFile = new File(LastResultPath);
Scanner communityResult = new Scanner(resultFile);
List<List<Integer>> membership = new ArrayList<List<Integer>>();
Map<Integer, List<Integer>> membershipTranspose = new HashMap<Integer, List<Integer>>();
Integer communitySize;
try {
while (communityResult.hasNext()) {
if (communityResult.next().equals("#community")) {
communityResult.next();
communityResult.next();
communitySize = communityResult.nextInt();
List<Integer> memberList = new ArrayList<Integer>();
memberList.clear();
for (int i = 0; i < communitySize; i++) {
memberList.add(communityResult.nextInt());
}
membership.add(memberList);
}
}
int communityCount = membership.size();
for (int i = 0; i < communityCount; i++) {
Integer community = i;
for (Integer element : membership.get(i)) {
List<Integer> communityList = new ArrayList<Integer>();
if (membershipTranspose.keySet().contains(element)) {
membershipTranspose.get(element).add(community);
} else {
communityList.add(community);
membershipTranspose.put(element, communityList);
}
}
}
Matrix membershipMatrix = new CCSMatrix(nodeCount, membership.size());
for (int i = 0; i < nodeCount; i++) {
double entryInTheLine = (double) 1 / (double) membershipTranspose.get(i).size();
for (int j = 0; j < membershipTranspose.get(i).size(); j++) {
membershipMatrix.set(i, membershipTranspose.get(i).get(j), entryInTheLine);
}
}
return membershipMatrix;
}
catch (Exception e) {
throw new IOException(e);
} finally {
try {
communityResult.close();
} catch (Exception e) {
}
}
}
}