package edu.isi.karma.modeling.steiner.topk;
import java.io.BufferedReader;
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.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
/**
* This class serves as a super class for different implementations of the STAR
* algorithm.
*
* @author kasneci
*
*/
public abstract class TopKSteinertrees {
/******* data structures and methods for main memory algorithms ************/
// graph which can be loaded into main memory
public static Map<SteinerNode, TreeSet<SteinerEdge>> graph;
//nodes of the graph
public static Map<String, SteinerNode> nodes;
//maps node names to ids
public static Map<String, Integer> nodeToId= new HashMap<>();
/**
* writes the graph for BLINKS into a text file
* @param fileName name of the grph file
* @throws IOException
*/
public void writeGraphForBLINKS(String fileName) throws IOException{
String folder ="d:\\DBLPgraph\\";
new File(folder).mkdir();
FileWriter fw= new FileWriter(folder+fileName+"BL.graph");
fw.write(graph.size()+"\n");
for(SteinerNode n: graph.keySet()){
fw.write(nodeToId.get(n.name())+" "+"0.0 "+nodeToId.get(n.name())+" \n");
}
for(Map.Entry<SteinerNode, TreeSet<SteinerEdge>> steinerNodeTreeSetEntry : graph.entrySet()){
for(SteinerEdge e: steinerNodeTreeSetEntry.getValue()){
if(nodeToId.get(steinerNodeTreeSetEntry.getKey().name())==null) nodeToId.put(steinerNodeTreeSetEntry.getKey().name(),1);
fw.write(nodeToId.get(steinerNodeTreeSetEntry.getKey().name())+" "
+nodeToId.get(steinerNodeTreeSetEntry.getKey().getNeighborInEdge(e).name())+" "+e.weight()+"\n");
}
}
fw.close();
fw= new FileWriter(folder+fileName+"BL.key");
for(SteinerNode n: graph.keySet()){
fw.write(nodeToId.get(n.name())+"---"+nodeToId.get(n.name())+"---"+"1\n");
}
fw.close();
fw= new FileWriter(folder+fileName+"BLStringToId.list");
for(SteinerNode n: graph.keySet()){
fw.write(nodeToId.get(n.name())+"---"+n.name()+"\n");
}
fw.close();
}
/**
* writes the graph for STAR into a text file
* @param fileName name of the graph file
* @throws IOException
*/
public void writeGraphForSTAR(String fileName) throws IOException{
// String folder ="d:\\DBLPgraph\\";
String folder ="/Users/mohsen/Documents/Academic/ISI/_GIT/Web-Karma/karma-research/";
new File(folder).mkdir();
FileWriter fw= new FileWriter(folder+fileName+"STAR.txt");
TreeSet<SteinerEdge> ts = new TreeSet<>();
for(Map.Entry<SteinerNode, TreeSet<SteinerEdge>> steinerNodeTreeSetEntry : graph.entrySet()){
for(SteinerEdge e: steinerNodeTreeSetEntry.getValue()){
if(ts.contains(e))continue;
fw.write(e.getEdgeLabel()+" : "+e.weight()+" : "+ steinerNodeTreeSetEntry.getKey().name()+" : "+ steinerNodeTreeSetEntry.getKey().getNeighborInEdge(e).name()+" : "+e.sourceNode.equals(steinerNodeTreeSetEntry.getKey())+"\n");
ts.add(e);
}
}
System.out.println("#edges: "+ts.size());
fw.close();
}
/**
* loads the graph from a text file into the main memory
* in case uniformWeights is true then all edges have weight 1,
* otherwise each edge has a random weight
* @throws IOException
*/
public void loadGraphFromFiles(boolean uniformWeights)throws IOException{
graph= new HashMap<>();
nodes = new HashMap<>();
//FileReader fr = new FileReader("d:\\DBLPgraph\\IMDBSTAR.txt");
FileReader fr = new FileReader("d:\\DBLPgraph\\dblpgraphNeighS.txt");
//FileReader fr = new FileReader("d:\\DBLPgraph\\DBLPSTAR.txt");
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
int k=0;
while(line!=null){
k++;
//if(k==30000) break;
String[]arr = line.split(" : ");
boolean isArg1=arr[4].equals("true");
//D.p(isArg1);D.p();
if(!nodes.containsKey(
arr[2])){
nodes.put(arr[2], new SteinerNode(arr[2]));
graph.put(nodes.get(arr[2]), new TreeSet<SteinerEdge>());
}
if(nodes.get(arr[3])==null){
nodes.put(arr[3], new SteinerNode(arr[3]));
graph.put(nodes.get(arr[3]), new TreeSet<SteinerEdge>());
}
SteinerEdge e;
if(!uniformWeights){
Random r= new Random();
arr[1]=String.valueOf(r.nextFloat());
}
if(isArg1) e= new SteinerEdge(nodes.get(arr[3]), arr[0].intern(), nodes.get(arr[2]) ,Float.valueOf(arr[1]));
else e= new SteinerEdge(nodes.get(arr[2]), arr[0].intern(), nodes.get(arr[3]),Float.valueOf(arr[1]));
graph.get(nodes.get(arr[2])).add(e);
graph.get(nodes.get(arr[3])).add(e);
line=br.readLine();
}
System.out.println(k + " edges loaded...");
br.close();
}
public void loadGraphFromFile(String filename)throws IOException{
graph= new HashMap<>();
nodes = new HashMap<>();
//FileReader fr = new FileReader("d:\\DBLPgraph\\IMDBSTAR.txt");
FileReader fr = new FileReader(filename);
//FileReader fr = new FileReader("d:\\DBLPgraph\\DBLPSTAR.txt");
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
int k=0;
while(line!=null){
k++;
//if(k==30000) break;
String[]arr = line.split(" : ");
boolean isArg1=arr[4].equals("true");
//D.p(isArg1);D.p();
if(!nodes.containsKey(
arr[2])){
nodes.put(arr[2], new SteinerNode(arr[2]));
graph.put(nodes.get(arr[2]), new TreeSet<SteinerEdge>());
}
if(nodes.get(arr[3])==null){
nodes.put(arr[3], new SteinerNode(arr[3]));
graph.put(nodes.get(arr[3]), new TreeSet<SteinerEdge>());
}
SteinerEdge e;
if(isArg1) e= new SteinerEdge(nodes.get(arr[3]), arr[0].intern(), nodes.get(arr[2]) ,Float.valueOf(arr[1]));
else e= new SteinerEdge(nodes.get(arr[2]), arr[0].intern(), nodes.get(arr[3]),Float.valueOf(arr[1]));
graph.get(nodes.get(arr[2])).add(e);
graph.get(nodes.get(arr[3])).add(e);
line=br.readLine();
}
System.out.println(k + " edges loaded...");
br.close();
}
protected Set<SteinerNode>terminalNodes;
protected ApprSteinerTree steinerTree;
protected List<Queue<SteinerNode>> iterators;
protected List<HashMap<String, SteinerNode>>visitedNodes;
protected Map<String, SteinerNode> forbiddenNodes;
protected Map<String, SteinerNode> almostForbiddenNodes;
protected Queue<ResultGraph> resultQueue;
/** Relations to exclude in interconnections */
// added by mohsen
protected List<ApprSteinerTree> addedSteinerTrees;
int accessedEdges=0;
public TopKSteinertrees() {
// TODO Auto-generated constructor stub
// added by mohsen
this.addedSteinerTrees = new LinkedList<>();
}
/**
*
* @param terminals the terminal nodes for which the Steiner trees are going to be constructed
* @throws Exception
*/
public TopKSteinertrees(TreeSet<SteinerNode> terminals)throws Exception {
terminalNodes=terminals;
iterators= new ArrayList<>(terminals.size());
visitedNodes= new ArrayList<>();
forbiddenNodes = new HashMap<>();
almostForbiddenNodes = new HashMap<>();
resultQueue= new LinkedList<>();
// added by mohsen
this.addedSteinerTrees = new LinkedList<>();
//for each terminal set an iterator
for(int i=0; i< terminals.size(); i++){
iterators.add(new LinkedList<SteinerNode>());
visitedNodes.add(new HashMap<String, SteinerNode>());
}
Iterator<SteinerNode> iteratorOfTerminals = terminalNodes.iterator();
for(Queue<SteinerNode> queue: iterators){
queue.offer(iteratorOfTerminals.next());
//System.out.println(iteratorOfTerminals.next().getNodeId());
}
}
/**
* This method reconstructs the first tree given the node (ancestor) that was reached
* by each of the iterators.
* @param ancestor the root node in a taxonomic tree
* @throws Exception
*/
public void getTaxonomicTree(SteinerNode ancestor) throws Exception{
TreeSet<SteinerNode> treeNodes = new TreeSet<>();
Map<String , SteinerNode> taxonomicTreeNodes= new HashMap<>();
taxonomicTreeNodes.put(ancestor.getNodeId(),new SteinerNode(ancestor.getNodeId()));
for(Map<String, SteinerNode> pnM: visitedNodes){
SteinerNode newNode=pnM.get(ancestor.getNodeId());
SteinerNode stNode=new SteinerNode(ancestor.getNodeId());
while(newNode!= null){
if (newNode.predecessor!= null){
if(taxonomicTreeNodes.containsKey(stNode.getNodeId())){
SteinerNode preNode=new SteinerNode(newNode.predecessor.getNodeId());
if(!taxonomicTreeNodes.containsKey(preNode.getNodeId())){
boolean isArg1=newNode.getEdgeToNode(newNode.predecessor).sourceNode.equals(stNode);
preNode.addEdge(taxonomicTreeNodes.get(stNode.getNodeId()),
isArg1,newNode.getEdgeLabelToNode(newNode.predecessor),
newNode.getEdgeToNode(newNode.predecessor).weight());
taxonomicTreeNodes.put(preNode.getNodeId(), preNode);
}
stNode= new SteinerNode(newNode.predecessor.getNodeId());
}
}
newNode=newNode.predecessor;
}
}
clean(taxonomicTreeNodes);
treeNodes.addAll(taxonomicTreeNodes.values());
steinerTree=new ApprSteinerTree(terminalNodes, treeNodes);
}
/**
* cleans a result tree, that is, nodes that are no terminlas and have a degree of 1 are
* deleted from the tree since they just increase the weight of the tree...
* @param map
*/
protected void clean (Map<String, SteinerNode> map){
LinkedList<SteinerNode> outliers = new LinkedList<>();
for(SteinerNode n: map.values())
if(!terminalNodes.contains(n)&& n.getDegree()==1)
outliers.add(n);
for(SteinerNode n: outliers)
while(n.getDegree()<2 && !terminalNodes.contains(n)){
SteinerNode node=n.getNeighbors().first();
node.edges.remove(node.getEdgeToNode(n));
map.remove(n.getNodeId());
n=node;
}
}
/**
* finds out whether all iterators hav visited the given node n
* @param n the node for which the check is being done
* @return true in case all iterators have visited the node n
* @throws Exception
*/
public boolean isCommonAncestor(SteinerNode n)throws Exception{
boolean isCAncestor= true;
for(Map<String, SteinerNode> pnM: visitedNodes){
if(!pnM.containsKey(n.getNodeId())) isCAncestor=false;
}
if(isCAncestor){
//n.print(); D.p(" Das ist es!!!");
getTaxonomicTree(n);
return isCAncestor;
}
return isCAncestor;
}
/**
*
* @param v node which was reached by one of the iterators, note that
* there is a node with the same name as v in initialSet2
* @param visitedNodes nodes visited by the iterator by which v is reached
* @param initialSet1 one initial set of nodes resulting from the removal of a loosepath.
* The iterator that reaches v has started from this inital set.
* @param initialSet2 the other initial set of nodes resulting from the removal of a loosepath.
* @return a new tree which has a path that connects the two initial sets
*/
protected ApprSteinerTree getApprTreeFrom(SteinerNode v, Map<String, SteinerNode>visitedNodes,
Set<SteinerNode>initialSet1, Set<SteinerNode>initialSet2){
v=visitedNodes.get(v.name());
for(SteinerNode n: initialSet2){
if(v.equals(n)){
//v.print();
n.addEdge(v.predecessor, !v.wasArg1, v.relationToPredecessor,v.weightToPredecessor);
break;
}
}
v=v.predecessor;
Map<String, SteinerNode> resultSet= new HashMap<>();
Map<String, SteinerNode> treeNodeSet= new HashMap<>();
for(SteinerNode n: initialSet1){resultSet.put(n.name(), n);treeNodeSet.put(n.name(), new SteinerNode(n.name()));}
for(SteinerNode n: initialSet2){resultSet.put(n.name(), n);treeNodeSet.put(n.name(), new SteinerNode(n.name()));}
//follow the predecessors of v until a predecessor
//is contained in initialSet1
while(!initialSet1.contains(v)){
SteinerNode newNode = v.predecessor;
v.addEdge(v.predecessor, !v.wasArg1, v.relationToPredecessor, v.weightToPredecessor);
resultSet.put(v.name(),v);
treeNodeSet.put(v.name(), new SteinerNode(v.name()));
v = newNode;
}
// make sure all edges are ok!
TreeSet<SteinerEdge> copyOfEdges= new TreeSet<>();
for(SteinerNode n: resultSet.values()){
copyOfEdges.addAll(n.edges);
}
for(SteinerEdge e: copyOfEdges){
treeNodeSet.get(e.sourceNode.name()).addEdge(
treeNodeSet.get(e.sinkNode.name()), false, e.getEdgeLabel(), e.weight());
}
Set<SteinerNode> treeNodes= new TreeSet<>();
treeNodes.addAll(treeNodeSet.values());
//D.p(resultSet.values());
return new ApprSteinerTree(terminalNodes, treeNodes);
}
/**
*
* @param v node reached by the iterator that started from initialSet1
* @param visitedNodes1 nodes visited by the iterator that started from initialSet1
* @param visitedNodes2 nodes visited by the iterator that started from initialSet2
* @param initialSet1 one initial set of nodes resulting from the removal of a loosepath.
* The iterator that reaches v has started from this inital set.
* @param initialSet2 the other initial set of nodes resulting from the removal of a loosepath.
* @return a new tree which has a path that connects the two initial sets
*/
protected ApprSteinerTree getApprTreeFrom(SteinerNode v, Map<String, SteinerNode>visitedNodes1,
Map<String, SteinerNode>visitedNodes2, Set<SteinerNode>initialSet1,
Set<SteinerNode>initialSet2){
Map<String, SteinerNode> resultSet= new HashMap<>();
for(SteinerNode n: initialSet1)resultSet.put(n.name(), n);
for(SteinerNode n: initialSet2)resultSet.put(n.name(), n);
SteinerNode newNode= v.predecessor;
SteinerNode n=visitedNodes2.get(v.name());
n.addEdge(newNode,
!v.wasArg1,
v.relationToPredecessor,
v.weightToPredecessor);
while(!initialSet2.contains(n)){
SteinerNode m= n.predecessor;
n.addEdge(m, !n.wasArg1, n.relationToPredecessor, n.weightToPredecessor);
resultSet.put(n.name(),n);
n = m;
}
while(!initialSet1.contains(newNode)){
SteinerNode m= newNode.predecessor;
newNode.addEdge(m, !newNode.wasArg1, newNode.relationToPredecessor, newNode.weightToPredecessor);
resultSet.put(newNode.name(),newNode);
newNode = m;
}
//make sure all edges are ok!
for(SteinerNode node: resultSet.values()){
TreeSet<SteinerEdge> copyOfEdges= new TreeSet<>();
copyOfEdges.addAll(node.edges);
for(SteinerEdge e: copyOfEdges){
node.edges.remove(e);
node.addEdge(new SteinerEdge(resultSet.get(e.sourceNode.name()),
e.getEdgeLabel(), resultSet.get(e.sinkNode.name()),e.weight()));
}
}
Set<SteinerNode> treeNodes= new TreeSet<>();
treeNodes.addAll(resultSet.values());
//D.p(resultSet.values());
return new ApprSteinerTree(terminalNodes, treeNodes);
}
/**
* This method constructs a first teaxonomic tree that contains all the
* terminals.
* @throws Exception
*/
public abstract void buildTaxonomicGraph() throws Exception;
/**
*
* @param k number of steiner trees to be returned
* @return Queue contining top-k steiner trees
* @throws Exception
*/
public abstract Queue<ResultGraph> getTopKTrees(int k)throws Exception;
public ApprSteinerTree getSteinerTree() {
return steinerTree;
}
public Queue<ResultGraph> getResultQueue() {
return resultQueue;
}
}