/**
*
*/
package statechum.analysis.learning;
import java.awt.Frame;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
import java.util.Vector;
import statechum.Configuration;
import statechum.DeterministicDirectedSparseGraph;
import statechum.JUConstants;
import statechum.Pair;
import statechum.analysis.learning.observers.Learner;
import statechum.analysis.learning.rpnicore.LearnerGraph;
import statechum.model.testset.PTASequenceEngine;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath;
import edu.uci.ics.jung.algorithms.shortestpath.ShortestPathUtils;
import edu.uci.ics.jung.algorithms.shortestpath.UnweightedShortestPath;
import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.impl.DirectedSparseEdge;
import edu.uci.ics.jung.graph.impl.DirectedSparseGraph;
import edu.uci.ics.jung.graph.impl.DirectedSparseVertex;
import edu.uci.ics.jung.utils.UserData;
/**
* @author kirr
*
*/
public class RPNIBlueFringeLearnerOrig extends RPNIBlueFringeLearner {
public RPNIBlueFringeLearnerOrig(Frame parent, Configuration c) {
super(parent, c);
}
protected Graph currentGraph = DeterministicDirectedSparseGraph.initialise();
protected HashSet<DirectedSparseEdge> doneEdges;
protected Collection<List<String>> sPlus, sMinus;
public static Collection<String> getAlphabetForEdges(Collection<Edge> edges){
HashSet<String> alphabet = new HashSet<String>();
Iterator<Edge> edgeIt = edges.iterator();
while(edgeIt.hasNext()){
Edge e = (edgeIt.next());
alphabet.addAll((Collection<String>)e.getUserDatum(JUConstants.LABEL));
}
return alphabet;
}
public Collection<List<String>> getSMinus() {
return sMinus;
}
public Collection<List<String>> getSPlus() {
return sPlus;
}
protected Graph removeNegatives(Graph g){
Iterator<Vertex> vertexIt = g.getVertices().iterator();
HashSet<Vertex> remove = new HashSet<Vertex>();
while(vertexIt.hasNext()){
Vertex v = vertexIt.next();
if(!DeterministicDirectedSparseGraph.isAccept(v)&&!DeterministicDirectedSparseGraph.isInitial(v))
remove.add(v);
}
Iterator<Vertex> removeIt = remove.iterator();
while(removeIt.hasNext()){
g.removeVertex(removeIt.next());
}
return g;
}
/** Takes all red-labelled nodes; non-red nodes which can be reached by a single transition from any
* red one is labelled blue.
*
* @param model
* @return the set of blue nodes.
*/
protected Set<Vertex> computeBlue(DirectedSparseGraph model){
Set<Vertex> blues = new HashSet<Vertex>();
for(Vertex v: DeterministicDirectedSparseGraph.findVertices(JUConstants.COLOUR, JUConstants.RED, model))
{
Iterator<DirectedSparseEdge>neighbourIt = v.getOutEdges().iterator();
while(neighbourIt.hasNext()){
DirectedSparseEdge next = neighbourIt.next();
Vertex neighbour = next.getDest();
JUConstants neighbourColour = (JUConstants)neighbour.getUserDatum(JUConstants.COLOUR);
if(neighbourColour!=null){
if(neighbourColour == JUConstants.RED)
continue;
}
neighbour.setUserDatum(JUConstants.COLOUR, JUConstants.BLUE, UserData.SHARED);
blues.add(neighbour);
}
}
//updateGraph(model);
return blues;
}
public static class OrigStatePair implements Comparable<OrigStatePair> {
private Vertex q, r;
public OrigStatePair(Vertex blue, Vertex red){
this.q = blue;
this.r = red;
}
private static String strLabel(Vertex v){
String vLabel = v.getUserDatum(JUConstants.LABEL).toString();
return vLabel;
}
public int compareTo(OrigStatePair pB){
int qLabels = strLabel(q).compareTo(strLabel(pB.getQ()));
int rLabels = strLabel(r).compareTo(strLabel(pB.getR()));
if(qLabels != 0)
return qLabels;
return rLabels;
}
public Vertex getQ(){
return q;
}
public Vertex getR(){
return r;
}
public String toString(){
return "[ "+((q == null)?"NULL":q.getUserDatum(JUConstants.LABEL))+", "+((r == null)?"NULL":r.getUserDatum(JUConstants.LABEL))+" ]";
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode(){
final int PRIME = 31;
return q.getUserDatum(JUConstants.LABEL).hashCode()+PRIME*r.getUserDatum(JUConstants.LABEL).hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o){
if(o == null)
return false;
if(o instanceof OrigStatePair){
OrigStatePair other = (OrigStatePair)o;
Object otherQ = other.getQ().getUserDatum(JUConstants.LABEL);
Object otherR = other.getR().getUserDatum(JUConstants.LABEL);
Object thisQ = q.getUserDatum(JUConstants.LABEL);
Object thisR = r.getUserDatum(JUConstants.LABEL);
if(thisQ.equals(otherQ)&&thisR.equals(otherR))
return true;
}
return false;
}
}
/** Makes a copy of the graph given to it and merges states in the pair supplied. */
public static DirectedSparseGraph mergeAndDeterminize(Graph model, OrigStatePair pair){
Graph original = (Graph)model.copy();
Vertex q = DeterministicDirectedSparseGraph.findVertex(JUConstants.LABEL, pair.getQ().getUserDatum(JUConstants.LABEL),original);
Vertex qDash = DeterministicDirectedSparseGraph.findVertex(JUConstants.LABEL, pair.getR().getUserDatum(JUConstants.LABEL),original);
pair = new OrigStatePair(q,qDash);
DirectedSparseGraph temp = merge((DirectedSparseGraph)original, pair);
OrigStatePair mergable = findMergablePair(temp);
while(mergable!=null){
temp=merge(temp, mergable);
mergable = findMergablePair(temp);
}
return temp;
}
protected DirectedSparseGraph createAugmentedPTA(DirectedSparseGraph model, Collection<List<String>> plus, Collection<List<String>> minus){
init(plus,minus);
model = augmentPTA(model, sMinus, false);
model = augmentPTA(model, sPlus, true);
DeterministicDirectedSparseGraph.numberVertices(model);
return model;
}
@Override
public void init(Collection<List<String>> plus, Collection<List<String>> minus)
{
sPlus = plus;
sMinus = minus;
}
@Override
public void init(@SuppressWarnings("unused") PTASequenceEngine en,
@SuppressWarnings("unused") int plus,
@SuppressWarnings("unused") int minus)
{
throw new NotImplementedException();
}
@Override
public DirectedSparseGraph learnMachine()
{
return learnMachine(DeterministicDirectedSparseGraph.initialise());
}
public DirectedSparseGraph learnMachine(DirectedSparseGraph model) {
model = createAugmentedPTA(model, sPlus, sMinus);
Vertex init = DeterministicDirectedSparseGraph.findInitial(model);
init.setUserDatum(JUConstants.COLOUR, JUConstants.RED, UserData.SHARED);
Stack<OrigStatePair> possibleMerges = chooseStatePairs(model, sPlus, sMinus);
while(!possibleMerges.isEmpty()){
OrigStatePair pair = possibleMerges.pop();
DirectedSparseGraph temp = mergeAndDeterminize((Graph)model.copy(), pair);
if(compatible(temp, sPlus, sMinus)){// KIRR: the should always return true
pair.getQ().setUserDatum(JUConstants.HIGHLIGHT, pair, UserData.SHARED);
pair.getR().setUserDatum(JUConstants.HIGHLIGHT, pair, UserData.SHARED);
setChanged();
List<List<String>> questions;
if(config.getAskQuestions())
questions = generateQuestions(model, pair);
else
questions = new ArrayList<List<String>>();
questions = trimSet(questions);
Iterator<List<String>> questionIt = questions.iterator();
while(questionIt.hasNext()){
List<String> question = questionIt.next();
boolean accepted = DeterministicDirectedSparseGraph.isAccept(pair.getQ());// Q is the blue vertex
Pair<Integer,String> response = checkWithEndUser(new LearnerGraph(model,Configuration.getDefaultConfiguration()),question,new Object[0]);// zero means "yes", everything else is "no"
questionCounter++;
pair.getQ().removeUserDatum(JUConstants.HIGHLIGHT);
pair.getR().removeUserDatum(JUConstants.HIGHLIGHT);
if(response.firstElem == USER_ACCEPTED){
sPlus.add(question);
System.out.println(howAnswerWasObtained+question+ " <yes>");
if(accepted == false)// KIRR: how can this be true? If it were so, there would be no questions to ask
return learnMachine(DeterministicDirectedSparseGraph.initialise());
}
else{
sMinus.add(question.subList(0, response.firstElem));
System.out.println(howAnswerWasObtained+question+ " <no>");
if(accepted == true){// KIRR: this cannot be false either
return learnMachine(DeterministicDirectedSparseGraph.initialise());
}
}
}
model = temp;
}
possibleMerges = chooseStatePairs(model, sPlus, sMinus);
}
System.out.println("finished");
return model;
}
protected boolean compatible(DirectedSparseGraph model, Collection<List<String>> sPlus, Collection<List<String>> sMinus){
boolean returnValue = true;
for(List<String> string:sMinus)
{
Vertex v = getVertex(model,string);
if(v != null){
if(DeterministicDirectedSparseGraph.isAccept(v))
returnValue = false;
}
}
for(List<String> string:sPlus)
{
Vertex v = getVertex(model,string);
if(v == null)
returnValue = false;
else{
if(!DeterministicDirectedSparseGraph.isAccept(v))
returnValue = false;
}
}
return returnValue;
}
/** Removes question sequences which are prefixes of other questions.
*
* @param questions
* @return a set of questions which are not prefixes of other questions.
*/
protected List<List<String>> trimSet(List<List<String>> questions){
Set<String> done = new HashSet<String>();
List<List<String>> trimmedSet = new ArrayList<List<String>>();
Iterator<List<String>> questionIt = questions.iterator();
while(questionIt.hasNext()){
List<String> question = questionIt.next();
Iterator<String> stringIt = question.iterator();
String questionString=new String();
while(stringIt.hasNext())
questionString = questionString.concat("]["+stringIt.next());
if(!done.contains(questionString.trim())){
done.add(questionString.trim());
trimmedSet.add(question);
}
}
return trimmedSet;
}
/*
* needs to be refactored into smaller methods
*/
protected List<List<String>> generateQuestions(DirectedSparseGraph model, OrigStatePair pair){
Vertex q = pair.getQ();
Vertex r = pair.getR();
if(q==null || r ==null)
return new ArrayList<List<String>>();
boolean accepted = DeterministicDirectedSparseGraph.isAccept(q);
if(accepted == false)
return new ArrayList<List<String>>();
List<String> sp = null;
Set<List<String>> w =null;
if(!hasAcceptedNeighbours(q)){
sp = getShortPrefix(model, q);
w = getShortSuffixes(model, r);
}
else{
sp = getShortPrefix(model, r);// shortest sequence to the red state
w = getSuffixes(model,q, accepted);
}
Iterator<List<String>> wIt;
ArrayList<List<String>> questions = new ArrayList<List<String>>();
Set<String>loopLabels = new HashSet<String>();
boolean loopToR = r.getSuccessors().contains(r);
boolean redAndBlueNeighbours = r.getNeighbors().contains(q);
if(loopToR||redAndBlueNeighbours){ //there either exists a loop to r or will do if r and b merge
if(loopToR){
Edge e = findEdge(r, r);
HashSet<String> labels = (HashSet<String>)e.getUserDatum(JUConstants.LABEL);
loopLabels.addAll(labels);
}
if(redAndBlueNeighbours){
Edge e = findEdge(r,q);
HashSet<String> labels = (HashSet<String>)e.getUserDatum(JUConstants.LABEL);
loopLabels.addAll(labels);
}
}
wIt = w.iterator();
while(wIt.hasNext()){
List<String> suffix = wIt.next();
Iterator<String> labelIt = loopLabels.iterator();
if(!loopLabels.isEmpty()){
while(labelIt.hasNext()){
List<String> newQuestion = new ArrayList<String>();
newQuestion.addAll(sp);
newQuestion.add(labelIt.next());
newQuestion.addAll(suffix);
Vertex v = getVertex(model, newQuestion);
if(v==null)
questions.add(newQuestion);
}
}
List<String> newQuestion = new ArrayList<String>();
newQuestion.addAll(sp);
newQuestion.addAll(suffix);
Vertex v = getVertex(model, newQuestion);
if(v==null)
questions.add(newQuestion);
}
return questions;
}
/*
* The conventional approach to computing suffixes presumes that the source vertex is the root
* of a tree. This method does not make that presumption, but simply returns the direct successors
* of the source vertex that are accepted.
*/
protected static HashSet<List<String>> getShortSuffixes(DirectedSparseGraph g, Vertex v){
HashSet<List<String>> returnStrings = new HashSet<List<String>>();
Iterator<Edge> outEdgeIt = v.getOutEdges().iterator();
while(outEdgeIt.hasNext()){
Edge e = outEdgeIt.next();
if(DeterministicDirectedSparseGraph.isAccept(e.getOpposite(v))){
ArrayList<Edge> l = new ArrayList<Edge>();
l.add(e);
returnStrings.addAll(getPaths(l));
}
}
return returnStrings;
}
public static boolean hasAcceptedNeighbours(Vertex v){
Iterator<DirectedSparseEdge> neighbourIt = v.getOutEdges().iterator();
while (neighbourIt.hasNext()){
DirectedSparseEdge e = neighbourIt.next();
Vertex to = e.getDest();
if(DeterministicDirectedSparseGraph.isAccept(to))
return true;
}
return false;
}
/** Returns shortest paths from the given vertex to states at the end of the
* PTA (those with no outgoing transitions) which
* satisfy the requested accept/reject labelling.
* @param graph
* @param r the vertex to consider.
* @param accepted labelling requested.
* @return the list of paths.
*/
protected Set<List<String>> getSuffixes(DirectedSparseGraph graph, Vertex r, boolean accepted){
Set<List<String>> setOfPaths = new HashSet<List<String>>();
Iterator<Vertex> vertexIt = graph.getVertices().iterator();
Set<Vertex> endVertices = new HashSet<Vertex>();
DijkstraShortestPath p = new DijkstraShortestPath(graph);
while(vertexIt.hasNext()){
Vertex v = vertexIt.next();
if(v.getSuccessors().isEmpty()&& DeterministicDirectedSparseGraph.isAccept(v) == accepted)
endVertices.add(v);
}
for(Vertex v:endVertices)
{
List l = p.getPath(r, v);
if(!l.isEmpty())
setOfPaths.addAll(getPaths(l));
}
return setOfPaths;
}
/** Given a sequence of edges, builds a set of sequences of labels which will traverse
* the given sequence. This builds l[0]*l[1] .. where l[i] is a set of labels associated
* with l[i] and * is pairwise set concatenation operation.
* KIRR: this is the set multiplication from test set generation algorithm - surely the code must be possible to share
*
* @param l path
* @return
*/
protected static Set<List<String>> getPaths(List<Edge> l){
TreeMap<Integer,Set<List<String>>> returnSet = new TreeMap<Integer,Set<List<String>>>();// KIRR: this should not be done in this way since access to this map is not random - you only need the last element in which case simply storing the last set of lists is best
for(int i=0;i<l.size();i++){// for each element of the source list
Edge e = l.get(i);
Set<String> labels = (Set<String>)e.getUserDatum(JUConstants.LABEL);
Set<List<String>> strings = new HashSet<List<String>>();
for(String s:labels)
{
if(i==0){
List<String> string = new ArrayList<String>();
string.add(s);
strings.add(string);
}
else{
Set<List<String>> oldStrings = returnSet.get(i-1);
Iterator<List<String>> stringIt = oldStrings.iterator();
while(stringIt.hasNext()){
List<String> newString = new ArrayList<String>();
newString.addAll(stringIt.next());
newString.add(s);
strings.add(newString);
}
}
}
returnSet.put(i, strings);
}
if(!returnSet.isEmpty())
return returnSet.get(returnSet.lastKey());
return new HashSet<List<String>>();
}
/** Returns a sequence of names labelling a shortest path from the initial node to node q. */
protected static List<String> getShortPrefix(DirectedSparseGraph model, Vertex q){
Vertex init = DeterministicDirectedSparseGraph.findInitial(model);
UnweightedShortestPath p = new UnweightedShortestPath(model);
Iterator<Edge> pathIt = ShortestPathUtils.getPath(p, init, q).iterator();
List<String> list = new ArrayList<String>();
while(pathIt.hasNext()){
Edge e = pathIt.next();
Set<String> s = (Set<String>)e.getUserDatum(JUConstants.LABEL);
Object[] strings = s.toArray();
list.add(strings[0].toString());
}
return list;
}
protected static DirectedSparseGraph merge(DirectedSparseGraph model, OrigStatePair pair){
Vertex q = pair.getQ();
Vertex qDash = pair.getR();
Iterator<DirectedSparseEdge> inEdges = q.getInEdges().iterator();
Set<DirectedSparseEdge> removeEdges = new HashSet<DirectedSparseEdge>();
while(inEdges.hasNext()){
DirectedSparseEdge e = inEdges.next();
DirectedSparseEdge eDash = new DirectedSparseEdge(e.getSource(), qDash);
eDash.addUserDatum(JUConstants.LABEL, e.getUserDatum(JUConstants.LABEL), UserData.CLONE);
if(!e.getSource().getSuccessors().contains(qDash))
model.addEdge(eDash);
else{
Edge existing = findEdge(e.getSource(), qDash);
Set<String> labels = (Set<String>)existing.getUserDatum(JUConstants.LABEL);// KIRR: if you use UserData.SHARED, you do not need to copy the result back using put
labels.addAll((Set<String>)e.getUserDatum(JUConstants.LABEL));
existing.setUserDatum(JUConstants.LABEL, labels, UserData.CLONE);
}
removeEdges.add(e);
}
Iterator<DirectedSparseEdge> outEdges = q.getOutEdges().iterator();
while(outEdges.hasNext()){
DirectedSparseEdge e = outEdges.next();
DirectedSparseEdge eDash = new DirectedSparseEdge(qDash, e.getDest());
eDash.addUserDatum(JUConstants.LABEL, e.getUserDatum(JUConstants.LABEL), UserData.CLONE);
if(!qDash.getSuccessors().contains(e.getDest()))
model.addEdge(eDash);
else{
Edge existing = findEdge(qDash, e.getDest());
Set<String> labels = (Set<String>)existing.getUserDatum(JUConstants.LABEL);
labels.addAll((Set<String>)e.getUserDatum(JUConstants.LABEL));
existing.setUserDatum(JUConstants.LABEL, labels, UserData.CLONE);
}
removeEdges.add(e);
}
model.removeEdges(removeEdges);
model.removeVertex(q);
return model;
}
/** After merging, a graph may exhibit non-determinism, in which case it is made deterministic
* by merging nodes. For instance, for A->B and A->C being a non-deterministic choice at node A,
* nodes B and C are to
* be merged. This function identifies such a (B,C).
*
* @param model
* @return a pair of states to be merged or null if the graph is deterministic.
*/
protected static OrigStatePair findMergablePair(DirectedSparseGraph model){
List<Vertex> queue = DeterministicDirectedSparseGraph.getBFSList(model);
Iterator<Vertex> queueIt = queue.iterator();
while(queueIt.hasNext()){
Vertex v = queueIt.next();
Set<DirectedSparseEdge> edges = v.getOutEdges();
Iterator<DirectedSparseEdge> edgeIt = edges.iterator();
Map<String,DirectedSparseEdge> doneLabels = new HashMap<String,DirectedSparseEdge>();
while(edgeIt.hasNext()){
DirectedSparseEdge e = edgeIt.next();
Set<String> labels = (Set<String>)e.getUserDatum(JUConstants.LABEL);
Iterator<String> labelIt = labels.iterator();
while(labelIt.hasNext()){
String label = labelIt.next();
if(doneLabels.get(label)==null)
doneLabels.put(label, e);
else {
DirectedSparseEdge eDash = doneLabels.get(label);
OrigStatePair p = null;
if(DeterministicDirectedSparseGraph.isInitial(eDash.getDest()))
p = new OrigStatePair(e.getDest(), eDash.getDest());
else
p = new OrigStatePair(eDash.getDest(),e.getDest());
if(!different(p)) // KIRR: strange - the two should never be different if the original pair to choose was selected properly
return p;
}
}
}
}
return null;
}
protected Stack<OrigStatePair> chooseStatePairs(DirectedSparseGraph g, Collection<List<String>> sPlus, Collection<List<String>> sMinus){
Stack<Vertex> blueStack = new Stack<Vertex>();
blueStack.addAll(computeBlue(g));
TreeMap<Integer,Vector<OrigStatePair> > scoreToPair = new TreeMap<Integer,Vector<OrigStatePair> >();// maps scores to pairs which have those scores
while(!blueStack.isEmpty()){
TreeMap<Integer,Vector<OrigStatePair> > singleSet = new TreeMap<Integer,Vector<OrigStatePair> >();
Vertex blueVertex = blueStack.pop();
Stack<Vertex> redStack = new Stack<Vertex>();
redStack.addAll(DeterministicDirectedSparseGraph.findVertices(JUConstants.COLOUR, JUConstants.RED, g));
while(!redStack.isEmpty()){
Vertex redVertex = redStack.pop();
OrigStatePair pair = new OrigStatePair(blueVertex, redVertex);
doneEdges = new HashSet<DirectedSparseEdge>();
Integer score = new Integer(computeScore(g,pair));
DirectedSparseGraph temp = mergeAndDeterminize((Graph)g.copy(), pair);
if(compatible(temp, sPlus, sMinus)){
// singleSet maps scores to pairs which have those scores
if(score<config.getKlimit())
continue;
if(singleSet.get(score) == null){
// nothing yet with this score
Vector<OrigStatePair> s = new Vector<OrigStatePair>();
s.add(pair);
singleSet.put(score, s);
}
else{
// already some pairs with this score
Vector<OrigStatePair> s = singleSet.get(score);
s.add(pair);
singleSet.put(score, s);
}
}
}
if(singleSet.isEmpty()){// no new pairs found, marking the current blue vertex as red.
blueVertex.setUserDatum(JUConstants.COLOUR, JUConstants.RED, UserData.SHARED);
blueStack.clear();
scoreToPair.clear();
blueStack.addAll(computeBlue(g));
}
else{
Iterator keyIt = singleSet.keySet().iterator();
while(keyIt.hasNext()){
Integer key = (Integer)keyIt.next();
Vector<OrigStatePair> s = scoreToPair.get(key);
if(s!=null){
s.addAll(singleSet.get(key));
Collections.sort(s);
}
else
{
Vector<OrigStatePair> value = singleSet.get(key);
Collections.sort(value);
scoreToPair.put(key, value);
}
}
}
}
return createOrderedStack(scoreToPair);
}
protected Stack<OrigStatePair> createOrderedStack(TreeMap<Integer,Vector<OrigStatePair> > sets){
Stack<OrigStatePair> values = new Stack<OrigStatePair>();
if(config.getPairsMergedPerHypothesis()>0){
Stack<Integer> keys = new Stack<Integer>();
keys.addAll(sets.keySet());
for(int i = 0;i< config.getPairsMergedPerHypothesis(); i++){
if(keys.isEmpty())
continue;
Vector<OrigStatePair> pairs = sets.get(keys.pop());
values.addAll(pairs);
}
}
else for(Vector<OrigStatePair> v:sets.values()){
values.addAll(v);
}
return values;
}
/** For every pair of transitions with the same label from a supplied pair of states
* this function recursively invokes itself and adds 1 to the result.
* KIRR: this should do the W set construction to determine whether two states are equivalent,
* but do it in the clever way, considering incompleteness.
*
* @param original the graph to operate on
* @param blueRed the pair of states
* @return
*/
protected int computeScore(DirectedSparseGraph original, OrigStatePair blueRed){
int returnValue = 0;
if(different(blueRed))
return -1;
Iterator<DirectedSparseEdge> edgesOut = blueRed.getQ().getOutEdges().iterator();
while(edgesOut.hasNext()){
DirectedSparseEdge e = edgesOut.next();
if(this.doneEdges.contains(e))
continue;
doneEdges.add(e);
HashSet<String> labels = (HashSet<String>)e.getUserDatum(JUConstants.LABEL);
Iterator<String> labelIt = labels.iterator();
while(labelIt.hasNext()){
List<String> string = new ArrayList<String>();
string.add(labelIt.next());
Vertex qi = e.getDest();
Vertex qj = getVertex(original,blueRed.getR(), string);
OrigStatePair newPair = new OrigStatePair(qi, qj);
if(qj!=null){
int equivalent = computeScore(original, newPair);
if(equivalent<0){
return -1;
}
returnValue++;
returnValue= returnValue + equivalent;
}
}
}
return returnValue;
}
/** Adds a given set of sequences to a PTA, with a specific accept-reject labelling.
*
* @param pta
* @param strings sequences to be added
* @param accepted whether sequences are accept or reject ones.
* @return the result of adding.
*/
DirectedSparseGraph augmentPTA(DirectedSparseGraph pta, Collection<List<String>> strings, boolean accepted){
Iterator<List<String>> stringsIt = strings.iterator();
while(stringsIt.hasNext()){
List<String> string = stringsIt.next();
if (string.isEmpty() && !accepted)
throw new IllegalArgumentException("since the initial state is an accept one, a negative string should not be empty");
for(int i = 1;i<=string.size();i++){
List<String> current = string.subList(0, i);
Vertex existing = getVertex(pta,current);
Vertex newVertex = new DirectedSparseVertex();
if (i == string.size())// KIRR: every prefix of a reject sequence is an accept sequence.
newVertex.setUserDatum(JUConstants.ACCEPTED, accepted, UserData.SHARED);
else
newVertex.setUserDatum(JUConstants.ACCEPTED, true, UserData.SHARED);
if(existing == null){
pta.addVertex(newVertex);
Vertex previous;
previous = getVertex(pta, string.subList(0, i-1));// for i==1, getVertex will return the initial vertex
DirectedSparseEdge e = new DirectedSparseEdge(previous, newVertex);
Set<String> labels = new HashSet<String>();
labels.add(string.get(i-1));
e.addUserDatum(JUConstants.LABEL, labels, UserData.CLONE);
pta.addEdge(e);
}
else
if (different(new OrigStatePair(existing,newVertex)))
{
existing.addUserDatum(JUConstants.HIGHLIGHT, "whatever", UserData.SHARED);
StringBuffer errorPath = new StringBuffer();
errorPath.append( string.get(0) );
for(int j = 1;j<i;j++)
errorPath.append(" ").append( string.get(j) );
throw new IllegalArgumentException("incompatible "+(accepted?"accept":"reject")+" labelling: "+errorPath);
}
}
}
return pta;
}
protected static Vertex getVertex (DirectedSparseGraph g,Vertex v, List<String> string){
Vertex current = v;
if (current == null)
return null;
for(int i = 0;i<string.size();i++){
String label = string.get(i);
DirectedSparseEdge edge = getEdgeWithLabel(current.getOutEdges(), label);
if(edge == null)
return null;
current = edge.getDest();
}
return current;
}
public static Vertex getVertex (DirectedSparseGraph g, List<String> string){
return getVertex(g, DeterministicDirectedSparseGraph.findInitial(g), string);
}
public static DirectedSparseEdge getEdgeWithLabel(Set<DirectedSparseEdge> edges, String label){
Iterator<DirectedSparseEdge> edgeIt = edges.iterator();
while(edgeIt.hasNext()){
DirectedSparseEdge e = edgeIt.next();
Set<String> labels = (Set<String>)e.getUserDatum(JUConstants.LABEL);
if(labels.contains(label))
return e;
}
return null;
}
public static Edge findEdge(Vertex from, Vertex to){
Iterator<DirectedSparseEdge> edgesOut = from.getOutEdges().iterator();
while(edgesOut.hasNext()){
DirectedSparseEdge current = edgesOut.next();
if(current.getDest().equals(to))
return current;
}
return null;
}
/** Checks for shallow compatibility between states, in other words if the two are both accept or both reject states
*
* @param pair a pair states to check for compatibility.
* @return whether the two are different.
*/
public static boolean different(OrigStatePair pair){
boolean qAcceptedO = DeterministicDirectedSparseGraph.isAccept(pair.getQ());
boolean rAcceptedO = DeterministicDirectedSparseGraph.isAccept(pair.getR());
return qAcceptedO != rAcceptedO;
}
@Override
public Learner getLearner() {
return null;
}
}