Package statechum.analysis.learning

Source Code of statechum.analysis.learning.TestFSMAlgo

package statechum.analysis.learning;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;

import static statechum.xmachine.model.testset.WMethod.createLabelToStateMap;
import static statechum.xmachine.model.testset.WMethod.getGraphData;

import junit.framework.Assert;
import junit.framework.JUnit4TestAdapter;

import org.junit.AfterClass;
import org.junit.Test;
import org.junit.BeforeClass;

import statechum.Configuration;
import statechum.DeterministicDirectedSparseGraph;
import statechum.JUConstants;
import statechum.DeterministicDirectedSparseGraph.CmpVertex;
import statechum.DeterministicDirectedSparseGraph.DeterministicEdge;
import statechum.xmachine.model.testset.WMethod;
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.io.GraphMLFile;
import edu.uci.ics.jung.utils.UserData;

import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;

import javax.swing.SwingUtilities;

public class TestFSMAlgo {

  static protected StatePair constructPair(String a,String b)
  {
    DirectedSparseVertex aV = new DirectedSparseVertex(), bV = new DirectedSparseVertex();
    aV.addUserDatum(JUConstants.LABEL, a, UserData.SHARED);
    bV.addUserDatum(JUConstants.LABEL, b, UserData.SHARED);
    return new StatePair(aV,bV);
  }

  static protected void checkLess(String a, String b, String c, String d)
  {
    StatePair p = constructPair(a,b), q=constructPair(c,d);
    assertFalse(p.equals(q));
    assertTrue(p.compareTo(q)<0);
    assertTrue(q.compareTo(p)>0);
    assertFalse(p.hashCode() == q.hashCode());
    assertEquals(0,p.compareTo(p));
    assertEquals(0,q.compareTo(q));
  }
 
  @Test
  public void testStatePairEquality()
  {
    StatePair p = constructPair("a","b"), q=constructPair("a","b");
    assertTrue(p.equals(p));
    assertTrue(p.equals(q));
    assertFalse(p.equals(null));
    assertFalse(p.equals("test"));
    assertFalse(p.equals(constructPair("a","c")));
    assertFalse(p.equals(constructPair("b","b")));
  }
 
  @Test
  public void testStatePairComparison()
  {
    checkLess("a","b","c","d");
    checkLess("a","b","a","c");
    checkLess("a","b","c","b");
  }
 
  /** Given a textual representation of an fsm, builds a corresponding Jung graph
   *
   * @param fsm the textual representation of an FSM
   * @param name graph name, to be displayed as the caption of the Jung window.
   * @return Jung graph for it
   * @throws IllegalArgumentException if fsm cannot be parsed.
   */
  public static DirectedSparseGraph buildGraph(String fsm,String name)
  {
    final Map<String,CmpVertex> existingVertices = new HashMap<String,CmpVertex>();
    final Map<StatePair,DeterministicEdge> existingEdges = new HashMap<StatePair,DeterministicEdge>();
   
    final DirectedSparseGraph g = new DirectedSparseGraph();
    g.setUserDatum(JUConstants.TITLE, name,UserData.SHARED);

    new TestFSMParser.fsmParser(fsm).parse(new TestFSMParser.TransitionReceiver()
    {
      public void put(String from, String to, String label, boolean accept) {
        CmpVertex fromVertex = existingVertices.get(from), toVertex = existingVertices.get(to);
       
        if (fromVertex == null)
        {
          fromVertex = new DeterministicDirectedSparseGraph.DeterministicVertex();
          if (existingVertices.isEmpty())
            fromVertex.addUserDatum(JUConstants.PROPERTY, JUConstants.INIT, UserData.SHARED);
          fromVertex.addUserDatum(JUConstants.ACCEPTED, "true", UserData.SHARED);
          fromVertex.addUserDatum(JUConstants.LABEL, from, UserData.SHARED);
          existingVertices.put(from, fromVertex);
          g.addVertex(fromVertex);
        }
        else
          if (!Boolean.valueOf(fromVertex.getUserDatum(JUConstants.ACCEPTED).toString()))
            throw new IllegalArgumentException("conflicting acceptance assignment on vertex "+from);

        if (from.equals(to))
        {
          if (!accept) throw new IllegalArgumentException("conflicting acceptance assignment on vertex "+to);
          toVertex = fromVertex;
        }
        else
          if (toVertex == null)
          {
            toVertex = new DeterministicDirectedSparseGraph.DeterministicVertex();
            toVertex.removeUserDatum(JUConstants.ACCEPTED); // in case we've got a reject loop in the same state
            toVertex.addUserDatum(JUConstants.ACCEPTED, Boolean.toString(accept), UserData.SHARED);
            toVertex.addUserDatum(JUConstants.LABEL, to, UserData.SHARED);
            existingVertices.put(to, toVertex);
            g.addVertex(toVertex);
          }
          else
            if (Boolean.valueOf(toVertex.getUserDatum(JUConstants.ACCEPTED).toString()) != accept)
              throw new IllegalArgumentException("conflicting acceptance assignment on vertex "+to);
       
        StatePair pair = new StatePair(fromVertex,toVertex);
        DeterministicEdge edge = existingEdges.get(pair);
        if (edge == null)
        {
          edge = new DeterministicDirectedSparseGraph.DeterministicEdge(fromVertex,toVertex);
          edge.addUserDatum(JUConstants.LABEL, new HashSet<String>(), UserData.CLONE);
          g.addEdge(edge);existingEdges.put(pair,edge);
        }
       
        Set<String> labels = (Set<String>)edge.getUserDatum(JUConstants.LABEL);
        labels.add(label);
      }

      public void accept(String from, String to, String label) {
        put(from,to,label,true);
      }
      public void reject(String from, String to, String label) {
        put(from,to,label,false);
      }
    });
   
    return g;
  }

  /** This data store represents an FSM and is used by tests. */
  public static class FSMStructure
  {
    public final Transform322 transform322 = new Transform322(this);
   
    /** The transition transition diagram, in which every state is mapped to a map between an input (label) and a target state. */
    public final Map<String,Map<String,String>> trans;
   
    /** All states of the machine should be in the domain of this function;
     * for a given state, this function will return <pre>true</pre> if it is an accept state and <pre>false</pre> for a reject one.
     */
    public final Map<String,Boolean> accept;
   
    /** The initial state. */
    public String init;
   
    public FSMStructure(Map<String,Map<String,String>> transitions,Map<String,Boolean> a,String initState)
    {
      trans = transitions;accept = a;init = initState;
    }
   
    public FSMStructure()
    {
      trans = new TreeMap<String,Map<String,String>>();accept = new TreeMap<String,Boolean>();
    }
   
    public FSMStructure(Graph g, @SuppressWarnings("unused") Configuration ignored)
    {
      FSMStructure data = WMethod.getGraphData(g);
      trans=data.trans;accept=data.accept;init=data.init;
    }
   
    @Override
    public boolean equals(Object o)
    {
      if (this == o)
        return true;
      if (o == null || !(o instanceof FSMStructure))
        return false;
     
      FSMStructure otherStruct= (FSMStructure)o;
      return
        accept.equals(otherStruct.accept) &&
        trans.equals(otherStruct.trans) &&
        init.equals(otherStruct.init);   
    }
   
    public FSMStructure copy()
    {
      FSMStructure result = new FSMStructure();
      for(Entry<String,Map<String,String>> entry:trans.entrySet())
      {
        Map<String,String> transition = new TreeMap<String,String>();transition.putAll(entry.getValue());
        result.trans.put(entry.getKey(),transition);
      }
      result.accept.putAll(accept);result.init = init;
      return result;
    }
   
    /** Loads a graph from the data in a supplied reader.
     *
     * @param from where to load from
     * @param cnf configuration to use (determines types of nodes created, such as whether they are Jung nodes or Strings).
     * @return created graph.
     */
    public static FSMStructure loadGraph(Reader from, Configuration cnf) throws IOException
    {
      FSMStructure graph = null;
      synchronized (computeStateScores.syncObj)
      {// ensure that the calls to Jung's vertex-creation routines do not occur on different threads.
          GraphMLFile graphmlFile = new GraphMLFile();
          graphmlFile.setGraphMLFileHandler(new statechum.analysis.learning.experiments.ExperimentGraphMLHandler());
          graph = new FSMStructure(graphmlFile.load(from),cnf);
        from.close();
      }
      return graph;
    }

    /** Loads a graph from the supplied XML node.
     *
     * @param elem XML element to load from
     * @param config configuration to use
     * @return loaded graph
     */
    public static FSMStructure loadGraph(org.w3c.dom.Element elem, Configuration config)
    {
      return new FSMStructure(Transform322.loadGraph(elem),config);
    }
   
    /** Loads a graph from a supplied file.
    */
    public static FSMStructure loadGraph(String fileName,Configuration config)
    {
      synchronized (computeStateScores.syncObj)
      {// ensure that the calls to Jung's vertex-creation routines do not occur on different threads.
          GraphMLFile graphmlFile = new GraphMLFile();
          graphmlFile.setGraphMLFileHandler(new statechum.analysis.learning.experiments.ExperimentGraphMLHandler());
          String fileToLoad = fileName;
          if (!new java.io.File(fileToLoad).canRead()) fileToLoad+=".xml";
          FSMStructure graph = new FSMStructure(graphmlFile.load(fileToLoad),config);
          return graph;
      }
    }

    public String findVertex(String string) {
      if (trans.containsKey(string))
        return string;
      return null;// unknown vertex ID
    }
   
    /** Traces a path in a graph and returns the entered state; null if a path does not exist.
     *
     * @param path path to trace
     * @return state which would be entered by the machine if it follows the given path.
     */
    public String getVertex(List<String> path)
    {
      String current = init;
      int pos = -1;
      for(String label:path)
      {
        ++pos;
        Map<String,String> exitingTrans = trans.get(current);
        if (exitingTrans == null || (current = exitingTrans.get(label)) == null)
          return null;
      }
      return current;
    }
  }
 
  @Test
  public final void testFSMStructureEquals1()
  {
    FSMStructure a=new FSMStructure(),b=new FSMStructure();
    a.init = "A";b.init = "A";
    Assert.assertTrue(a.equals(a));
    Assert.assertTrue(a.equals(b));

    Assert.assertFalse(a.equals(null));
    Assert.assertFalse(a.equals("hello"));
    b.init = "B";Assert.assertFalse(a.equals(b));
  }
 
  @Test
  public final void testFSMStructureEquals2()
  {
    FSMStructure a=getGraphData(buildGraph("A-a->A-b->B", "testFSMStructureEquals2"));
    FSMStructure b=getGraphData(buildGraph("A-a->A-b->B", "testFSMStructureEquals2"));
    Assert.assertTrue(a.equals(b));
  }
 
  @Test
  public final void testFSMStructureEquals3()
  {
    FSMStructure a=getGraphData(buildGraph("A-a->A-b->B", "testFSMStructureEquals2"));
    FSMStructure b=getGraphData(buildGraph("A-a->A-b->B", "testFSMStructureEquals2"));
   
    b.trans.clear();
    Assert.assertFalse(a.equals(b));
  }
 
  @Test
  public final void testFSMStructureEquals4()
  {
    FSMStructure a=getGraphData(buildGraph("A-a->A-b->B", "testFSMStructureEquals2"));
    FSMStructure b=getGraphData(buildGraph("A-a->A-b->B", "testFSMStructureEquals2"));
   
    b.accept.clear();
    Assert.assertFalse(a.equals(b));
  }
 
 
  @Test
  public void testCreateLabelToStateMap1() // test with empty data
  {
    assertTrue(createLabelToStateMap(new LinkedList<String>(), "junk", null).isEmpty());
    Map<String,String> map = new HashMap<String,String>();
    assertSame(map,createLabelToStateMap(new LinkedList<String>(), "junk", map));assertTrue(map.isEmpty());
  }
 
  @Test
  public void testCreateLabelToStateMap2() // test for no changes
  {
    Map<String,String> trans = new HashMap<String,String>();
    trans.put("a", "A");trans.put("b", "A");trans.put("c", "B");
    Map<String,String> expected = new HashMap<String,String>();expected.putAll(trans);
    assertSame(trans,WMethod.createLabelToStateMap(new LinkedList<String>(), "junk",trans));
    assertTrue(expected.equals(trans));
  }
 
  @Test
  public void testCreateLabelToStateMap3() // test for correct data being added
  {
    Map<String,String> trans = new HashMap<String,String>();
    trans.put("a", "A");trans.put("b", "A");trans.put("c", "B");
    Map<String,String> expected = new HashMap<String,String>();expected.putAll(trans);expected.put("e", "A");expected.put("g", "A");
    assertSame(trans,createLabelToStateMap(Arrays.asList(new String[] {"g","e"}), "A",trans));
    assertTrue(expected.equals(trans));
  }
 
  @Test
  public void testCreateLabelToStateMap4() // test for correct data being added
  {
    Map<String,String> trans = new HashMap<String,String>();
    trans.put("a", "A");trans.put("b", "A");trans.put("c", "B");
    Map<String,String> expected = new HashMap<String,String>();expected.putAll(trans);expected.put("e", "D");expected.put("f", "D");
    assertSame(trans,createLabelToStateMap(Arrays.asList(new String[] {"f","e"}), "D",trans));
    assertTrue(expected.equals(trans));
  }
 
  @Test
  public void testCreateLabelToStateMap5() // test for correct data being added
  {
    Map<String,String> trans = new HashMap<String,String>();
    trans.put("a", "A");trans.put("b", "A");trans.put("c", "B");
    Map<String,String> expected = new HashMap<String,String>();expected.putAll(trans);expected.put("e", "B");expected.put("g", "B");
    assertSame(trans,createLabelToStateMap(Arrays.asList(new String[] {"g","e"}), "B",trans));
    assertTrue(expected.equals(trans));
  }
 
  @Test
  public void testCreateLabelToStateMap6() // test for correct data being added when an empty collection is passed
  {
    Map<String,String> trans = new HashMap<String,String>();
    Map<String,String> expected = new HashMap<String,String>();expected.put("e","A");expected.put("b","A");
    assertSame(trans,createLabelToStateMap(Arrays.asList(new String[] {"b","e"}), "A",trans));
    assertTrue(expected.equals(trans));
  }

  @Test
  public void testCreateLabelToStateMap7() // test for correct data being added when null is passed
  {
    Map<String,String> expected = new HashMap<String,String>();expected.put("e","A");expected.put("b","A");
    assertTrue(expected.equals(createLabelToStateMap(Arrays.asList(new String[] {"b","e"}), "A",null)));
  }

  @Test
  public void testCreateLabelToStateMap8() // test for correct detection of nondeterminism
  {
    Map<String,String> trans = new HashMap<String,String>();trans.put("a", "A");trans.put("b", "A");trans.put("c", "B");
    boolean exceptionThrown = false;
    try
    {
      createLabelToStateMap(Arrays.asList(new String[] {"b","e"}), "A",trans);
    }
    catch(IllegalArgumentException e)
    {
      assertTrue("incorrect exception thrown",e.getMessage().contains("nondeterminism"));
      exceptionThrown = true;
    }
   
    assertTrue("exception not thrown",exceptionThrown);
  }

  @Test
  public void testCreateLabelToStateMap9() // test for correct detection of nondeterminism
  {
    boolean exceptionThrown = false;
    try
    {
      createLabelToStateMap(Arrays.asList(new String[] {"b","b"}), "A",null);
    }
    catch(IllegalArgumentException e)
    {
      assertTrue("incorrect exception thrown",e.getMessage().contains("nondeterminism"));
      exceptionThrown = true;
    }
   
    assertTrue("exception not thrown",exceptionThrown);
  }

  /** Displays the graph passed as an argument in the Jung window.
   * @param g the graph to display
   */
  public void updateFrame(DirectedSparseGraph g)
  {
    if (visFrame == null)
      visFrame = new Visualiser();
    visFrame.update(null, g);
  }
 
  @Test
  public void testGraphConstruction1()
  {
    FSMStructure expected = new FSMStructure();
    DirectedSparseGraph g = buildGraph("A--a-->B-b->C-c->A","testConstruction1");
    FSMStructure graph = getGraphData(g);
    expected.trans.put("A", createLabelToStateMap(Arrays.asList(new String[] {"a"}),"B",null));
    expected.trans.put("B", createLabelToStateMap(Arrays.asList(new String[] {"b"}),"C",null));
    expected.trans.put("C", createLabelToStateMap(Arrays.asList(new String[] {"c"}),"A",null));
    expected.accept.put("A", true);
    expected.accept.put("B", true);
    expected.accept.put("C", true);
   
    assertEquals("A", graph.init);
    assertEquals("incorrect vertice set",true,expected.accept.equals(graph.accept));
    assertEquals("incorrect transition set",true,graph.trans.equals(expected.trans));
  }

  @Test
  public void testGraphConstruction2()
  {
    FSMStructure expected = new FSMStructure();
    DirectedSparseGraph g = buildGraph("A--a-->B-b->C-c->A-b->B-a-#D","testConstruction2");
    g.setUserDatum(JUConstants.TITLE, "testConstruction2",UserData.SHARED);
    FSMStructure graph = getGraphData(g);
    expected.trans.put("A", createLabelToStateMap(Arrays.asList(new String[] {"a","b"}),"B",null));
    expected.trans.put("B", createLabelToStateMap(Arrays.asList(new String[] {"b"}),"C",createLabelToStateMap(Arrays.asList(new String[] {"a"}),"D",null)));
    expected.trans.put("C", createLabelToStateMap(Arrays.asList(new String[] {"c"}),"A",null));
    expected.trans.put("D", createLabelToStateMap(Collections.EMPTY_LIST,null,null));
    expected.accept.put("A", true);
    expected.accept.put("B", true);
    expected.accept.put("C", true);
    expected.accept.put("D", false);
   
    assertEquals("A", graph.init);
    assertEquals("incorrect vertice set",true,expected.accept.equals(graph.accept));
    assertEquals("incorrect transition set",true,expected.trans.equals(graph.trans));
  }

  @Test
  public void testGraphConstruction3()
  {
    FSMStructure expected = new FSMStructure();
    DirectedSparseGraph g = buildGraph("A--a-->B<-b--C-c->A-b->A-c->A\nB-d->B-p->C\nB-q->C\nB-r->C\n","testConstruction3");
    FSMStructure graph = getGraphData(g);
    expected.trans.put("A", createLabelToStateMap(Arrays.asList(new String[] {"b","c"}),"A",createLabelToStateMap(Arrays.asList(new String[] {"a"}),"B",null)));
    expected.trans.put("B", createLabelToStateMap(Arrays.asList(new String[] {"d"}),"B",createLabelToStateMap(Arrays.asList(new String[] {"r","p","q"}),"C",null)));
    expected.trans.put("C", createLabelToStateMap(Arrays.asList(new String[] {"b"}),"B",createLabelToStateMap(Arrays.asList(new String[] {"c"}),"A",null)));
    expected.accept.put("A", true);
    expected.accept.put("B", true);
    expected.accept.put("C", true);
   
    assertEquals("A", graph.init);
    assertEquals("incorrect vertice set",true,expected.accept.equals(graph.accept));
    assertEquals("incorrect transition set",true,expected.trans.equals(graph.trans));
  }

  @Test
  public void testGraphConstruction4()
  {
    FSMStructure expected = new FSMStructure();
    DirectedSparseGraph g = buildGraph("A--a-->B<-b--D-c->A-b->A-c->A\nB-d->B-p-#C\nB-q-#C\nB-r-#C\n","testConstruction4");
    FSMStructure graph = getGraphData(g);
    expected.trans.put("A", createLabelToStateMap(Arrays.asList(new String[] {"b","c"}),"A",createLabelToStateMap(Arrays.asList(new String[] {"a"}),"B",null)));
    expected.trans.put("B", createLabelToStateMap(Arrays.asList(new String[] {"d"}),"B",createLabelToStateMap(Arrays.asList(new String[] {"r","p","q"}),"C",null)));
    expected.trans.put("D", createLabelToStateMap(Arrays.asList(new String[] {"b"}),"B", createLabelToStateMap(Arrays.asList(new String[] {"c"}),"A",null)));
    expected.trans.put("C", createLabelToStateMap(Collections.EMPTY_LIST,null,null));
    expected.accept.put("A", true);
    expected.accept.put("B", true);
    expected.accept.put("C", false);
    expected.accept.put("D", true);
   
    assertEquals("A", graph.init);
    assertEquals("incorrect vertice set",true,expected.accept.equals(graph.accept));
    assertEquals("incorrect transition set",true,expected.trans.equals(graph.trans));
  }

  @Test
  public void testGraphConstruction5()
  {
    FSMStructure expected = new FSMStructure();
    DirectedSparseGraph g = buildGraph("A--a-->B-b-#C\nA-b->A-c->A\nB-d->B-p-#C\nB-q-#C\nB-r-#C\n","testConstruction5");
    FSMStructure graph = getGraphData(g);
    expected.trans.put("A", createLabelToStateMap(Arrays.asList(new String[] {"b","c"}),"A",createLabelToStateMap(Arrays.asList(new String[] {"a"}),"B",null)));
    expected.trans.put("B", createLabelToStateMap(Arrays.asList(new String[] {"d"}),"B",createLabelToStateMap(Arrays.asList(new String[] {"b","r","p","q"}),"C",null)));
    expected.trans.put("C", createLabelToStateMap(Collections.EMPTY_LIST,null,null));
    expected.accept.put("A", true);
    expected.accept.put("B", true);
    expected.accept.put("C", false);
   
    assertEquals("A", graph.init);
    assertEquals("incorrect vertice set",true,expected.accept.equals(graph.accept));
    assertEquals("incorrect transition set",true,expected.trans.equals(graph.trans));
  }
 
  @Test
  public void testGraphConstruction6() // checks loop support
  {
    FSMStructure expected = new FSMStructure();
    DirectedSparseGraph g = buildGraph("P-c->P<-b-Q_State<-a-P-b->P\nQ_State-a->Q_State","testConstruction6");
    FSMStructure graph = getGraphData(g);
    expected.trans.put("P", createLabelToStateMap(Arrays.asList(new String[] {"b","c"}),"P",createLabelToStateMap(Arrays.asList(new String[] {"a"}),"Q_State",null)));
    expected.trans.put("Q_State", createLabelToStateMap(Arrays.asList(new String[] {"a"}),"Q_State",createLabelToStateMap(Arrays.asList(new String[] {"b"}),"P",null)));
    expected.accept.put("P", true);
    expected.accept.put("Q_State", true);
   
    assertEquals("P", graph.init);
    assertEquals("incorrect vertice set",true,expected.accept.equals(graph.accept));
    assertEquals("incorrect transition set",true,expected.trans.equals(graph.trans));
  }

  @Test
  public void testGraphConstructionFail1a()
  {
    boolean exceptionThrown = false;
    try
    {
      buildGraph("A--a-->B<-b-CONFL\nA-b->A-c->A\nB-d->B-p-#CONFL","testGraphConstructionFail1a");
    }
    catch(IllegalArgumentException e)
    {
      assertTrue("correct exception not thrown",e.getMessage().contains("conflicting") && e.getMessage().contains("CONFL"));
      exceptionThrown = true;
    }
   
    assertTrue("exception not thrown",exceptionThrown);
  }
 
  @Test
  public void testGraphConstructionFail1b()
  {
    boolean exceptionThrown = false;
    try
    {
      buildGraph("A--a-->CONFL-b-#CONFL","testGraphConstructionFail1b");
    }
    catch(IllegalArgumentException e)
    {
      assertTrue("correct exception not thrown",e.getMessage().contains("conflicting") && e.getMessage().contains("CONFL"));
      exceptionThrown = true;
    }
   
    assertTrue("exception not thrown",exceptionThrown);
  }
 
  /** Checks if adding a vertex to a graph causes an exception to be thrown. */
  public static void checkWithVertex(Vertex v,String expectedExceptionString, String testName)
  {
    final DirectedSparseGraph g = buildGraph("A--a-->B<-b-CONFL\nA-b->A-c->A\nB-d->B-p->CONFL",testName);
    getGraphData(g);// without the vertex being added, everything should be fine.
    g.addVertex(v);// add the vertex
   
    boolean exceptionThrown = false;
    try
    {
      getGraphData(g);// now getGraphData should choke.     
    }
    catch(IllegalArgumentException e)
    {
      assertTrue("correct exception not thrown",e.getMessage().contains(expectedExceptionString) );
      exceptionThrown = true;
    }
   
    assertTrue("exception not thrown",exceptionThrown);
  }
 
  @Test
  public void testGraphConstructionFail2()
  {
    DirectedSparseVertex v = new DirectedSparseVertex();
    v.addUserDatum(JUConstants.ACCEPTED, "true", UserData.SHARED);v.addUserDatum(JUConstants.LABEL, "B", UserData.SHARED);
    checkWithVertex(v, "multiple", "testGraphConstructionFail2");
  }
 
  @Test
  public void testGraphConstructionFail3()
  {
    DirectedSparseVertex v = new DirectedSparseVertex();
    v.addUserDatum(JUConstants.ACCEPTED, "true", UserData.SHARED);v.addUserDatum(JUConstants.LABEL, "CONFL", UserData.SHARED);
    checkWithVertex(v, "multiple", "testGraphConstructionFail3");
  }
 
  @Test
  public void testGraphConstructionFail4()
  {
    DirectedSparseVertex v = new DirectedSparseVertex();
    v.addUserDatum(JUConstants.ACCEPTED, "true", UserData.SHARED);v.addUserDatum(JUConstants.LABEL, "Q", UserData.SHARED);v.addUserDatum(JUConstants.PROPERTY, JUConstants.INIT, UserData.SHARED);
    checkWithVertex(v, "duplicate", "testGraphConstructionFail4");
  }
 
  @Test
  public void testGraphConstructionFail5()
  {
    DirectedSparseVertex v = new DirectedSparseVertex();
    v.addUserDatum(JUConstants.ACCEPTED, "true", UserData.SHARED);v.addUserDatum(JUConstants.LABEL, "Q", UserData.SHARED);v.addUserDatum(JUConstants.PROPERTY, "aa", UserData.SHARED);
    checkWithVertex(v, "property", "testGraphConstructionFail5");
  }
 
  @Test
  public void testGraphConstructionFail6() // missing initial state in an empty graph
  {
    boolean exceptionThrown = false;
    try
    {
      getGraphData(new DirectedSparseGraph());// now getGraphData should choke.     
    }
    catch(IllegalArgumentException e)
    {
      assertTrue("correct exception not thrown",e.getMessage().contains("missing initial") );
      exceptionThrown = true;
    }
   
    assertTrue("exception not thrown",exceptionThrown);
  }

  @Test
  public final void testGraphConstructionFail7() // unlabelled states
  {
    DirectedSparseGraph g = new DirectedSparseGraph();
    DirectedSparseVertex init = new DirectedSparseVertex();
    init.addUserDatum(JUConstants.PROPERTY, JUConstants.INIT, UserData.SHARED);
    init.addUserDatum(JUConstants.ACCEPTED, "true", UserData.SHARED);g.addVertex(init);
    boolean exceptionThrown = false;
    try
    {
      getGraphData(g);// now getGraphData should choke.     
    }
    catch(IllegalArgumentException e)
    {
      assertTrue("correct exception not thrown",e.getMessage().contains("unlabelled") );
      exceptionThrown = true;
    }
   
    assertTrue("exception not thrown",exceptionThrown);
  }
 
  /** Checks if the passed graph is isomorphic to the provided fsm
   *
   * @param g graph to check
   * @param fsm the string representation of the machine which the graph should be isomorphic to
   */
  public void checkEq(DirectedSparseGraph g, String fsm)
  {
    DirectedSparseGraph expectedGraph = buildGraph(fsm,"expected graph");
    final FSMStructure graph = getGraphData(g);
    final FSMStructure expected = getGraphData(expectedGraph);
    assertEquals("incorrect initial state",expected.init, graph.init);
    assertEquals("incorrect vertice set",true,expected.accept.equals(graph.accept));
    assertEquals("incorrect transition set",true,expected.trans.equals(graph.trans));   
  }

  @Test
  public void testCheckEq()
  {
    DirectedSparseGraph g=buildGraph("P-a->Q_State-b->P-c->P","testCheckEq");
    checkEq(g,"P-c->P<-b-Q_State<-a-P");
  }
 
  /** This one is used to indicate that a two machines are not accepting the same language -
   * I need to check that it is the incompatibility exception thrown by the <i>checkM</i>
   * method and not any other <i>IllegalArgumentException</i>.
   */
  public static class DifferentFSMException extends IllegalArgumentException
  {
    /**
     *  Serialization ID.
     */
    private static final long serialVersionUID = 6126662147586264877L;

    public DifferentFSMException(String arg)
    {
      super(arg);
    }
  }
 
 
  public static void checkM(DirectedSparseGraph g,String fsm)
  {
    final FSMStructure graph = getGraphData(g);
    final DirectedSparseGraph expectedGraph = buildGraph(fsm,"expected graph");
    final FSMStructure expected = getGraphData(expectedGraph);
    checkM(graph,expected,graph.init,expected.init);
  }
 
  public static class StringPair implements Comparable<StringPair>
  {
    public final String a,b;
   
    public StringPair(String aStr,String bStr)
    {
      a=aStr;b=bStr;
    }

    @Override
    public boolean equals(Object arg0) {
      if (arg0 == null || !(arg0 instanceof StringPair))
        return false;
      StringPair arg = (StringPair)arg0;
      return a.equals(arg.a) && b.equals(arg.b);
    }

    @Override
    public int hashCode() {
      return a.hashCode() ^ b.hashCode();
    }

    @Override
    public String toString() {
      return "( "+a+","+b+" )";
    }

    public int compareTo(StringPair pB) {
      int aStr = a.compareTo(pB.a);
      int bStr = b.compareTo(pB.b);
     
      if(aStr != 0)
        return aStr;
      return bStr;
    }
   
   
  }
 
  static protected void checkStatePairLess(String a, String b, String c, String d)
  {
    StringPair p = new StringPair(a,b), q=new StringPair(c,d);
    assertFalse(p.equals(q));
    assertTrue(p.compareTo(q)<0);
    assertTrue(q.compareTo(p)>0);
    assertFalse(p.hashCode() == q.hashCode());
    assertEquals(0,p.compareTo(p));
    assertEquals(0,q.compareTo(q));
  }
 
  @Test
  public void testStringPairEquality()
  {
    StringPair p = new StringPair("a","b"), q=new StringPair("a","b");
    assertTrue(p.equals(p));
    assertTrue(p.equals(q));
    assertFalse(p.equals(null));
    assertFalse(p.equals("test"));
    assertFalse(p.equals(new StringPair("a","c")));
    assertFalse(p.equals(new StringPair("b","b")));
   
    assertTrue(p.hashCode() != 0);
    assertTrue(q.hashCode() != 0);
  }
 
  @Test
  public void testStringPairComparison()
  {
    checkStatePairLess("a","b","c","d");
    checkStatePairLess("a","b","a","c");
    checkStatePairLess("a","b","c","b");
  }
 
  /** Checks the equivalence between the two states, stateG of graphA and stateB of graphB.
   * Unreachable states are ignored.
   */
  public static void checkM(FSMStructure graph, FSMStructure expected)
  {
    checkM(graph,expected,graph.init,expected.init);
  }
 
  /** Checks the equivalence between the two states, stateG of graphA and stateB of graphB.
   * Unreachable states are ignored.
   */
  public static void checkM(FSMStructure graph, FSMStructure expected, String stateGraph, String stateExpected)
  {
    Queue<StringPair> currentExplorationBoundary = new LinkedList<StringPair>();// FIFO queue

    Set<StringPair> statesAddedToBoundary = new HashSet<StringPair>();
    currentExplorationBoundary.add(new StringPair(stateGraph,stateExpected));statesAddedToBoundary.add(new StringPair(stateGraph,stateExpected));
   
    while(!currentExplorationBoundary.isEmpty())
    {
      StringPair statePair = currentExplorationBoundary.remove();
      assert graph.accept.containsKey(statePair.a) : "state "+statePair.a+" is not known to the first graph";
      assert expected.accept.containsKey(statePair.b) : "state "+statePair.b+" is not known to the second graph";
      if (!graph.accept.get(statePair.a).equals(expected.accept.get(statePair.b)))
        throw new DifferentFSMException("states "+statePair.a+" and " + statePair.b+" have a different acceptance labelling between the machines");
           
      Map<String,String> targets = graph.trans.get(statePair.a), expectedTargets = expected.trans.get(statePair.b);
      if (expectedTargets.size() != targets.size())// each of them is equal to the keyset size from determinism
        throw new DifferentFSMException("different number of transitions from state "+statePair);
       
      for(Entry<String,String> labelstate:targets.entrySet())
      {
        String label = labelstate.getKey();
        if (!expectedTargets.containsKey(label))
          throw new DifferentFSMException("no transition with expected label "+label+" from a state corresponding to "+statePair.b);
        String tState = labelstate.getValue();// the original one
        String expectedState = expectedTargets.get(label);
       
        StringPair nextPair = new StringPair(tState,expectedState);
        if (!statesAddedToBoundary.contains(nextPair))
        {
          currentExplorationBoundary.offer(nextPair);
          statesAddedToBoundary.add(nextPair);
        }
      }
    }
   
  }
 
  @Test
  public void testCheckM1()
  {
    checkM(buildGraph("A-a->B-b->C", "testCheck1"), "B-a->C-b->D");
  }
 
  @Test
  public void testCheckM2()
  {
    checkM(buildGraph("A-a->B-b->C-d-#F#-b-A", "testCheck2"), "B-a->C-b->D\nB-b-#REJ\nD-d-#REJ");
  }

  @Test
  public void testCheckM3()
  {
    String another  = "A-a->B-b->C\nC-b-#REJ\nA-d-#REJ";
    String expected = "A-a->B-b->C-b-#F#-d-A";
    checkM(buildGraph(another.replace('A', 'Q').replace('B', 'G').replace('C', 'A'), "testCheck3"), expected);
  }

  @Test
  public void testCheckM4() // multiple reject states
  {
    String another  = "A-a->B-b->C\nC-b-#REJ\nA-d-#REJ\nA-b-#REJ2\nB-a-#REJ2\nB-c-#REJ3";
    String expected = "A-a->B-b->C-b-#F#-d-A-b-#R\nB-a-#R\nU#-c-B";
    checkM(buildGraph(another.replace('A', 'Q').replace('B', 'G').replace('C', 'A'), "testCheck4"), expected);
  }

  @Test
  public void testCheckM5()
  {
    checkM(buildGraph("A-a->B-b->B-a->C", "testCheck5"), "S-a->U<-b-U\nQ<-a-U");
  }

  @Test
  public void testCheckM6()
  {
    final FSMStructure graph = getGraphData(buildGraph("A-a->B-b->B-a->C", "testCheck6"));
    final FSMStructure expected = getGraphData(buildGraph("U<-b-U\nQ<-a-U<-a-S","expected graph"));
    checkM(graph,expected,"A","S");
    checkM(graph,expected,"B","U");
    checkM(graph,expected,"C","Q");
  }

  @Test
  public final void testCheckM_multipleEq1() // equivalent states
  {
    final FSMStructure graph = getGraphData(buildGraph("S-a->A\nS-b->B\nS-c->C\nS-d->D\nS-e->E\nS-f->F\nS-h->H-d->H\nA-a->A1-b->A2-a->K1-a->K1\nB-a->B1-b->B2-b->K1\nC-a->C1-b->C2-a->K2-b->K2\nD-a->D1-b->D2-b->K2\nE-a->E1-b->E2-a->K3-c->K3\nF-a->F1-b->F2-b->K3","testCheckM_multipleEq1"));
    assertTrue(checkMBoolean(graph,graph,"D","C2"));
    assertTrue(checkMBoolean(graph,graph,"C2","D"));
   
    assertTrue(checkMBoolean(graph,graph,"D1","D2"));
    assertTrue(checkMBoolean(graph,graph,"D2","D1"));

    assertTrue(checkMBoolean(graph,graph,"D2","K2"));
    assertTrue(checkMBoolean(graph,graph,"K2","D2"));

    assertFalse(checkMBoolean(graph,graph,"D2","A1"));
    assertFalse(checkMBoolean(graph,graph,"A1","D2"));

    assertFalse(checkMBoolean(graph,graph,"D2","F1"));
    assertFalse(checkMBoolean(graph,graph,"F1","D2"));
  }

  @Test
  public final void testCheckM_multipleEq2() // equivalent states
  {
    final DirectedSparseGraph g = buildGraph("S-a->A-a->D-a->D-b->A-b->B-a->D\nB-b->C-a->D\nC-b->D\nS-b->N-a->N-b->N","testCheckM_multipleEq2");
    final FSMStructure graph = getGraphData(g);
    List<String> states = Arrays.asList(new String[]{"S","A","B","C","D","N"});
    for(String stA:states)
      for(String stB:states)
        assertTrue("states "+stA+"and "+stB+" should be equivalent",checkMBoolean(graph,graph,stA,stB));
  }
 
  @Test
  public final void testCheckM_multipleEq3() // equivalent states
  {
    final DirectedSparseGraph g = buildGraph("S-a->A-a->D-a->D-b->A-b->B-a->D\nB-b->C-a->D\nC-b->D\nS-b->N-a->M-a->N\nN-b->M-b->N","testCheckM_multipleEq3");
    final FSMStructure graph = getGraphData(g);
    List<String> states = Arrays.asList(new String[]{"S","A","B","C","D","N","M"});
    for(String stA:states)
      for(String stB:states)
        assertTrue("states "+stA+"and "+stB+" should be equivalent",checkMBoolean(graph,graph,stA,stB));
  }
 
  @Test
  public final void testCheckM_multipleEq4() // non-equivalent states
  {
    final DirectedSparseGraph g = buildGraph("A-a->B-a->C-a->A-b->C-b->B","testCheckM_multipleEq4");
    final FSMStructure graph = getGraphData(g);
    List<String> states = Arrays.asList(new String[]{"A","B","C"});
    for(String stA:states)
      for(String stB:states)
        if (stA.equals(stB))
          assertTrue("states "+stA+" and "+stB+" should be equivalent",checkMBoolean(graph,graph,stA,stB));
        else
          assertFalse("states "+stA+" and "+stB+" should not be equivalent",checkMBoolean(graph,graph,stA,stB));
  }
 
  /** Same as checkM, but returns a boolean false instead of an exception. */
  public static boolean checkMBoolean(FSMStructure graph, FSMStructure expected, String stateGraph, String stateExpected)
  {
    try
    {
      checkM(graph,expected,stateGraph,stateExpected);
    }
    catch(DifferentFSMException ex)
    {
      return false;
    }
    return true;
  }
 
  @Test
  public void testCheckM6_f1()
  {
    final FSMStructure graph = getGraphData(buildGraph("A-a->B-b->B-a->C", "testCheck6"));
    final FSMStructure expected = getGraphData(buildGraph("U<-b-U\nQ<-a-U<-a-S","expected graph"));
    Assert.assertTrue(checkMBoolean(graph,graph,"A","A"));
    Assert.assertTrue(checkMBoolean(graph,graph,"B","B"));
    Assert.assertTrue(checkMBoolean(graph,graph,"C","C"));
    Assert.assertTrue(checkMBoolean(expected,expected,"Q","Q"));
    Assert.assertTrue(checkMBoolean(expected,expected,"S","S"));
   
    Assert.assertFalse(checkMBoolean(graph,expected,"A","Q"));
    Assert.assertFalse(checkMBoolean(graph,expected,"A","U"));
    Assert.assertFalse(checkMBoolean(graph,expected,"B","Q"));
    Assert.assertFalse(checkMBoolean(graph,expected,"B","S"));
    Assert.assertFalse(checkMBoolean(graph,expected,"C","U"));
    Assert.assertFalse(checkMBoolean(graph,expected,"C","S"));
  }
 

  @Test(expected = DifferentFSMException.class)
  public void testCheckMD1()
  {
    checkM(buildGraph("A-a->B-b->C", "testCheckMD1"), "B-a->C-b->B");   
  }

  @Test(expected = DifferentFSMException.class)
  public void testCheckMD2() // different reject states
  {
    checkM(buildGraph("A-a->B-b->C", "testCheckMD2"), "B-a->C-b-#D");
  }

  @Test(expected = DifferentFSMException.class)
  public void testCheckMD3() // missing transition
  {
    checkM(buildGraph("A-a->B-b->C\nA-b->B", "testCheckMD3"), "B-a->C-b->D");
  }

  @Test(expected = DifferentFSMException.class)
  public void testCheckMD4() // extra transition
  {
    checkM(buildGraph("A-a->B-b->C", "testCheckMD4"), "B-a->C-b->D\nB-b->C");
  }

  @Test(expected = DifferentFSMException.class)
  public void testCheckMD5() // missing transition
  {
    checkM(buildGraph("A-a->B-b->C\nB-c->B", "testCheckMD5"), "B-a->C-b->D");
  }

  @Test(expected = DifferentFSMException.class)
  public void testCheckMD6() // extra transition
  {
    checkM(buildGraph("A-a->B-b->C", "testCheckMD6"), "B-a->C-b->D\nC-c->C");
  }

  @Test(expected = DifferentFSMException.class)
  public void testCheckMD7() // swapped transitions
  {
    String another  = "A-a->B-b->C\nC-b-#REJ\nA-d-#REJ";
    String expected = "A-a->B-b->C-d-#F#-b-A";
    checkM(buildGraph(another.replace('A', 'Q').replace('B', 'G').replace('C', 'A'), "testCheckMD7"), expected);
  }
 
  /** Given an FSM and a sequence of labels to follow, this one checks whether the sequence is correctly
   * accepted or not, and if not whether it is rejected at the correct element.
   *
   * @param fsmString a description of an FSM
   * @param path a sequence of labels to follow
   * @param ExpectedResult the result to check
   * @param The name of the vertex which is expected to be returned by getVertex
   */
  public static void checkPath(String fsmString, String []path, int ExpectedResult, String enteredName)
  {
    assert (enteredName == null)? (ExpectedResult >= 0):true;
    final DirectedSparseGraph g = buildGraph(fsmString, "sample FSM");
    final FSMStructure graph = getGraphData(g);
    assertEquals(ExpectedResult, WMethod.tracePath(graph, Arrays.asList(path)));
    Vertex expected = (enteredName == null)? null:new computeStateScores(g,"SINK").findVertex(enteredName);
    assertSame(expected, RPNIBlueFringeLearner.getVertex(g, Arrays.asList(path)));
  }
 
  /** Given an FSM and a sequence of labels to follow, this one checks whether the sequence is correctly
   * accepted from a supplied state or not, and if not whether it is rejected at the correct element.
   *
   * @param fsmString a description of an FSM
   * @param path a sequence of labels to follow
   * @param ExpectedResult the result to check
   * @param The name of the vertex which is expected to be returned by getVertex
   */
  public static void checkPathFrom(String fsmString, String startingState, String []path, int ExpectedResult, String enteredName)
  {
    assert (enteredName == null) == (ExpectedResult >= 0);
    final DirectedSparseGraph g = buildGraph(fsmString, "sample FSM");
    final FSMStructure graph = getGraphData(g);
    assertEquals(ExpectedResult, WMethod.tracePath(graph, Arrays.asList(path),startingState));
    Vertex starting = new computeStateScores(g,"SINK").findVertex(startingState);
    Vertex expected = (enteredName == null)? null:new computeStateScores(g,"SINK").findVertex(enteredName);
    assertSame(expected, RPNIBlueFringeLearner.getVertex(g, starting,Arrays.asList(path)));
  }
 
  @Test
  public void testTracePath()
  {
    checkPath("A-a->B-b->C-c->D", new String[]{}, RPNIBlueFringeLearner.USER_ACCEPTED,"A");
  }
 
  @Test
  public void testTracePath1a()
  {
    checkPath("A-a->B-b->C-c->D", new String[]{"a"}, RPNIBlueFringeLearner.USER_ACCEPTED,"B");
  }
 
  @Test
  public void testTracePath1b()
  {
    checkPathFrom("A-a->B-b->C-c->D","B",new String[]{"b"},RPNIBlueFringeLearner.USER_ACCEPTED,"C");
  }
 
  @Test
  public void testTracePath2a()
  {
    checkPath("A-a->B-b->C-c->D", new String[]{"a","b","c"}, RPNIBlueFringeLearner.USER_ACCEPTED,"D");
  }
 
  @Test
  public void testTracePath2b()
  {
    checkPath("A-a->B-b->C-c->D", new String[]{"a","b","c","d"}, 3,null);
  }
 
  @Test
  public void testTracePath3()
  {
    checkPath("A-a->B-b->C-c->D", new String[]{"b"}, 0,null);
  }
 
  @Test
  public void testTracePath4()
  {
    checkPath("A-a->B-b->C-c->D", new String[]{"a","b","d"}, 2,null);
  }
 
  @Test
  public void testTracePath5a()
  {
    checkPath("A-a->B-b->C-c->D", new String[]{"b","a","c"}, 0,null);
  }
 
  @Test
  public void testTracePath5b()
  {
    checkPathFrom("A-a->B-b->C-c->D", "B",new String[]{"c"},0,null);
  }
 
  @Test
  public void testTracePath5c()
  {
    checkPathFrom("A-a->B-b->C-c->D", "Q",new String[]{"c"},0,null);
  }
 
  @Test
  public void testTracePath6()
  {
    checkPath("A-a->B-b->C-c->D", new String[]{"a","a","c","b"}, 1,null);
  }
 
  @Test
  public void testTracePath7()
  {
    checkPath("A-a->B-b->C-c-#D", new String[]{"a","b","c"}, 2,"D");
  }
 
  @Test
  public void testTracePath8()
  {
    checkPath("A-a->B-b->C-c-#D", new String[]{"a","b","c","d"}, 3,null);
  }
 
  @Test
  public void testTracePath9()
  {
    checkPath("A-a->B-b->C-c-#D", new String[]{"a","b","c","d","e"}, 3,null);
  }
 
  /** Computes an alphabet of a given graph and adds transitions to a
   * reject state from all states A and inputs a from which there is no B such that A-a->B
   * (A-a-#REJECT) gets added. Note: such transitions are even added to reject vertices.
   *
   * @param g the graph to add transitions to
   * @param reject the name of the reject state, to be added to the graph.
   * @return true if any transitions have been added
   */  
  public static boolean completeGraph(DirectedSparseGraph g, String reject)
  {
    DirectedSparseVertex rejectVertex = new DirectedSparseVertex();
    boolean transitionsToBeAdded = false;// whether and new transitions have to be added.
    rejectVertex.addUserDatum(JUConstants.ACCEPTED, "false", UserData.SHARED);
    rejectVertex.addUserDatum(JUConstants.LABEL, reject, UserData.SHARED);
   
    // first pass - computing an alphabet
    Set<String> alphabet = WMethod.computeAlphabet(g);
   
    // second pass - checking if any transitions need to be added.
    Set<String> outLabels = new HashSet<String>();
    Iterator<Vertex> vertexIt = (Iterator<Vertex>)g.getVertices().iterator();
    while(vertexIt.hasNext() && !transitionsToBeAdded)
    {
      Vertex v = vertexIt.next();
      outLabels.clear();
      Iterator<DirectedSparseEdge>outEdgeIt = v.getOutEdges().iterator();
      while(outEdgeIt.hasNext()){
        DirectedSparseEdge outEdge = outEdgeIt.next();
        outLabels.addAll( (Set<String>)outEdge.getUserDatum(JUConstants.LABEL) );
      }
      transitionsToBeAdded = !alphabet.equals(outLabels);
    }
   
    if (transitionsToBeAdded)
    {
      // third pass - adding transitions
      g.addVertex(rejectVertex);
      vertexIt = (Iterator<Vertex>)g.getVertices().iterator();
      while(vertexIt.hasNext())
      {
        Vertex v = vertexIt.next();
        if (v != rejectVertex)
        {// no transitions should start from the reject vertex
          Set<String> outgoingLabels = new TreeSet<String>();outgoingLabels.addAll(alphabet);
         
          Iterator<DirectedSparseEdge>outEdgeIt = v.getOutEdges().iterator();
          while(outEdgeIt.hasNext()){
            DirectedSparseEdge outEdge = outEdgeIt.next();
            outgoingLabels.removeAll( (Set<String>)outEdge.getUserDatum(JUConstants.LABEL) );
          }
          if (!outgoingLabels.isEmpty())
          {
            // add a transition
            DirectedSparseEdge edge = new DirectedSparseEdge(v,rejectVertex);
            edge.addUserDatum(JUConstants.LABEL, outgoingLabels, UserData.CLONE);
            g.addEdge(edge);
          }
        }
      }
    }
   
    return transitionsToBeAdded;
  }

  @Test
  public void completeComputeAlphabet0()
  {
    Set<String> alphabet = WMethod.computeAlphabet(new DirectedSparseGraph());
    Assert.assertTrue(alphabet.isEmpty());
  }

  @Test
  public void completeComputeAlphabet1()
  {
    Set<String> alphabet = WMethod.computeAlphabet(buildGraph("A-a->A", "completeComputeAlphabet1"));
    Set<String> expected = new HashSet<String>();expected.addAll( Arrays.asList(new String[] {"a"}));
    Assert.assertTrue(alphabet.equals(expected));
    DirectedSparseGraph g = buildGraph("A-a->A", "completeGraphTest1");Assert.assertFalse(completeGraph(g,"REJECT"));
  }

  @Test
  public void completeComputeAlphabet2()
  {
    Set<String> alphabet = WMethod.computeAlphabet(buildGraph("A-a->A<-b-A", "completeComputeAlphabet2"));
    Set<String> expected = new HashSet<String>();expected.addAll( Arrays.asList(new String[] {"a","b"}));
    Assert.assertTrue(alphabet.equals(expected));
    DirectedSparseGraph g = buildGraph("A-a->A", "completeGraphTest1");Assert.assertFalse(completeGraph(g,"REJECT"));
  }

  @Test
  public void completeComputeAlphabet3()
  {
    Set<String> alphabet = WMethod.computeAlphabet(buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "completeComputeAlphabet3"));
    Set<String> expected = new HashSet<String>();expected.addAll( Arrays.asList(new String[] {"a","b","c","d"}));
    Assert.assertTrue(alphabet.equals(expected));
    DirectedSparseGraph g = buildGraph("A-a->A", "completeGraphTest1");Assert.assertFalse(completeGraph(g,"REJECT"));
  }

  @Test
  public void completeGraphTest1()
  {
    DirectedSparseGraph g = buildGraph("A-a->A", "completeGraphTest1");Assert.assertFalse(completeGraph(g,"REJECT"));
    checkM(g, "A-a->A");   
  }
 
  @Test
  public void completeGraphTest2()
  {
    DirectedSparseGraph g = buildGraph("A-a->B-a->A", "completeGraphTest2");Assert.assertFalse(completeGraph(g,"REJECT"));
    checkM(g, "A-a->A");   
  }
 
  @Test
  public void completeGraphTest3()
  {
    DirectedSparseGraph g = buildGraph("A-a->A<-b-A", "completeGraphTest3");Assert.assertFalse(completeGraph(g,"REJECT"));
    checkM(g, "A-b->A-a->A");   
  }
 
  @Test
  public void completeGraphTest4()
  {
    DirectedSparseGraph g = buildGraph("A-a->B-b->A", "completeGraphTest4");Assert.assertTrue(completeGraph(g,"REJECT"));
    checkM(g, "A-a->B-b->A\nA-b-#REJECT#-a-B");   
  }
 
  @Test
  public void completeGraphTest4b()
  {
    DirectedSparseGraph g = buildGraph("A-a->B-b->A-b->A", "completeGraphTest4b");Assert.assertTrue(completeGraph(g,"REJECT"));
    checkM(g, "A-a->B-b->A-b->A\nREJECT#-a-B");   
  }

  @Test
  public void completeGraphTest5()
  {
    DirectedSparseGraph g = buildGraph("A-a->A-b->B-c->B", "completeGraphTest5");Assert.assertTrue(completeGraph(g,"REJECT"));
    checkM(g, "A-a->A-b->B-c->B\nA-c-#REJECT#-a-B-b-#REJECT");   
 
 
  @Test
  public void completeGraphTest6()
  {
    DirectedSparseGraph g = buildGraph("A-a->A-b->B-c->B-a->C", "completeGraphTest6");Assert.assertTrue(completeGraph(g,"REJECT"));
    checkM(g, "A-a->A-b->B-c->B-a->C\nA-c-#REJECT#-b-B\nC-a-#REJECT\nC-b-#REJECT\nC-c-#REJECT");   
 
 
  @Test
  public void completeGraphTest7()
  {
    DirectedSparseGraph g = buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "completeGraphTest7");Assert.assertTrue(completeGraph(g,"REJECT"));
    final FSMStructure graph = getGraphData(g);
    final FSMStructure expected = getGraphData(buildGraph("A-a->A-b->B-c->B-a->C\nA-c-#REJECT\nA-d-#REJECT\nB-b-#REJECT\nB-d-#REJECT\nC-a-#REJECT\nC-b-#REJECT\nC-c-#REJECT\nC-d-#REJECT\nS-a-#REJECT\nS-b-#REJECT\nS-c-#REJECT\nS-d-#REJECT\nQ-a-#REJECT\nQ-b-#REJECT\nQ-c-#REJECT\nQ-d->S","expected graph"));
    Assert.assertTrue(checkMBoolean(graph,expected,"A","A"));
    Assert.assertTrue(checkMBoolean(graph,expected,"B","B"));
    Assert.assertTrue(checkMBoolean(graph,expected,"Q","Q"));
    Assert.assertTrue(checkMBoolean(graph,expected,"S","S"));
    Assert.assertTrue(checkMBoolean(graph,expected,"REJECT","REJECT"));
 

  @Test
  public void testFindVertex1()
  {
    Assert.assertNull(RPNIBlueFringeLearner.findVertex("aa", "bb", new DirectedSparseGraph()));
  }
 
  @Test
  public void testFindVertex2()
  {
    Assert.assertNull(RPNIBlueFringeLearner.findVertex("aa", "bb", buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex2")));
  }
   
  @Test
  public void testFindVertex3()
  {
    Assert.assertNull(RPNIBlueFringeLearner.findVertex(JUConstants.LABEL, "D", buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex3")));
  }

  @Test
  public void testFindVertex4()
  {
    Vertex v = RPNIBlueFringeLearner.findVertex(JUConstants.PROPERTY, JUConstants.INIT, buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex4"));
    Assert.assertEquals("A", v.getUserDatum(JUConstants.LABEL));
  }
 
  @Test
  public void testFindVertex5()
  {
    Vertex v =  RPNIBlueFringeLearner.findVertex(JUConstants.LABEL, "A", buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex5"));
    Assert.assertEquals("A", v.getUserDatum(JUConstants.LABEL));
  }
 
  @Test
  public void testFindVertex6()
  {
    Vertex v =  RPNIBlueFringeLearner.findVertex(JUConstants.LABEL, "C", buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex6"));
    Assert.assertEquals("C", v.getUserDatum(JUConstants.LABEL));
  }
 
  @Test
  public void testFindVertex7()
  {
    Vertex v = RPNIBlueFringeLearner.findVertex(JUConstants.LABEL, "S", buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex7"));
    Assert.assertEquals("S", v.getUserDatum(JUConstants.LABEL));
  }
 
  @Test
  public void testFindVertex8()
  {
    Vertex v = RPNIBlueFringeLearner.findVertex(JUConstants.LABEL, "Q", buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex8"));
    Assert.assertEquals("Q", v.getUserDatum(JUConstants.LABEL));
  }

 
  /** Builds a set of sequences from a two-dimensional array, where each element corresponds to a sequence.
   *
   * @param data source data
   * @return a set of sequences to apply to an RPNI learner
   */
  public static Set<List<String>> buildSet(String [][] data)
  {
    Set<List<String>> result = new HashSet<List<String>>();
    for(String []seq:data)
    {
      result.add(Arrays.asList(seq));
    }
    return result;
  }
 
  /** Builds a set of sequences from a two-dimensional array, where each element corresponds to a sequence.
   *
   * @param data source data
   * @return a set of sequences to apply to an RPNI learner
   */
  public static List<List<String>> buildList(String [][] data)
  {
    List<List<String>> result = new LinkedList<List<String>>();result.addAll(buildSet(data));
    return result;
  }
 
  @Test
  public void testBuildSet1()
  {
    assertTrue(buildSet(new String[] []{}).isEmpty());
  }

  @Test
  public void testBuildSet2()
  {
    Set<List<String>> expectedResult = new HashSet<List<String>>();
    expectedResult.add(new LinkedList<String>());
    assertTrue(expectedResult.equals(buildSet(new String[] []{new String[]{}})));
  }

  @Test
  public void testBuildSet3A()
  {
    Set<List<String>> expectedResult = new HashSet<List<String>>();
    expectedResult.add(Arrays.asList(new String[]{"a","b","c"}));
    expectedResult.add(new LinkedList<String>());
    assertTrue(expectedResult.equals(buildSet(new String[] []{new String[]{},new String[]{"a","b","c"}})));
  }

  @Test
  public void testBuildSet3B()
  {
    Set<List<String>> expectedResult = new HashSet<List<String>>();
    expectedResult.add(Arrays.asList(new String[]{"a","b","c"}));
    assertTrue(expectedResult.equals(buildSet(new String[] []{new String[]{"a","b","c"}})));
  }

  @Test
  public void testBuildSet4()
  {
    Set<List<String>> expectedResult = new HashSet<List<String>>();
    expectedResult.add(Arrays.asList(new String[]{"a","b","c"}));
    expectedResult.add(new LinkedList<String>());
    expectedResult.add(Arrays.asList(new String[]{"g","t"}));
    expectedResult.add(Arrays.asList(new String[]{"h","q","i"}));
    assertTrue(expectedResult.equals(buildSet(new String[] []{
        new String[]{"a","b","c"},new String[]{"h","q","i"}, new String[] {},new String[]{"g","t"} })));
  }

  /** Converts a transition into an FSM structure, by taking a copy.
   *
   * @param tTable table, where tTable[source][input]=targetstate
   * @param vFrom the order in which elements from tTable are to be used.
   * @param rejectNumber the value of an entry in a tTable which is used to denote an absence of a transition.
   * @return the constructed transition structure.
   */
  public static FSMStructure convertTableToFSMStructure(final int [][]tTable, final int []vFrom, int rejectNumber)
  {
    if (vFrom.length == 0 || tTable.length == 0) throw new IllegalArgumentException("array is zero-sized");
    int alphabetSize = tTable[vFrom[0]].length;
    if (alphabetSize == 0) throw new IllegalArgumentException("alphabet is zero-sized");
    String stateName[] = new String[tTable.length];for(int i=0;i < tTable.length;++i) stateName[i]="S"+i;
    String inputName[] = new String[alphabetSize];for(int i=0;i < alphabetSize;++i) inputName[i]="i"+i;
    FSMStructure fsm = new FSMStructure();
    fsm.init = stateName[vFrom[0]];
    Set<String> statesUsed = new HashSet<String>();
    for(int i=0;i<vFrom.length;++i)
    {
      int currentState = vFrom[i];
      if (currentState == rejectNumber) throw new IllegalArgumentException("reject number in vFrom");
      if (tTable[currentState].length != alphabetSize) throw new IllegalArgumentException("rows of inconsistent size");
      Map<String,String> row = new LinkedHashMap<String,String>();
      fsm.accept.put(stateName[currentState], true);
      for(int input=0;input < tTable[currentState].length;++input)
        if (tTable[currentState][input] != rejectNumber)
        {
          int nextState = tTable[currentState][input];
          if (nextState < 0 || nextState > tTable.length)
            throw new IllegalArgumentException("transition from state "+currentState+" leads to an invalid state "+nextState);
          row.put(inputName[input], stateName[nextState]);
          statesUsed.add(stateName[nextState]);
        }
      fsm.trans.put(stateName[currentState], row);
    }
    statesUsed.removeAll(fsm.accept.keySet());
    if (!statesUsed.isEmpty())
      throw new IllegalArgumentException("Some states in the transition table are not included in vFrom");
    return fsm;
  }
 
  @Test(expected = IllegalArgumentException.class)
  public final void testConvertTableToFSMStructure1a()
  {
    int [][]table = new int[][] {
      {4,5,1,6},
      {7,7}
    };
    convertTableToFSMStructure(table, new int[0], -1);
  }
 
  @Test(expected = IllegalArgumentException.class)
  public final void testConvertTableToFSMStructure1b()
  {
    int [][]table = new int[][] {
      {},
      {1,1}
    };
    convertTableToFSMStructure(table, new int[]{1,0}, -1);
  }
 
  @Test(expected = IllegalArgumentException.class)
  public final void testConvertTableToFSMStructure2()
  {
    int [][]table = new int[][] {
        {1,0,1,0},
        {0,1}
      };
      convertTableToFSMStructure(table, new int[]{0,1}, -1);
  }
 
  @Test(expected = IllegalArgumentException.class)
  public final void testConvertTableToFSMStructure3()
  {
    int [][]table = new int[][] {
        {1,0,1,0},
        {0,1,0,1}
      };
      convertTableToFSMStructure(table, new int[]{0,-1}, -1);
  }
 
  @Test(expected = IllegalArgumentException.class)
  public final void testConvertTableToFSMStructure4a()
  {
    int [][]table = new int[][] {
      {01,  -12},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    FSMStructure fsm = convertTableToFSMStructure(table, new int[]{0,1,2,3}, -1);
    checkM(fsm, getGraphData(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0\nS2-i0->S0\nS2-i1->S0\nS2-i2->S0\nS2-i3->S0", "testConvertTableToFSMStructure4")), "S0", "S0");
  }
 
  @Test(expected = IllegalArgumentException.class)
  public final void testConvertTableToFSMStructure4b()
  {
    int [][]table = new int[][] {
      {01,  -12},
      {0, 30,  -1},
      {0,0,0,-4},
      {-1,-1,-1,-1}
    };
    FSMStructure fsm = convertTableToFSMStructure(table, new int[]{0,1,2,3}, -1);
    checkM(fsm, getGraphData(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0\nS2-i0->S0\nS2-i1->S0\nS2-i2->S0\nS2-i3->S0", "testConvertTableToFSMStructure4")), "S0", "S0");
  }
 
  @Test
  public final void testConvertTableToFSMStructure5()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    FSMStructure fsm = convertTableToFSMStructure(table, new int[]{0,1,3}, -1);
    checkM(fsm, getGraphData(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0", "testConvertTableToFSMStructure4")), "S0", "S0");
  }
 
  @Test
  public final void testConvertTableToFSMStructure6()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    FSMStructure fsm = convertTableToFSMStructure(table, new int[]{1,0,3}, -1);
    checkM(fsm, getGraphData(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0", "testConvertTableToFSMStructure4")), "S0", "S0");
  }

  @Test
  public final void testConvertTableToFSMStructure7()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    FSMStructure fsm = convertTableToFSMStructure(table, new int[]{3,0,1}, -1);
    checkM(fsm, getGraphData(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0", "testConvertTableToFSMStructure4")), "S0", "S0");
  }
 
  @Test
  public final void testConvertTableToFSMStructure8()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    FSMStructure fsm = convertTableToFSMStructure(table, new int[]{3,0,1,0,1,1}, -1);
    checkM(fsm, getGraphData(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0", "testConvertTableToFSMStructure4")), "S0", "S0");
  }

  @Test
  public final void testGetNonRepeatingNumbers0()
  {
    int data[] = DeterministicDirectedSparseGraph.getNonRepeatingNumbers(0, 0);
    Assert.assertEquals(0,data.length);
  }
 
  @Test
  public final void testGetNonRepeatingNumbers1()
  {
    int data[] = DeterministicDirectedSparseGraph.getNonRepeatingNumbers(1, 0);
    Assert.assertEquals(1,data.length);Assert.assertEquals(0, data[0]);
  }
 
  @Test
  public final void testGetNonRepeatingNumbers2()
  {
    int data[] = DeterministicDirectedSparseGraph.getNonRepeatingNumbers(2, 0);
    Assert.assertEquals(2,data.length);
    if (data[0] == 0)
      Assert.assertEquals(1, data[1]);
    else
    {
      Assert.assertEquals(1, data[0]);Assert.assertEquals(0, data[1]);
    }
  }
 
  @Test
  public final void testGetVertex1()
  {
    FSMStructure score = new FSMStructure(TestFSMAlgo.buildGraph("A-a->B-a->C-b->D\n","testFindVertex1"), null);
    Assert.assertTrue(score.getVertex(new LinkedList<String>()).equals("A"));
  }

  @Test
  public final void testGetVertex2()
  {
    FSMStructure score = new FSMStructure(TestFSMAlgo.buildGraph("A-a->B-b->C-b->D\n","testFindVertex2"), null);
    Assert.assertTrue(score.getVertex(Arrays.asList(new String[]{"a","b"})).equals("C"));
  }

  @Test
  public final void testGetVertex3()
  {
    FSMStructure score = new FSMStructure(TestFSMAlgo.buildGraph("A-a->B-a->C-b->D\n","testFindVertex3"), null);
    Assert.assertNull(score.getVertex(Arrays.asList(new String[]{"a","d"})));
  }

  @Test
  public final void assertsEnabled()
  {
    boolean assertsOn = false;
    assert assertsOn = true;
   
    Assert.assertTrue("asserts have to be enabled", assertsOn);
  }
 
  /** Holds the JFrame to see the graphs being dealt with. Usage:
   * <pre>
   *     updateFrame(g);// a public method
   * </pre>
   * where <i>g</i> is the graph to be displayed.
   */
  protected static Visualiser visFrame = null;
 
  @BeforeClass
  public static void initJungViewer() // initialisation - once only for all tests in this class
  {   
    visFrame = null;
  }

  @AfterClass
  public static void cleanUp()
  {
    try {
      if (visFrame != null)
      {
        SwingUtilities.invokeAndWait(new Runnable()
        {
          public void run()
          {
              visFrame.setVisible(false);
              visFrame.dispose();
          }
        });
      }
    } catch (InterruptedException e) {
      // cannot do anything with this
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      // cannot do anything with this
      e.printStackTrace();
    }
  } 

  /** In order to be able to use old junit runner. */
  public static junit.framework.Test suite()
  {
    return new JUnit4TestAdapter(TestFSMAlgo.class);
  }
}
TOP

Related Classes of statechum.analysis.learning.TestFSMAlgo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.