@SuppressWarnings("unchecked")
public static DirectedSparseGraph mergeAndDeterminize(Graph graphToMerge, StatePair pair, Configuration conf)
{
DirectedSparseGraph g = (DirectedSparseGraph)graphToMerge.copy();
DeterministicVertex newBlue = DeterministicDirectedSparseGraph.findVertexNamed(pair.getQ(),g);
DeterministicVertex newRed = DeterministicDirectedSparseGraph.findVertexNamed(pair.getR(),g);
Map<CmpVertex,List<CmpVertex>> mergedVertices = conf.getTransitionMatrixImplType() == STATETREE.STATETREE_ARRAY?
new ArrayMapWithSearch<CmpVertex,List<CmpVertex>>(g.numVertices()):
new HashMapWithSearch<CmpVertex,List<CmpVertex>>(g.numVertices());
// Special configuration is necessary to ensure that computePairCompatibilityScore_internal
// builds mergedVertices using g's vertices rather than StringVertices or clones of g's vertices.
Configuration VertexCloneConf = conf.copy();VertexCloneConf.setLearnerUseStrings(false);VertexCloneConf.setLearnerCloneGraph(false);
LearnerGraph s=new LearnerGraph(g,VertexCloneConf);
if (s.pairscores.computePairCompatibilityScore_internal(new StatePair(s.findVertex(pair.getQ()),s.findVertex(pair.getR())),mergedVertices) < 0)
throw new IllegalArgumentException("elements of the pair are incompatible");
// make a loop
Set<Label> usedInputs = new HashSet<Label>();
for(DirectedSparseEdge e:(Set<DirectedSparseEdge>)newBlue.getInEdges())
{
Vertex source = e.getSource();
Collection<Label> existingLabels = (Collection<Label>)e.getUserDatum(JUConstants.LABEL);
g.removeEdge(e);
// It is possible that there is already an edge between g.getSource Blue and newRed
Iterator<DirectedSparseEdge> sourceOutIt = source.getOutEdges().iterator();
Edge fromSourceToNewRed = null;
while(sourceOutIt.hasNext() && fromSourceToNewRed == null)
{
DirectedSparseEdge out = sourceOutIt.next();if (out.getDest() == newRed) fromSourceToNewRed = out;
}
if (fromSourceToNewRed == null)
{
fromSourceToNewRed = new DirectedSparseEdge(source,newRed);
fromSourceToNewRed.setUserDatum(JUConstants.LABEL, existingLabels, UserData.CLONE);// no need to clone this one since I'll delete the edge in a bit
g.addEdge(fromSourceToNewRed);
}
else
// there is already a transition from source to newRed, hence all we have to do is merge the new labels into it.
((Collection<Label>)fromSourceToNewRed.getUserDatum(JUConstants.LABEL)).addAll( existingLabels );
}
// now the elements of mergedVertices are in terms of the copied graph.
for(Vertex vert:(Set<Vertex>)g.getVertices())
if (mergedVertices.containsKey(vert))
{// there are some vertices to merge with this one.
usedInputs.clear();usedInputs.addAll(s.transitionMatrix.get(vert).keySet());
for(CmpVertex toMerge:mergedVertices.get(vert))
{// for every input, I'll have a unique target state - this is a feature of PTA
// For this reason, every if multiple branches of PTA get merged, there will be no loops or parallel edges.
// As a consequence, it is safe to assume that each input/target state combination will lead to a new state.
Set<Label> inputsFrom_toMerge = s.transitionMatrix.get(toMerge).keySet();
for(Label input:inputsFrom_toMerge)
if (!usedInputs.contains(input))
{
Set<Label> labels = new HashSet<Label>();
labels.add(input);
DeterministicVertex targetVert = (DeterministicVertex)s.transitionMatrix.get(toMerge).get(input);
DirectedSparseEdge newEdge = new DirectedSparseEdge(vert,targetVert);
newEdge.addUserDatum(JUConstants.LABEL, labels, UserData.CLONE);
g.removeEdges(targetVert.getInEdges());g.addEdge(newEdge);
}
usedInputs.addAll(inputsFrom_toMerge);
}
}