{
@Override
public LearnerGraph MergeAndDeterminize(LearnerGraph original, StatePair pair)
{
LearnerGraph outcome = null;
int extraPhantomVertices = 0;
if (useOptimizedMerge)
{
// Use the old and limited version to compute the merge because the general one is too slow on large graphs and we do not need either to merge arbitrary states or to handle "incompatibles".
outcome = MergeStates.mergeAndDeterminize(original, pair);outcome.pathroutines.updateDepthLabelling();
}
else
{
Collection<AMEquivalenceClass<CmpVertex,LearnerGraphCachedData>> mergedVertices = new ArrayList<AMEquivalenceClass<CmpVertex,LearnerGraphCachedData>>();
long score = original.pairscores.computePairCompatibilityScore_general(pair,null,mergedVertices);
outcome = MergeStates.mergeCollectionOfVertices(original,pair.getR(),mergedVertices);
if (score != original.getStateNumber()-outcome.getStateNumber())
{// This is either a bug somewhere in the merger or (most likely) that the phantomVertex has been removed by the generalised learner.
// We are checking which of these two has happened in the code below.
// The computation below is expensive on large graphs but only needs to be done once.
LinkedHashSet<CmpVertex> removedStates = new LinkedHashSet<CmpVertex>();removedStates.addAll(original.transitionMatrix.keySet());
removedStates.removeAll(outcome.transitionMatrix.keySet());removedStates.remove(pair.getQ());removedStates.remove(pair.getR());
Assert.assertEquals(1,removedStates.size());// if it were a phantom vertex, there would only be one of them.
CmpVertex tentativePhantom = removedStates.iterator().next();
Set<Label> alphabetUsedOnPhantom = new TreeSet<Label>();alphabetUsedOnPhantom.addAll(original.pathroutines.computeAlphabet());
for(Entry<Label,CmpVertex> transition:original.transitionMatrix.get(tentativePhantom).entrySet())
{
Assert.assertSame(tentativePhantom,transition.getValue());alphabetUsedOnPhantom.remove(transition.getKey());
}
Assert.assertEquals(0, alphabetUsedOnPhantom.size());
extraPhantomVertices = 1;// now certain it was indeed a phantom vertex added when the PTA was initially built.
}
Assert.assertEquals(score+extraPhantomVertices,original.getStateNumber()-outcome.getStateNumber());
}
ScoreMode origScore = original.config.getLearnerScoreMode();original.config.setLearnerScoreMode(ScoreMode.COMPATIBILITY);
long compatibilityScore = original.pairscores.computePairCompatibilityScore(pair);
original.config.setLearnerScoreMode(origScore);
Assert.assertEquals(compatibilityScore+1+extraPhantomVertices,original.getStateNumber()-outcome.getStateNumber());
return outcome;
}
@Override
public Stack<PairScore> ChooseStatePairs(LearnerGraph graph)
{
Stack<PairScore> outcome = graph.pairscores.chooseStatePairs(new PairScoreComputation.RedNodeSelectionProcedure(){
@Override
public CmpVertex selectRedNode(LearnerGraph coregraph, @SuppressWarnings("unused") Collection<CmpVertex> reds, Collection<CmpVertex> tentativeRedNodes)
{
CmpVertex redVertex = null;
if (listOfPairsToWrite != null)
{
redVertex = tentativeRedNodes.iterator().next();
listOfPairsToWrite.add(new PairOfPaths(coregraph, new PairScore(null, redVertex, 0, 0)));
}
if(listOfPairsToCheckAgainstIterator != null)
{
PairOfPaths pair = listOfPairsToCheckAgainstIterator.next();
Assert.assertNull(pair.getQ());
redVertex = coregraph.getVertex(pair.getR());
}
return redVertex;
}
@SuppressWarnings("unused")
@Override
public CmpVertex resolvePotentialDeadEnd(LearnerGraph coregraph, Collection<CmpVertex> reds, List<PairScore> pairs) {
return null;// do not resolve in any way
}
@Override
public void initComputation(@SuppressWarnings("unused") LearnerGraph gr) {
// dummy
}
@Override
public long overrideScoreComputation(PairScore p) {
return p.getScore();// dummy
}
@Override
public Collection<Entry<Label, CmpVertex>> getSurroundingTransitions(@SuppressWarnings("unused") CmpVertex currentRed)
{
return null;// dummy, ignored if null.
}
});
if (!outcome.isEmpty())
{
if (listOfPairsToWrite != null)
{
//System.out.println("Optimized: "+useOptimizedMerge+", matrix: "+graph.config.getTransitionMatrixImplType()+", pair : "+outcome.peek());
listOfPairsToWrite.add(new PairOfPaths(graph, outcome.peek()));
}
if(listOfPairsToCheckAgainstIterator != null)
{
PairOfPaths pair = listOfPairsToCheckAgainstIterator.next();
while(pair.getQ() == null)
pair = listOfPairsToCheckAgainstIterator.next();// skip red pairs, we are no longer checking with selectRedNode collections of reds where there there is only one choice.
//System.out.println("Choosing "+pair+" from "+outcome);
//System.out.println("chosen "+outcome.peek()+", expected "+new PairScore(graph.getVertex(pair.getQ()),graph.getVertex(pair.getR()),0,0));
pair.rebuildStack(graph, outcome);
}
}
return outcome;
}
@Override
public LearnerGraph init(Collection<List<Label>> plus, Collection<List<Label>> minus)
{
if (initPta != null)
{
LearnerGraph graph = decoratedLearner.init(plus,minus);
LearnerGraph.copyGraphs(initPta, graph);
return initPta;
}
throw new IllegalArgumentException("should not be called");
}
@Override
public LearnerGraph init(PTASequenceEngine engine, int plusSize, int minusSize)
{
LearnerGraph graph = decoratedLearner.init(engine,plusSize,minusSize);
if (initPta != null)
{
LearnerGraph.copyGraphs(initPta, graph);
}