/*******************************************************************************
* Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tamas Szabo - initial API and implementation
*******************************************************************************/
package org.eclipse.incquery.runtime.base.itc.alg.misc.scc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.eclipse.incquery.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
import org.eclipse.incquery.runtime.base.itc.igraph.IBiDirectionalWrapper;
import org.eclipse.incquery.runtime.base.itc.igraph.IGraphDataSource;
import org.eclipse.incquery.runtime.base.itc.igraph.IGraphObserver;
public class PKAlg<V> implements IGraphObserver<V> {
private static final long serialVersionUID = -4382533946686076317L;
/**
* Maps the nodes to their indicies.
*/
private HashMap<V, Integer> node2index;
private HashMap<Integer, V> index2node;
private HashMap<V, Boolean> node2mark;
/**
* Maps the index of a node to the index in the topsort.
*/
private HashMap<Integer, Integer> index2topsort;
private HashMap<Integer, Integer> topsort2index;
/**
* Index associated to the inserted nodes (incrementing with every insertion).
*/
private int index;
/**
* Index within the topsort for the target node when edge insertion occurs.
*/
private int lower_bound;
/**
* Index within the topsort for the source node when edge insertion occurs.
*/
private int upper_bound;
private ArrayList<V> RF;
private ArrayList<V> RB;
private IBiDirectionalGraphDataSource<V> gds;
public PKAlg(IGraphDataSource<V> gds) {
if (gds instanceof IBiDirectionalGraphDataSource<?>) {
this.gds = (IBiDirectionalGraphDataSource<V>) gds;
} else {
this.gds = new IBiDirectionalWrapper<V>(gds);
}
node2mark = new HashMap<V, Boolean>();
node2index = new HashMap<V, Integer>();
index2node = new HashMap<Integer, V>();
index2topsort = new HashMap<Integer, Integer>();
topsort2index = new HashMap<Integer, Integer>();
index = 0;
gds.attachObserver(this);
}
@Override
public void edgeInserted(V source, V target) {
RF = new ArrayList<V>();
RB = new ArrayList<V>();
lower_bound = index2topsort.get(node2index.get(target));
upper_bound = index2topsort.get(node2index.get(source));
if (lower_bound < upper_bound) {
dfsForward(target);
dfsBackward(source);
reorder();
}
}
private ArrayList<Integer> getIndicies(ArrayList<V> list) {
ArrayList<Integer> indicies = new ArrayList<Integer>();
for (V n : list)
indicies.add(index2topsort.get(node2index.get(n)));
return indicies;
}
private void reorder() {
Collections.reverse(RB);
// azon csomopontok indexei amelyek sorrendje nem jo
ArrayList<Integer> L = getIndicies(RF);
L.addAll(getIndicies(RB));
Collections.sort(L);
for (int i = 0; i < RB.size(); i++) {
index2topsort.put(node2index.get(RB.get(i)), L.get(i));
topsort2index.put(L.get(i), node2index.get(RB.get(i)));
}
for (int i = 0; i < RF.size(); i++) {
index2topsort.put(node2index.get(RF.get(i)), L.get(i + RB.size()));
topsort2index.put(L.get(i + RB.size()), node2index.get(RF.get(i)));
}
}
@SuppressWarnings("unused")
private List<V> getTopSort() {
List<V> topsort = new ArrayList<V>();
for (int i : topsort2index.values()) {
topsort.add(index2node.get(i));
}
return topsort;
}
private void dfsBackward(V node) {
node2mark.put(node, true);
RB.add(node);
List<V> sources = gds.getSourceNodes(node);
if (sources != null)
for (V sn : sources) {
int top_id = index2topsort.get(node2index.get(sn));
if (!node2mark.get(sn) && lower_bound < top_id)
dfsBackward(sn);
}
}
private void dfsForward(V node) {
node2mark.put(node, true);
RF.add(node);
List<V> targets = gds.getTargetNodes(node);
if (targets != null)
for (V tn : targets) {
int top_id = index2topsort.get(node2index.get(tn));
if (top_id == upper_bound)
System.out.println("!!!Cycle detected!!!");
else if (!node2mark.get(tn) && top_id < upper_bound)
dfsForward(tn);
}
}
@Override
public void edgeDeleted(V source, V target) {
// Edge deletion does not affect topsort
}
@Override
public void nodeInserted(V n) {
node2mark.put(n, false);
node2index.put(n, index);
index2node.put(index, n);
index2topsort.put(index, index);
topsort2index.put(index, index);
index++;
}
@Override
public void nodeDeleted(V n) {
node2mark.remove(n);
int node_id = node2index.remove(n);
index2node.remove(node_id);
int top_id = index2topsort.remove(node_id);
topsort2index.remove(top_id);
}
}