Package statechum.analysis.learning

Source Code of statechum.analysis.learning.MethodAndArgs

/*Copyright (c) 2006, 2007, 2008 Neil Walkinshaw and Kirill Bogdanov
This file is part of StateChum

StateChum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

StateChum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with StateChum.  If not, see <http://www.gnu.org/licenses/>.
*/

package statechum.analysis.learning;

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

import junit.framework.Assert;

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

import statechum.ArrayOperations;
import statechum.Configuration;
import statechum.DeterministicDirectedSparseGraph;
import statechum.JUConstants;
import statechum.StringVertex;
import statechum.Configuration.IDMode;
import statechum.Configuration.LEARNER;
import statechum.Configuration.QuestionGeneratorKind;
import statechum.Configuration.ScoreMode;
import statechum.DeterministicDirectedSparseGraph.CmpVertex;
import statechum.DeterministicDirectedSparseGraph.DeterministicEdge;
import statechum.DeterministicDirectedSparseGraph.DeterministicVertex;
import statechum.DeterministicDirectedSparseGraph.VertexID;
import statechum.DeterministicDirectedSparseGraph.VertexID.VertKind;
import statechum.Helper.whatToRun;
import statechum.analysis.learning.RPNIBlueFringeLearnerOrig.OrigStatePair;
import statechum.analysis.learning.rpnicore.AMEquivalenceClass;
import statechum.analysis.learning.rpnicore.LearnerGraph;
import statechum.analysis.learning.rpnicore.WMethod;
import statechum.analysis.learning.rpnicore.WMethod.DifferentFSMException;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.impl.DirectedSparseGraph;
import edu.uci.ics.jung.graph.impl.DirectedSparseVertex;
import edu.uci.ics.jung.utils.UserData;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import static statechum.analysis.learning.Visualiser.isGraphTransformationDebug;

public class TestFSMAlgo {
  org.w3c.dom.Document doc = null;

  public TestFSMAlgo()
  {
    mainConfiguration = Configuration.getDefaultConfiguration();
    mainConfiguration.setAllowedToCloneNonCmpVertex(true);
  }
 
  /** Make sure that whatever changes a test have made to the
   * configuration, next test is not affected.
   */
  @Before
  public void beforeTest()
  {
    config = (Configuration)mainConfiguration.clone();
    LearnerGraph.testMode=true;

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    try
    {
      factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);factory.setXIncludeAware(false);
      factory.setExpandEntityReferences(false);factory.setValidating(false);// we do not have a schema to validate against-this does not seem necessary for the simple data format we are considering here.
      doc = factory.newDocumentBuilder().newDocument();
    }
    catch(ParserConfigurationException e)
    {
      statechum.Helper.throwUnchecked("failed to construct DOM document",e);
    }
  }

  /** The configuration to use when running tests. */
  private Configuration config = null, mainConfiguration = null;

  static protected OrigStatePair constructOrigPair(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 OrigStatePair(aV,bV);
  }

  /** Used to check that equality checking is implemented correctly.
   * The first two arguments are supposed to be independently constructed and they
   * are checked for equality.
   * The last two arguments are supposed to be different from any of the first two.
   */
  static public void equalityTestingHelper(Object p, Object q,
      Object differentA, Object differentB)
  {
    assertTrue(p.equals(p));assertTrue(q.equals(q));
    assertTrue(p.equals(q));assertTrue(q.equals(p));
    assertTrue(p.hashCode() == q.hashCode());assertTrue(p.hashCode() != 0);assertTrue(q.hashCode() != 0);
    assertFalse(p.equals(null));assertFalse(q.equals(null));
   
    assertFalse(p.equals("test"));assertFalse(q.equals("test"));
    assertFalse("test".equals(p));assertFalse("test".equals(q));
   
    Object obj = new Object();assertTrue(obj.equals(obj));
    assertFalse(p.equals(obj));assertFalse(q.equals(obj));
    assertFalse(obj.equals(p));assertFalse(obj.equals(q));
   
    assertFalse(p.equals(differentA));assertFalse(q.equals(differentA));
    if (differentA != null)
    {
      assertFalse(differentA.equals(p));
      assertFalse(differentA.equals(q));
      assertFalse(p.hashCode() == differentA.hashCode());
      assertFalse(q.hashCode() == differentA.hashCode());
    }
    if (differentB != null)
    {
      assertFalse(differentB.equals(p));
      assertFalse(differentB.equals(q));
      assertFalse(p.hashCode() == differentB.hashCode());
      assertFalse(q.hashCode() == differentB.hashCode());
    }
  }
 
  /** Used to check that compareTo method works well. */
  @SuppressWarnings("unchecked")
  static private void checkLessHelper(Comparable p, Comparable q)
  {
    assertFalse(p.equals(q));assertFalse(p.hashCode() == q.hashCode());
    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 testConfigurationEquals()
  {
    Configuration confA = new Configuration(), confB = new Configuration(),
      confC = new Configuration(), confD = new Configuration();
    confA.setBumpPositives(true);confA.setLearnerIdMode(Configuration.IDMode.NONE);confA.setDefaultInitialPTAName("test");
    confB.setBumpPositives(true);confB.setLearnerIdMode(Configuration.IDMode.NONE);confB.setDefaultInitialPTAName("test");
    confC.setBumpPositives(true);confC.setLearnerIdMode(Configuration.IDMode.NONE);confC.setDefaultInitialPTAName("a");
    confD.setLearnerIdMode(Configuration.IDMode.POSITIVE_NEGATIVE);
    equalityTestingHelper(confA, confB, confC, confD);
    confC.setDefaultInitialPTAName("test");confA.setDefaultInitialPTAName("b");
    equalityTestingHelper(confC, confB, confA, confD);
  }
 
  @Test
  public void testConfigurationClone()
  {
    Configuration confA = new Configuration(),
    confC = new Configuration(), confD = new Configuration();
    confA.setBumpPositives(true);confA.setLearnerIdMode(Configuration.IDMode.NONE);confA.setDefaultInitialPTAName("test");
    confC.setBumpPositives(true);confC.setLearnerIdMode(Configuration.IDMode.NONE);confC.setDefaultInitialPTAName("a");
    Configuration confClone = (Configuration)confA.clone();
    equalityTestingHelper(confA, confClone, confC, confD);
   
    confClone.setDefaultInitialPTAName("avalue");// mess up the clone
    equalityTestingHelper(confA, confA, confClone, confD);
    equalityTestingHelper(confA.clone(), confA, confClone, confD);
   
    confA.setDefaultInitialPTAName("avalue");// mess up the original the same way as the clone was messed up
    equalityTestingHelper(confA, confClone, confC, confD);
  }

  /** An obvious problem with Configuration is forgetting to include all
   * the necessary variables in equals and hashcode methods. This one
   * checks that each change to instance variables affects the response from
   * those methods. This is accomplished by collecting all fields, identifying
   * the corresponding setter methods and choosing two values for each
   * of those fields. Subsequently, I can assign the first value to all fields
   * and go through the fields setting the second one and checking that
   * this affects hashCode and equals.
   */
  @Test
  public void testConfigurationUsesAllItsVariables()
  {
    class MethodAndArgs {
      public MethodAndArgs(Method m, Field f, Object a, Object b)
      {
        method=m;Arg=a;AlternativeArg=b;field = f;
      }
      Field field;
      Method method;Object Arg, AlternativeArg;
    }

    List<MethodAndArgs> MethodsArgs=new LinkedList<MethodAndArgs>();
    for(Field var:Configuration.class.getDeclaredFields())
    {
      if (var.getType() != Configuration.class &&
          var.getName() != "$VRc"// added by eclemma (coverage analysis)
            && !java.lang.reflect.Modifier.isFinal(var.getModifiers())
            )
      {
        String varName = var.getName();
        Method setter = Configuration.getMethod(Configuration.GETMETHOD_KIND.FIELD_SET, var);
        Object valueA = null, valueB = null;
        if (var.getType().equals(Boolean.class) || var.getType().equals(boolean.class))
        {
          valueA = new Boolean(true);valueB=new Boolean(false);
        }
        else
          if (var.getType().equals(Double.class) || var.getType().equals(double.class))
          {
            valueA = new Double(0.4);valueB=new Double(0.5);// note that we have to choose values which fall within the allowed range of values
          }
          else
          if (var.getType().equals(String.class))
          {
            valueA = varName+", value A";valueB=varName+", value B";
          }
          else
            if (var.getType().equals(IDMode.class))
            {
              valueA = IDMode.POSITIVE_NEGATIVE;valueB=IDMode.POSITIVE_ONLY;
            }
            else
              if (var.getType().equals(ScoreMode.class))
              {
                valueA = ScoreMode.KTAILS;valueB=ScoreMode.COMPATIBILITY;
              }
            else
              if (var.getType().equals(QuestionGeneratorKind.class))
              {
                  valueA = QuestionGeneratorKind.CONVENTIONAL;valueB=QuestionGeneratorKind.SYMMETRIC;
              }
              else
                if (var.getType().equals(LEARNER.class))
                {
                    valueA = LEARNER.LEARNER_BLUEFRINGE_MAY2008;valueB=LEARNER.LEARNER_BLUEAMBER_MAY2008;
                }
                else
                if (var.getType().equals(Integer.class) || var.getType().equals(int.class))
                {
                  valueA = varName.hashCode();valueB=setter.hashCode();// just some integers likely to be different from each other between different variables.
                }
                else
                  throw new IllegalArgumentException("A field "+var+" of Configuration has an unsupported type "+var.getType());
       
        MethodsArgs.add(new MethodAndArgs(setter,var,valueA,valueB));
      }
    }
   
    try {
      // Now check that hashCode and equals are affected by values of different fields.
      for(MethodAndArgs currentMethod:MethodsArgs)
      {
        Configuration
          configA = Configuration.getDefaultConfiguration().copy(),
          configB = Configuration.getDefaultConfiguration().copy();
        for(MethodAndArgs orig:MethodsArgs)
        {
          orig.method.invoke(configA, new Object[]{orig.Arg});
          orig.method.invoke(configB, new Object[]{orig.Arg});
        }
        Assert.assertEquals(configB, configA);
       
        // now test that we can serialise these
        {
          org.w3c.dom.Element xmlB = configB.writeXML(doc),xmlA=configA.writeXML(doc);
          Configuration loadedB=new Configuration();loadedB.readXML(xmlB);Configuration loadedA=new Configuration();loadedA.readXML(xmlA);
          Assert.assertEquals(loadedB, loadedA);
          Assert.assertEquals(loadedB, configA);
        }

        currentMethod.method.invoke(configB, new Object[]{currentMethod.AlternativeArg});
        String errMsg = "configurations differ: field "+currentMethod.field+" is not in use for ";
        Assert.assertFalse(errMsg+"equals",configB.equals(configA));
        Assert.assertFalse(errMsg+"equals",configA.equals(configB));
       
        {
          org.w3c.dom.Element xmlB = configB.writeXML(doc),xmlA=configA.writeXML(doc);
          Configuration loadedB=new Configuration();loadedB.readXML(xmlB);Configuration loadedA=new Configuration();loadedA.readXML(xmlA);
          Assert.assertEquals(loadedA, configA);
          Assert.assertFalse(errMsg+"equals",loadedB.equals(loadedA));
          Assert.assertFalse(errMsg+"equals",loadedB.equals(configA));
          Assert.assertFalse(errMsg+"equals",loadedA.equals(loadedB));
        }
       
        Assert.assertTrue(errMsg+"hashCode",configA.hashCode() != configB.hashCode());
      }
    } catch (Exception e) {
      e.printStackTrace();
      Assert.fail(e.getMessage());
    }
  }

  /** Wrong tag. */
  @Test(expected=IllegalArgumentException.class)
  public void testSerialisationFailure1()
  {
    new Configuration().readXML(doc.createElement("test"));
  }
 
  /** No data to load. */
  @Test
  public void testSerialisationEmpty()
  {
    Configuration cnf = new Configuration();cnf.readXML(doc.createElement(Configuration.configXMLTag));
    Assert.assertEquals(new Configuration(), cnf);
  }
 
  /** Old data should not affect us. */
  @Test
  public void testSerialisationOldJunk_normal()
  {
    org.w3c.dom.Element elem = new Configuration().writeXML(doc), oldData = doc.createElement(Configuration.configVarTag);
    oldData.setAttribute(Configuration.configVarAttrName, "old_junk");
    oldData.setAttribute(Configuration.configVarAttrValue, "junk");
   
    elem.appendChild(oldData);
    Configuration cnf = new Configuration();cnf.readXML(elem);
    Assert.assertEquals(new Configuration(), cnf);
  }
 
  /** Old data causes an exception to be thrown. */
  @Test
  public void testSerialisationOldJunk_strict()
  {
    final org.w3c.dom.Element elem = new Configuration().writeXML(doc), oldData = doc.createElement(Configuration.configVarTag);
    oldData.setAttribute(Configuration.configVarAttrName, "old_junk");
    oldData.setAttribute(Configuration.configVarAttrValue, "junk");
   
    elem.appendChild(oldData);
    statechum.Helper.checkForCorrectException(new whatToRun() { public void run() {
      new Configuration().readXML(elem,true);
    }}, IllegalArgumentException.class,"cannot deserialise unknown field");
  }
 

  /** Unexpected tag. */
  @Test
  public void testSerialisationFailure2()
  {
    final org.w3c.dom.Element cnf = new Configuration().writeXML(doc);
    cnf.appendChild(doc.createElement("junk"));
    statechum.Helper.checkForCorrectException(new whatToRun() { public void run() {
      new Configuration().readXML(cnf);
    }},IllegalArgumentException.class,"unexpected element");
  }
   
  /** Text elements are ignored. */
  @Test
  public void testSerialisationFailure3a()
  {
    final org.w3c.dom.Element cnf = new Configuration().writeXML(doc);
    cnf.appendChild(doc.createTextNode(Configuration.configVarTag));
    Configuration c = new Configuration();c.readXML(cnf);
    Assert.assertEquals(new Configuration(),c);
  }
 
  /** Unexpected type of an element. */
  @Test
  public void testSerialisationFailure3b()
  {
    final org.w3c.dom.Element cnf = new Configuration().writeXML(doc);
    cnf.appendChild(doc.createComment(Configuration.configVarTag));
    statechum.Helper.checkForCorrectException(new statechum.Helper.whatToRun() { public void run() {
      new Configuration().readXML(cnf);
    }},IllegalArgumentException.class,"unexpected element");
  }
 
  /** Unexpected element. */
  @Test
  public void testSerialisationFailure4()
  {
    statechum.Helper.checkForCorrectException(new statechum.Helper.whatToRun() { public void run() {
      new Configuration().readXML(doc.createTextNode(Configuration.configXMLTag));
    }},IllegalArgumentException.class,"invalid node type passed to readXML");
  }
   
  /** Unexpected type of an element. */
  @Test
  public void testSerialisationFailure5()
  {
    statechum.Helper.checkForCorrectException(new statechum.Helper.whatToRun() { public void run() {
      new Configuration().readXML(doc.createElement("junk"));
    }},IllegalArgumentException.class,"configuration cannot be loaded from element");
  }
   
  /** Tests that it is not possible to create an invalid vertexid. */
  @Test(expected=IllegalArgumentException.class)
  public void testCannotCreateNoneVertexID1()
  {
    new VertexID(VertKind.NONE,3);
  }
 
  /** Tests that it is not possible to create an invalid vertexid. */
  @Test(expected=IllegalArgumentException.class)
  public void testCannotCreateNoneVertexID2()
  {
    new VertexID(null);
  }
 
  /** Tests equality for VertexIDs. */
  @Test
  public void testVertexIDEquals1()
  {
    equalityTestingHelper(new VertexID("A"), new VertexID("A"), new VertexID("B"), new VertexID("C"));
  }

  /** Tests equality for VertexIDs. */
  @Test
  public void testVertexIDEquals2()
  {
    equalityTestingHelper(new VertexID(VertKind.POSITIVE,5), new VertexID(VertKind.POSITIVE,5), new VertexID(VertKind.NEGATIVE,9), new VertexID(VertKind.INIT,9));
  }

  public final static String
    idP5 = new VertexID(VertKind.POSITIVE,5).getStringId(),
    idN5 = new VertexID(VertKind.NEGATIVE,5).getStringId(),
    idP6 = new VertexID(VertKind.POSITIVE,6).getStringId();
 
  /** Tests equality for VertexIDs. */
  @Test
  public void testVertexIDEquals3()
  {
    equalityTestingHelper(new VertexID(VertKind.NEGATIVE,5), new VertexID(VertKind.NEGATIVE,5), new VertexID(VertKind.POSITIVE,5), new VertexID(VertKind.INIT,5));
  }
 
  /** Tests equality for VertexIDs with string and numerical IDs. */
  @Test
  public void testVertexIDEquals4()
  {
    equalityTestingHelper(new VertexID(VertKind.POSITIVE,5), new VertexID(idP5), new VertexID(idN5), new VertexID(VertKind.INIT,9));
  }

  /** Tests equality for VertexIDs with string and numerical IDs, checking that cached representation works. */
  @Test
  public void testVertexIDEquals_cached()
  {
    VertexID p=new VertexID(VertKind.POSITIVE,5), q=new VertexID(idP5),
    differentA=new VertexID(VertKind.POSITIVE,6), differentB=new VertexID(VertKind.INIT,9);
    equalityTestingHelper(p, p, differentA, differentB);// at this point, numeric ID will have a textual representation added

    equalityTestingHelper(p, q, differentA, differentB);
    equalityTestingHelper(p, new VertexID(idP5), differentA, differentB);
    equalityTestingHelper(new VertexID(idP5), q, differentA, differentB);
    equalityTestingHelper(new VertexID(idP5), q, new VertexID(idP6), new VertexID(VertKind.POSITIVE,6));
    equalityTestingHelper(new VertexID(idP5), q, new VertexID(idN5), new VertexID(VertKind.POSITIVE,6));
  }

  /** Tests VertexID toString methods. */
  @Test
  public void testVertexIDToString()
  {
    Assert.assertEquals("P5", new VertexID(idP5).toString());
    Assert.assertEquals("N5", new VertexID(idN5).toString());
    Assert.assertEquals("P5", new VertexID(VertKind.POSITIVE,5).toString());
    Assert.assertEquals("N5", new VertexID(VertKind.NEGATIVE,5).toString());

    Assert.assertEquals("JustAnything", new VertexID("JustAnything").toString());
    Assert.assertEquals("V5", new VertexID(VertKind.NEUTRAL,5).toString());
  }
 
  @Test
  public void testVertexIDLess1()
  {
    VertexID pA=new VertexID(VertKind.POSITIVE,5), pB=new VertexID(idP5),
      qA = new VertexID(VertKind.POSITIVE,6);
    checkLessHelper(pA,qA);
    checkLessHelper(pB,qA);// now qA has a cached representation of its string value.
    checkLessHelper(pB,qA);
    checkLessHelper(pA,qA);
  }
 
  @Test
  public void testVertexIDLess2()
  {
    VertexID pA=new VertexID(idP5), pB=new VertexID(VertKind.POSITIVE,5),
      qA = new VertexID(idP6);
    checkLessHelper(pA,qA);
    checkLessHelper(pB,qA);// now pB has a cached representation of its string value.
    checkLessHelper(pB,qA);
    checkLessHelper(pA,qA);
  }
 
  @Test
  public void testVertexIDLess3()
  {
    VertexID pA=new VertexID(VertKind.POSITIVE,5), pB=new VertexID(VertKind.POSITIVE,10),
      qA = new VertexID(VertKind.POSITIVE,6);
    checkLessHelper(pA,qA);
    checkLessHelper(pA,pB);
    checkLessHelper(qA,pB);
   
    Assert.assertTrue("P10".compareTo("P5") < 0);
   
    Assert.assertTrue(pB.compareTo(new VertexID(idP5)) > 0);
   
    checkLessHelper(pA,qA);
    checkLessHelper(pA,pB);
    checkLessHelper(qA,pB);
  }
 
  private final DeterministicVertex DvertA = new DeterministicVertex("a"),DvertB = new DeterministicVertex("a");
  private final DeterministicVertex DdifferentA = new DeterministicVertex("b");

  private final StringVertex SvertA = new StringVertex("a"),SvertB = new StringVertex("a");
  private final StringVertex SdifferentA = new StringVertex("b");

  /** Resets the attributes on vertices used for equality testing. */
  @Before
  public void beforeTests()
  {
    DvertA.setAccept(true);DvertB.setAccept(true);DvertA.setColour(null);DvertB.setColour(null);DvertA.setHighlight(false);DvertB.setHighlight(false);
    SvertA.setAccept(true);SvertB.setAccept(true);SvertA.setColour(null);SvertB.setColour(null);SvertA.setHighlight(false);SvertB.setHighlight(false);
  }
 
  @Test
  public void checkDEquality1()
  {
    DvertA.setAccept(true);DvertB.setAccept(true);
    equalityTestingHelper(DvertA,DvertA,DdifferentA,SdifferentA);equalityTestingHelper(DvertB,DvertB,DdifferentA,SdifferentA);
    equalityTestingHelper(DvertA,DvertB,DdifferentA,SdifferentA);
  }

  @Test
  public void checkDEquality2()
  {
    DvertA.setAccept(false);DvertB.setAccept(false);
    equalityTestingHelper(DvertA,DvertA,DdifferentA,SdifferentA);equalityTestingHelper(DvertB,DvertB,DdifferentA,SdifferentA);
    equalityTestingHelper(DvertA,DvertB,DdifferentA,SdifferentA);
  }

  @Test
  public void checkDEquality3()
  {
    DvertA.setAccept(true);DvertB.setAccept(false);
    equalityTestingHelper(DvertA,DvertA,DvertB,DdifferentA);equalityTestingHelper(DvertB,DvertB,DvertA,DdifferentA);
  }
 
  @Test
  /** Checks that attributes other than accept and name are ignored. */
  public void checkDEquality_ignoresAttrs()
  {
    DvertA.setAccept(true);DvertB.setAccept(true);
    DvertA.setColour(JUConstants.RED);DvertA.setHighlight(true);DvertA.addUserDatum(JUConstants.INITIAL, "", UserData.SHARED);DvertA.addUserDatum(JUConstants.JUNKVERTEX, "a", UserData.SHARED);
    DvertB.setColour(JUConstants.BLUE);DvertB.setHighlight(true);DvertB.removeUserDatum(JUConstants.INITIAL);DvertB.addUserDatum(JUConstants.JUNKVERTEX, "b", UserData.SHARED);
    equalityTestingHelper(DvertA,DvertB,DdifferentA,SdifferentA);
  }
 
  @Test
  public void checkSEquality1()
  {
    SvertA.setAccept(true);SvertB.setAccept(true);
    equalityTestingHelper(SvertA,SvertA,SdifferentA,DdifferentA);equalityTestingHelper(SvertB,SvertB,SdifferentA,DdifferentA);
    equalityTestingHelper(SvertA,SvertB,SdifferentA,DdifferentA);
  }

  @Test
  public void checkSEquality2()
  {
    SvertA.setAccept(false);SvertB.setAccept(false);
    equalityTestingHelper(SvertA,SvertA,SdifferentA,DdifferentA);equalityTestingHelper(SvertB,SvertB,SdifferentA,DdifferentA);
    equalityTestingHelper(SvertA,SvertB,SdifferentA,DdifferentA);
  }

  @Test
  /** Checks that if one is accept and another one is reject, they are different. */
  public void checkSEquality3()
  {
    SvertA.setAccept(true);SvertB.setAccept(false);
    equalityTestingHelper(SvertA,SvertA,SvertB,SdifferentA);
    equalityTestingHelper(SvertB,SvertB,SvertA,SdifferentA);
 

  @Test
  /** Checks that attributes other than accept and name are ignored. */
  public void checkSEquality_ignoresAttrs()
  {
    SvertA.setAccept(true);SvertB.setAccept(true);
    SvertA.setColour(JUConstants.RED);SvertA.setHighlight(true);
    SvertB.setColour(JUConstants.BLUE);SvertB.setHighlight(true);
    equalityTestingHelper(SvertA,SvertB,SdifferentA,DdifferentA);
  }

  /** Checks that if CmpVertex implemented with different types
   * (StringVertex v.s. DeterminisitcVertex), equals returns false.
   * Right now, we allow comparisons between different types, hence the test is commented out.
  @Test
  public void checkSEquality4()
  {
    DvertA.setAccept(true);DvertB.setAccept(true);SvertA.setAccept(true);SvertB.setAccept(true);
    equalityTestingHelper(DvertA,DvertB,SvertA,SvertB);
  } 
   */

  /** Checks that implementations of different types can be compared.
   */
  @Test
  public void checkEquality_differentTypes()
  {
    equalityTestingHelper(SvertA,DvertA,SdifferentA,DdifferentA);
  }

  @Test
  public void checkDComparison1()
  {
    checkLessHelper(DvertA, new DeterministicVertex("b"));
  }
 
  @Test
  public void checkSComparison1()
  {
    checkLessHelper(SvertA, new StringVertex("b"));
  }
 
  @Test
  public void checkComparison_differentTypes()
  {
    checkLessHelper(DvertA, new StringVertex("b"));
    checkLessHelper(SvertA, new DeterministicVertex("b"));
  }

  /** Checks that it is not possible to compare implementations of different types.
   * The restriction is useful to detect programming errors when I end up putting elements of unrelated graphs into the same collection.
   * Decided to comment this out since the restriction makes life hard: if I have
   * a collection of StringVertices and another one of Deterministic ones, they may
   * actually be equal, but the way Java5 collections compare them makes it impossible
   * to use equals without causing a comparison between vertices of the two types.
  @Test(expected=IllegalArgumentException.class)
  public void checkComparison_fail1()
  {
    SvertA.compareTo(DvertA);
  }
   
  @Test(expected=IllegalArgumentException.class)
  public void checkComparison_fail2()
  {
    DvertA.compareTo(SvertA);
  }
   */
 
  @Test
  public void testDeterministicVertexComparison1_old()
  {
    DeterministicVertex p = new DeterministicVertex("P"), q= new DeterministicVertex("Q");
    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 testDeterministicVertexComparison2_old()
  {
    DeterministicVertex p = new DeterministicVertex("A"), q= new DeterministicVertex("B");
    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 testDeterministicVertexComparison3_old()
  {
    DeterministicVertex p = new DeterministicVertex("P"), q= new DeterministicVertex("P");
    assertTrue(p.equals(q));
    assertTrue(p.compareTo(q)==0);
  }

  @Test(expected=IllegalArgumentException.class)
  public void testEqClassEquality_fail1()
  {
    new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{}));
  }
 
  @Test(expected=IllegalArgumentException.class)
  public void testEqClassEquality_fail2()
  {
    new AMEquivalenceClass(null);
  }
 
  @Test
  public void testEqClass_toString1()
  {
    Assert.assertEquals("[B->{B,A,D}]",
    new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        new StringVertex("B"),new StringVertex("A"),new StringVertex("D")})).toString());   
  }
 
  @Test
  public void testEqClass_toString2()
  {
    Assert.assertEquals("[B->{B}]",
    new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        new StringVertex("B")})).toString());   
  }
 
  @Test
  public void testEqClassEquality1()
  {
    equalityTestingHelper(
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("B"),new StringVertex("A"),new StringVertex("C")})),
       
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("B"),new StringVertex("A"),new StringVertex("C")})),

        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("A"),new StringVertex("A"),new StringVertex("C")})),
   
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("B"),new StringVertex("A"),new StringVertex("D")}))
    );
  }

  @Test
  public void testEqClassEquality2()
  {
    equalityTestingHelper(
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("B")})),
       
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("B")})),

        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("A"),new StringVertex("A"),new StringVertex("C")})),
   
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("B"),new StringVertex("A"),new StringVertex("D")}))
    );
  }

  @Test
  public void testEqClassEquality3()
  {
    equalityTestingHelper(
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("A"),new StringVertex("B"),new StringVertex("C")})),
       
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("A"),new StringVertex("B"),new StringVertex("C")})),

        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("A"),new StringVertex("B"),new StringVertex("D")})),
   
        new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
            new StringVertex("B"),new StringVertex("A"),new StringVertex("C")}))
    );
  }

  @Test
  public final void testAM_colour1()
  {
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        new StringVertex("A"),new StringVertex("B"),new StringVertex("C")}));
    eq.computeMergedColour();
    Assert.assertNull(eq.getMergedVertex().getColour());
  }
 
  @Test
  public final void testAM_colour2a()
  {
    CmpVertex vertB = new StringVertex("B");vertB.setColour(JUConstants.RED);
    CmpVertex vertC = new StringVertex("C");
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        new StringVertex("A"),vertB,vertC}));
    eq.computeMergedColour();
    Assert.assertTrue(eq.getMergedVertex().getColour() == JUConstants.RED);
  }

  @Test
  public final void testAM_colour2b()
  {
    CmpVertex vertB = new StringVertex("B");vertB.setColour(JUConstants.BLUE);
    CmpVertex vertC = new StringVertex("C");
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        new StringVertex("A"),vertB,vertC}));
    eq.computeMergedColour();
    Assert.assertTrue(eq.getMergedVertex().getColour() == JUConstants.BLUE);
  }

  @Test
  public final void testAM_colour2c()
  {
    CmpVertex vertB = new StringVertex("B");vertB.setColour(JUConstants.AMBER);
    CmpVertex vertC = new StringVertex("C");vertC.setColour(JUConstants.BLUE);
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        new StringVertex("A"),vertB,vertC}));
    eq.computeMergedColour();
    Assert.assertTrue(eq.getMergedVertex().getColour() == JUConstants.BLUE);
  }

  @Test
  public final void testAM_colour2d()
  {
    CmpVertex vertA = new StringVertex("A");vertA.setColour(JUConstants.AMBER);
    CmpVertex vertB = new StringVertex("B");
    CmpVertex vertC = new StringVertex("C");vertC.setColour(JUConstants.BLUE);
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        vertA,vertB,vertC}));
    eq.computeMergedColour();
    Assert.assertTrue(eq.getMergedVertex().getColour() == JUConstants.BLUE);
  }

  @Test
  public final void testAM_colour2e()
  {
    CmpVertex vertA = new StringVertex("A");vertA.setColour(JUConstants.AMBER);
    CmpVertex vertB = new StringVertex("B");
    CmpVertex vertC = new StringVertex("C");
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        vertA,vertB,vertC}));
    eq.computeMergedColour();
    Assert.assertNull(eq.getMergedVertex().getColour());
  }

  @Test
  public final void testAM_colour2f()
  {
    CmpVertex vertA = new StringVertex("A");vertA.setColour(JUConstants.AMBER);
    CmpVertex vertB = new StringVertex("B");
    CmpVertex vertC = new StringVertex("C");vertC.setColour(JUConstants.AMBER);
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        vertA,vertB,vertC}));
    eq.computeMergedColour();
    Assert.assertNull(eq.getMergedVertex().getColour());
  }

  @Test
  public final void testAM_colour2g()
  {
    CmpVertex vertA = new StringVertex("A");
    CmpVertex vertB = new StringVertex("B");vertB.setColour(JUConstants.AMBER);
    CmpVertex vertC = new StringVertex("C");vertC.setColour(JUConstants.AMBER);
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        vertA,vertB,vertC}));
    eq.computeMergedColour();
    Assert.assertNull(eq.getMergedVertex().getColour());
  }

  @Test
  public final void testAM_colour2h()
  {
    CmpVertex vertA = new StringVertex("A");vertA.setColour(JUConstants.AMBER);
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        vertA}));
    eq.computeMergedColour();
    Assert.assertTrue(eq.getMergedVertex().getColour() == JUConstants.AMBER);
  }

  @Test
  public final void testAM_colour3()
  {
    CmpVertex vertB = new StringVertex("B");vertB.setColour(JUConstants.RED);
    CmpVertex vertC = new StringVertex("C");vertC.setColour(JUConstants.BLUE);
    AMEquivalenceClass eq =new AMEquivalenceClass(Arrays.asList(new CmpVertex[]{
        new StringVertex("A"),vertB,vertC}));
    eq.computeMergedColour();
    Assert.assertTrue(eq.getMergedVertex().getColour() == JUConstants.RED);
  }

  /** Tests of comparison/equality of string/deterministic pairs of vertices
   * (string-"a"/string "b"/det-"a"/det-"b")
   * each pair of above, against another pair.
   */
  @Test
  public void testStatePairEquality()
  {
    final Object samePairs[] = new StatePair[]{
        new StatePair(new StringVertex("a"), new StringVertex("b")),
        new StatePair(new DeterministicVertex("a"), new StringVertex("b")),
        new StatePair(new StringVertex("a"), new DeterministicVertex("b")),
        new StatePair(new DeterministicVertex("a"), new DeterministicVertex("b"))       
    },
    differentPairs[] = new Object[] {
        new StatePair(new StringVertex("a"), new StringVertex("c")),
        new StatePair(new StringVertex("d"), new StringVertex("b")),
        new StatePair(new StringVertex("d"), new StringVertex("e")),
        constructOrigPair("a", "b")
    };
    for(int sameFirst=0;sameFirst<samePairs.length;++sameFirst)
      for(int sameSecond=0;sameSecond<samePairs.length;++sameSecond)
        for(int different=0;different<differentPairs.length;++different)
          equalityTestingHelper(samePairs[sameFirst],samePairs[sameSecond],differentPairs[different],differentPairs[differentPairs.length-different-1]);

    equalityTestingHelper(constructOrigPair("a","b"), constructOrigPair("a","b"),
        constructOrigPair("a","c"),constructOrigPair("b","b"));
    for(int i=0;i<samePairs.length;++i)
      equalityTestingHelper(constructOrigPair("a","b"), constructOrigPair("a","b"),
          samePairs[i],samePairs[samePairs.length-i-1]);
  }
 
  private static void checkLess(String a,String b,String c,String d)
  {
    checkLessHelper(new StatePair(new StringVertex(a), new StringVertex(b)), new StatePair(new StringVertex(c), new StringVertex(d)));
    checkLessHelper(new StatePair(new DeterministicVertex(a), new StringVertex(b)), new StatePair(new DeterministicVertex(c), new StringVertex(d)));
    checkLessHelper(new StatePair(new StringVertex(a), new DeterministicVertex(b)), new StatePair(new StringVertex(c), new DeterministicVertex(d)));
  }
 
  @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,DeterministicVertex> existingVertices = new HashMap<String,DeterministicVertex>();
    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) {
        DeterministicVertex fromVertex = existingVertices.get(from), toVertex = existingVertices.get(to);
       
        if (fromVertex == null)
        {
          fromVertex = new DeterministicDirectedSparseGraph.DeterministicVertex(from);
          if (existingVertices.isEmpty())
            fromVertex.addUserDatum(JUConstants.INITIAL, true, UserData.SHARED);
          fromVertex.addUserDatum(JUConstants.ACCEPTED, true, 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(to);
            toVertex.removeUserDatum(JUConstants.ACCEPTED); // in case we've got a reject loop in the same state
            toVertex.addUserDatum(JUConstants.ACCEPTED, accept, UserData.SHARED);
            existingVertices.put(to, toVertex);
            g.addVertex(toVertex);
          }
          else
            if (DeterministicDirectedSparseGraph.isAccept(toVertex) != 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);
      }
    });

    if (isGraphTransformationDebug(g))
    {
      Visualiser.updateFrame(g, null);System.out.println("******** PROCESSING "+name+" **********\n");
    }
    return g;
  }

  /** 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 LearnerGraph graph = new LearnerGraph(g,Configuration.getDefaultConfiguration());
    final LearnerGraph expected = new LearnerGraph(expectedGraph,Configuration.getDefaultConfiguration());
   
    assertEquals("incorrect data",true,expected.equals(graph));
  }

  @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");
  }
 
  /** Verifies the equivalence of a supplied graph to the supplied machine. */
  public static void checkM(DirectedSparseGraph g,String fsm,Configuration conf)
  {
    final LearnerGraph graph = new LearnerGraph(g,conf);
    final DirectedSparseGraph expectedGraph = buildGraph(fsm,"expected graph");
    final LearnerGraph expected = new LearnerGraph(expectedGraph,conf);
    WMethod.checkM(graph,expected);
  }
   
  @Test
  public void testCheckM1()
  {
    checkM(buildGraph("A-a->B-b->C", "testCheck1"), "B-a->C-b->D",config);
  }
 
  @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",config);
  }

  @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,config);
  }

  @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,config);
  }

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

  @Test
  public void testCheckM6()
  {
    final LearnerGraph graph = new LearnerGraph(buildGraph("A-a->B-b->B-a->C", "testCheck6"),config);
    final LearnerGraph expected = new LearnerGraph(buildGraph("U<-b-U\nQ<-a-U<-a-S","expected graph"),config);
    assertTrue(checkMBoolean(graph,expected,"A","S"));
    assertTrue(checkMBoolean(graph,expected,"B","U"));
    assertTrue(checkMBoolean(graph,expected,"C","Q"));
  }

  @Test
  public final void testCheckM_multipleEq1() // equivalent states
  {
    final LearnerGraph graph = new LearnerGraph(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"),config);
    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 LearnerGraph graph = new LearnerGraph(g,Configuration.getDefaultConfiguration());
    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 LearnerGraph graph = new LearnerGraph(g,Configuration.getDefaultConfiguration());
    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 LearnerGraph graph = new LearnerGraph(g,Configuration.getDefaultConfiguration());
    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(LearnerGraph graph, LearnerGraph expected, String stateGraph, String stateExpected)
  {
    try
    {
      WMethod.checkM(graph,expected,graph.findVertex(stateGraph),expected.findVertex(stateExpected));
    }
    catch(DifferentFSMException ex)
    {
      return false;
    }
    return true;
  }
 
  @Test
  public void testCheckM6_f1()
  {
    final LearnerGraph graph = new LearnerGraph(buildGraph("A-a->B-b->B-a->C", "testCheck6"), Configuration.getDefaultConfiguration());
    final LearnerGraph expected = new LearnerGraph(buildGraph("U<-b-U\nQ<-a-U<-a-S","expected graph"),Configuration.getDefaultConfiguration());
    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",config);   
  }

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

  @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",config);
  }

  @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",config);
  }

  @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",config);
  }

  @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",config);
  }

  @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,config);
  }

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

  /** Tests alphabet computation in the presence of unreachable states. */
  @Test
  public final void testComputeFSMAlphabet1()
  {
    Set<String> expected = new HashSet<String>();
    expected.add("p");
    DirectedSparseGraph g = buildGraph("A-p->A","testComputeFSMAlphabet1");
    Assert.assertEquals(expected, new LearnerGraph(g,config).wmethod.computeAlphabet());
    Assert.assertEquals(expected, DeterministicDirectedSparseGraph.computeAlphabet(g));
  }

  @Test
  public void testComputeFSMAlphabet2()
  {
    DirectedSparseGraph g = buildGraph("A-a->A<-b-A", "completeComputeAlphabet3");
    Collection<String> expected = new HashSet<String>();expected.addAll(Arrays.asList(new String[] {"a","b"}));
    Assert.assertEquals(expected, new LearnerGraph(g,config).wmethod.computeAlphabet());
    Assert.assertEquals(expected, DeterministicDirectedSparseGraph.computeAlphabet(g));       
  }
 
  /** Tests alphabet computation in the presence of unreachable states. */
  @Test
  public final void testComputeFSMAlphabet3()
  {
    Collection<String> expected = new HashSet<String>();expected.addAll(Arrays.asList(new String[]{"p","d","b","c","a"}));
    DirectedSparseGraph g = buildGraph("A-p->A-b->B-c->B-a-#C\nQ-d->S-c->S","testComputeFSMAlphabet3");
    Assert.assertEquals(expected, new LearnerGraph(g,config).wmethod.computeAlphabet());
    Assert.assertEquals(expected, DeterministicDirectedSparseGraph.computeAlphabet(g));       
  }


  @Test
  public final void testComputeFSMAlphabet4() {
    DirectedSparseGraph g = buildGraph("A-p->A-b->B-c->B-a->C\nQ-d->S-a-#T","testComputeFSMAlphabet4");
    Collection<String> expected = new HashSet<String>();expected.addAll(Arrays.asList(new String[]{"p","d","b","c","a"}));
    Assert.assertEquals(expected, new LearnerGraph(g,config).wmethod.computeAlphabet());
    Assert.assertEquals(expected, DeterministicDirectedSparseGraph.computeAlphabet(g));       
  }

  @Test
  public void completeComputeAlphabet5()
  {
    DirectedSparseGraph g = buildGraph("A-a->A-b->B-c->B-a->C\nQ-a->S\nA-c->A\nB-b->B\nC-a->C-b->C-c->C\nQ-b->Q-c->Q\nS-a->S-b->S-c->S", "completeComputeAlphabet5");
    Collection<String> expected = new HashSet<String>();expected.addAll(Arrays.asList(new String[] {"a","b","c"}));
    Assert.assertEquals(expected, new LearnerGraph(g,config).wmethod.computeAlphabet());
    Assert.assertEquals(expected, DeterministicDirectedSparseGraph.computeAlphabet(g));       

    LearnerGraph clone = new LearnerGraph(g,config).copy(config);
    Assert.assertFalse( clone.paths.completeGraph(
        new VertexID("REJECT")));
    Assert.assertFalse(DeterministicDirectedSparseGraph.completeGraph(g,"REJECT"));
  }
 
  /** Given a graph, this one calls completeGraph and checks that the returned value is whetherToBeCompleted
   * and that the final graph is equivalent to the one provided. Note that this also checks that in case
   * a graph does not need to be completed, the result of completion is the same graph.
   *
   * @param originalGraph the graph to complete
   * @param expectedOutcome the graph to be expected
   * @param whetherToBeCompleted whether graph "machine" is incomplete.
   * @param testName the name of the test to give to the above graph.
   */
  private void completeGraphTestHelper(String originalGraph, String expectedOutcome, boolean whetherToBeCompleted, String testName)
  {
    DirectedSparseGraph g = buildGraph(originalGraph, testName);
    Assert.assertEquals(whetherToBeCompleted,DeterministicDirectedSparseGraph.completeGraph(g,"REJECT"));checkM(g, expectedOutcome,config);   
    LearnerGraph fsm = new LearnerGraph(buildGraph(originalGraph, testName),config);
    Assert.assertEquals(whetherToBeCompleted,fsm.paths.completeGraph(
        new VertexID("REJECT")));
    WMethod.checkM(fsm, new LearnerGraph(buildGraph(expectedOutcome,testName),config));       
  }
 
  /** Checks that passing a name of an existing state causes an exception to be thrown. */
  @Test(expected=IllegalArgumentException.class)
  public void complete_fail()
  {
    new LearnerGraph(buildGraph("A-a->A-b->B-c->B", "complete_fail"),config).paths.completeGraph(
        new VertexID("B"));
  }
 
  @Test
  public void completeGraphTest1()
  {
    completeGraphTestHelper("A-a->A", "A-a->A",false,"completeGraphTest1");
  }
 
  @Test
  public void completeGraphTest2()
  {
    completeGraphTestHelper("A-a->B-a->A", "A-a->A", false, "completeGraphTest2");
  }
 
  @Test
  public void completeGraphTest3()
  {
    completeGraphTestHelper("A-a->A<-b-A", "A-b->A-a->A", false, "completeGraphTest3");
  }
 
  @Test
  public void completeGraphTest4a()
  {
    completeGraphTestHelper("A-a->B-b->A", "A-a->B-b->A\nA-b-#REJECT#-a-B", true, "completeGraphTest4a");
  }
 
  @Test
  public void completeGraphTest4b()
  {
    completeGraphTestHelper("A-a->B-b->A-b->A", "A-a->B-b->A-b->A\nREJECT#-a-B", true, "completeGraphTest4b");
  }

  @Test
  public void completeGraphTest5()
  {
    completeGraphTestHelper("A-a->A-b->B-c->B", "A-a->A-b->B-c->B\nA-c-#REJECT#-a-B-b-#REJECT", true, "completeGraphTest5");
 
 
  @Test
  public void completeGraphTest6()
  {
    completeGraphTestHelper("A-a->A-b->B-c->B-a->C", "A-a->A-b->B-c->B-a->C\nA-c-#REJECT#-b-B\nC-a-#REJECT\nC-b-#REJECT\nC-c-#REJECT", true, "completeGraphTest6");
 
 
  @Test
  public void completeGraphTest7()
  {
    String fsmOrig = "A-a->A-b->B-c->B-a->C\nQ-d->S",
      fsmExpected = "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";
    completeGraphTestHelper(fsmOrig,fsmExpected,true,"completeGraphTest7");
   
    // Additional checking.
    DirectedSparseGraph g = buildGraph(fsmOrig, "completeGraphTest7");
    final LearnerGraph graph = new LearnerGraph(g,config);
    Assert.assertTrue(graph.paths.completeGraph(
        new DeterministicDirectedSparseGraph.VertexID("REJECT")));
    final LearnerGraph expected = new LearnerGraph(buildGraph(fsmExpected,"completeGraphTest7"),config);
    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(expected = IllegalArgumentException.class)
  public void testFindVertex0()
  {
    DeterministicDirectedSparseGraph.findVertex(JUConstants.JUNKVERTEX, null, new DirectedSparseGraph());
  }

  @Test
  public void testFindVertex1()
  {
    Assert.assertNull(DeterministicDirectedSparseGraph.findVertex(JUConstants.JUNKVERTEX, "bb", new DirectedSparseGraph()));
  }
 
  @Test
  public void testFindVertex2()
  {
    DirectedSparseGraph g = buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex2");
    //Visualiser.updateFrame(g, g);Visualiser.waitForKey();
    Assert.assertNull(DeterministicDirectedSparseGraph.findVertex(JUConstants.JUNKVERTEX, "bb", g));
  }
   
  @Test
  public void testFindVertex3()
  {
    DirectedSparseGraph g = buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex3");
    //Visualiser.updateFrame(g, null);Visualiser.waitForKey();
    Assert.assertNull(DeterministicDirectedSparseGraph.findVertex(JUConstants.LABEL, "D", g));
  }

  @Test
  public void testFindVertex4a()
  {
    Vertex v = DeterministicDirectedSparseGraph.findVertex(JUConstants.INITIAL, "anything", buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex4a"));
    Assert.assertNull(v);
  }

  @Test
  public void testFindVertex4b()
  {
    Vertex v =  DeterministicDirectedSparseGraph.findVertex(JUConstants.INITIAL, true, buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindVertex4b"));
    Assert.assertEquals(new VertexID("A"), v.getUserDatum(JUConstants.LABEL));
  }

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

 
  @Test
  public void testFindInitial1()
  {
    Vertex v = DeterministicDirectedSparseGraph.findInitial(buildGraph("A-a->A-b->B-c->B-a->C\nQ-d->S", "testFindInitial"));
    Assert.assertEquals(new VertexID("A"), v.getUserDatum(JUConstants.LABEL));
  }
 
  @Test
  public void testFindInitial2()
  {
    Vertex v = DeterministicDirectedSparseGraph.findInitial(new DirectedSparseGraph());
    Assert.assertNull(v);
  }

  /** 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 map from an array, where each element corresponds to a pair of a string array
   * (representing a sequence) and a string (representing flags associated with this sequence).
   *
   * @param data source data
   * @return a string->string map
   */
  public static Map<String,String> buildStringMap(Object [][] data)
  {
    Map<String,String> result = new HashMap<String,String>();
    for(Object[] str:data)
    {
      if (str.length != 2)
        throw new IllegalArgumentException("more than two elements in sequence "+str);
      if (str[0] == null || str[1] == null || !(str[0] instanceof String[]) || !(str[1] instanceof String))
        throw new IllegalArgumentException("invalid data in array");// TODO: to test that this exception is thrown.
      result.put(ArrayOperations.seqToString(Arrays.asList((String[])str[0])),(String)str[1]);
    }
    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"} })));
  }

  @Test
  public void testBuildStringMap1()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
    })));
  }
 
  @Test
  public void testBuildStringMap2()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"a"},"value2"},
        new Object[]{new String[]{"b"},"value3"}
    })));
  }
 
  @Test
  public void testBuildStringMap3()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value2"},
        new Object[]{new String[]{"a"},"value1"},
        new Object[]{new String[]{"b"},"value3"}
    })));
  }
 
  @Test(expected = IllegalArgumentException.class)
  public void testBuildStringMap4()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value1"},
        new Object[]{new String[]{"a"}},// an invalid sequence
        new Object[]{new String[]{"b"},"value3"}
    })));
  }

  @Test(expected = IllegalArgumentException.class)
  public void testBuildStringMap5()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value1"},
        new Object[]{},// an invalid sequence - too few elements
        new Object[]{new String[]{"b"},"value3"}
    })));
  }

  @Test(expected = IllegalArgumentException.class)
  public void testBuildStringMap6()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value1"},
        new Object[]{new String[]{"a"},"c","d"},// an invalid sequence - too many elements
        new Object[]{new String[]{"b"},"value3"}
    })));
  }

  @Test(expected = IllegalArgumentException.class)
  public void testBuildStringMap7()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value1"},
        new Object[]{new Object(),"c"},// an invalid sequence - wrong type of the first element
        new Object[]{new String[]{"b"},"value3"}
    })));
  }

  @Test(expected = IllegalArgumentException.class)
  public void testBuildStringMap8()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value1"},
        new Object[]{"text","c"},// an invalid sequence - wrong type of the first element
        new Object[]{new String[]{"b"},"value3"}
    })));
  }

  @Test(expected = IllegalArgumentException.class)
  public void testBuildStringMap9()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value1"},
        new Object[]{new String[]{"a"},new Object()},// an invalid sequence - wrong type of the second element
        new Object[]{new String[]{"b"},"value3"}
    })));
  }

  @Test(expected = IllegalArgumentException.class)
  public void testBuildStringMap10()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value1"},
        new Object[]{new String[]{"a"},new Object()},// an invalid sequence - null in the first element
        new Object[]{new String[]{"b"},"value3"}
    })));
  }

  @Test(expected = IllegalArgumentException.class)
  public void testBuildStringMap11()
  {
    Map<String,String> expectedResult = new HashMap<String,String>();
    expectedResult.put("a","value1");expectedResult.put("strC","value2");expectedResult.put("b","value3");
   
    assertTrue(expectedResult.equals(buildStringMap(new Object[][]{
        new Object[]{new String[]{"strC"},"value1"},
        new Object[]{null, "a"},// an invalid sequence - null in the second element
        new Object[]{new String[]{"b"},null}
    })));
  }
 
  public final void checkForCorrectException(final int [][]tTable, final int []vFrom, String exceptionString)
  {
    try
    {
      LearnerGraph.convertTableToFSMStructure(tTable, vFrom, -,config);
      Assert.fail("Exception not thrown");
    }
    catch(IllegalArgumentException ex)
    {
      Assert.assertTrue(ex.getMessage().contains(exceptionString));
    }
  }
 
  /** Zero-sized array. */
  @Test
  public final void testConvertTableToFSMStructure0()
  {
    int [][]table = new int[][] {
    };
    checkForCorrectException(table, new int[0], "array is zero-sized");
  }

  /** Zero-sized alphabet. */
  @Test
  public final void testConvertTableToFSMStructure1a()
  {
    int [][]table = new int[][] {
      {},
      {1,1}
    };
    checkForCorrectException(table, new int[]{0,1}, "alphabet is zero-sized");
  }
 
  /** "rows of inconsistent size" */
  @Test
  public final void testConvertTableToFSMStructure1b()
  {
    int [][]table = new int[][] {
      {},
      {1,1}
    };
    checkForCorrectException(table, new int[]{1,0}, "rows of inconsistent size");
  }
 
  /** "rows of inconsistent size" */
  @Test
  public final void testConvertTableToFSMStructure2()
  {
    int [][]table = new int[][] {
        {1,0,1,0},
        {0,1}
      };
    checkForCorrectException(table, new int[]{0,1}, "rows of inconsistent size");
  }
 
  /** Reject number in vfrom. */
  @Test
  public final void testConvertTableToFSMStructure3()
  {
    int [][]table = new int[][] {
        {1,0,1,0},
        {0,1,0,1}
      };
    checkForCorrectException(table, new int[]{0,-1}, "reject number in vFrom");
  }
 
  /** Transition to illegal state 6 */
  @Test
  public final void testConvertTableToFSMStructure4a()
  {
    int [][]table = new int[][] {
      {01,  -12},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    checkForCorrectException(table, new int[]{0,1,2,3}, "leads to an invalid state");
  }
 
  /** Transition to illegal state -4 */
  @Test
  public final void testConvertTableToFSMStructure4b()
  {
    int [][]table = new int[][] {
      {01,  -12},
      {0, 30,  -1},
      {0,0,0,-4},
      {-1,-1,-1,-1}
    };
    checkForCorrectException(table, new int[]{0,1,2,3}, "leads to an invalid state");
  }

  @Test
  public final void testConvertTableToFSMStructure_missing_elements_in_vFrom()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    checkForCorrectException(table, new int[]{0,1}, "Some states in the transition table are not included in vFrom");
  }

  @Test
  public final void testConvertTableToFSMStructure5()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    LearnerGraph fsm = LearnerGraph.convertTableToFSMStructure(table, new int[]{0,1,3}, -,config);
    WMethod.checkM(fsm, new LearnerGraph(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0", "testConvertTableToFSMStructure5"),config), fsm.findVertex("S0"), fsm.findVertex("S0"));
  }
 
  @Test
  public final void testConvertTableToFSMStructure6()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    LearnerGraph fsm = LearnerGraph.convertTableToFSMStructure(table, new int[]{1,0,3}, -,config);
    WMethod.checkM(fsm, new LearnerGraph(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0", "testConvertTableToFSMStructure6"),config), fsm.findVertex("S0"), fsm.findVertex("S0"));
  }

  @Test
  public final void testConvertTableToFSMStructure7()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    LearnerGraph fsm = LearnerGraph.convertTableToFSMStructure(table, new int[]{3,0,1}, -,config);
    WMethod.checkM(fsm, new LearnerGraph(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0", "testConvertTableToFSMStructure7"),config), fsm.findVertex("S0"), fsm.findVertex("S0"));
  }
 
  @Test
  public final void testConvertTableToFSMStructure8()
  {
    int [][]table = new int[][] {
      {01,  -13},
      {0, 30,  -1},
      {0,0,0,6},
      {-1,-1,-1,-1}
    };
    LearnerGraph fsm = LearnerGraph.convertTableToFSMStructure(table, new int[]{3,0,1,0,1,1}, -,config);
    WMethod.checkM(fsm, new LearnerGraph(buildGraph("S0-i0->S0-i1->S1\nS0-i3->S2\nS1-i0->S0\nS1-i1->S3\nS1-i2->S0", "testConvertTableToFSMStructure8"),config), fsm.findVertex("S0"), fsm.findVertex("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 testGetNonRepeatingNumbers3()
  {
    final int size = 200;
    int data[] = DeterministicDirectedSparseGraph.getNonRepeatingNumbers(size, 1);
    Assert.assertEquals(size,data.length);
    boolean values[] = new boolean[size];
    for(int i=0;i<size;++i) { Assert.assertFalse(values[data[i]]);values[data[i]]=true; }
    //System.out.println(Arrays.toString(data));
  }
 
  @Test
  public final void assertsEnabled()
  {
    boolean assertsOn = false;
    assert assertsOn = true;
   
    Assert.assertTrue("asserts have to be enabled", assertsOn);
  }
   
  @BeforeClass
  public static void initJungViewer() // initialisation - once only for all tests in this class
  {   
    Visualiser.disposeFrame();
  }

  @AfterClass
  public static void cleanUp()
  {
    Visualiser.disposeFrame();
  }
}
TOP

Related Classes of statechum.analysis.learning.MethodAndArgs

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.