/**
   * Writes the supplied learner evaluation configuration.
   *
   * @param cnf configuration to write
   * @return the recorded XML element
   */
  public Element writeLearnerEvaluationConfiguration(LearnerEvaluationConfiguration cnf) {
    Element evaluationData = doc.createElement(StatechumXML.ELEM_EVALUATIONDATA.name());
    evaluationData.appendChild(cnf.graph.storage.createGraphMLNode(doc));

    Element sequenceListElement =
        labelio.writeSequenceList(StatechumXML.ATTR_TESTSET.name(), cnf.testSet);
    evaluationData.appendChild(AbstractPersistence.endl(doc));
    evaluationData.appendChild(sequenceListElement);
    evaluationData.appendChild(AbstractPersistence.endl(doc));
    evaluationData.appendChild(cnf.config.writeXML(doc));
    evaluationData.appendChild(AbstractPersistence.endl(doc));
    if (cnf.ifthenSequences != null) {
      Element ltl = doc.createElement(StatechumXML.ELEM_CONSTRAINTS.name());
      StringBuffer ltlsequences = new StringBuffer();
      stringio.writeInputSequence(ltlsequences, cnf.ifthenSequences);
      ltl.setTextContent(ltlsequences.toString());
      evaluationData.appendChild(ltl);
      evaluationData.appendChild(AbstractPersistence.endl(doc));
    }
    if (cnf.labelDetails != null) {
      evaluationData.appendChild(cnf.labelDetails.storeToXML(doc, stringio));
      evaluationData.appendChild(AbstractPersistence.endl(doc));
    }
    if (cnf.graphNumber >= 0) {
      Element progressIndicatorElement =
          doc.createElement(StatechumXML.ELEM_PROGRESSINDICATOR.name());
      progressIndicatorElement.setAttribute(
          StatechumXML.ATTR_GRAPHNUMBER.name(), Integer.toString(cnf.graphNumber));
      evaluationData.appendChild(progressIndicatorElement);
    }
    return evaluationData;
  }
  /**
   * Loads the initial data from the supplied XML element.
   *
   * @param elem where to load from
   * @return initial data
   */
  public InitialData readInitialData(Element elem) {
    if (!elem.getNodeName().equals(StatechumXML.ELEM_INIT.name()))
      throw new IllegalArgumentException(
          "expecting to load learner initial data " + elem.getNodeName());
    NodeList children = elem.getChildNodes();
    InitialData result = new InitialData();
    for (int i = 0; i < children.getLength(); ++i)
      if (children.item(i).getNodeType() == Node.ELEMENT_NODE) {
        Element e = (Element) children.item(i);
        if (e.getNodeName().equals(StatechumXML.graphmlNodeNameNS.toString())) {
          if (result.graph != null) throw new IllegalArgumentException("duplicate graph element");
          result.graph = new LearnerGraph(config);
          AbstractPersistence.loadGraph(e, result.graph, decoratedLearner.getLabelConverter());
        } else if (e.getNodeName().equals(StatechumXML.ELEM_SEQ.name())) {
          String sequenceName = e.getAttribute(StatechumXML.ATTR_SEQ.name());
          if (sequenceName.equals(StatechumXML.ATTR_POSITIVE_SEQUENCES.name())) {
            if (result.plus != null)
              throw new IllegalArgumentException("duplicate positive element");
            result.plus = labelio.readSequenceList(e, StatechumXML.ATTR_POSITIVE_SEQUENCES.name());
            if (!e.hasAttribute(StatechumXML.ATTR_POSITIVE_SIZE.name()))
              throw new IllegalArgumentException("missing positive size");
            String size = e.getAttribute(StatechumXML.ATTR_POSITIVE_SIZE.name());
            try {
              result.plusSize = Integer.valueOf(size);
            } catch (NumberFormatException ex) {
              statechum.Helper.throwUnchecked("positive value is not an integer " + size, ex);
            }
          } else if (sequenceName.equals(StatechumXML.ATTR_NEGATIVE_SEQUENCES.name())) {
            if (result.minus != null)
              throw new IllegalArgumentException("duplicate negative element");
            result.minus = labelio.readSequenceList(e, StatechumXML.ATTR_NEGATIVE_SEQUENCES.name());
            if (!e.hasAttribute(StatechumXML.ATTR_NEGATIVE_SIZE.name()))
              throw new IllegalArgumentException("missing negative size");
            String size = e.getAttribute(StatechumXML.ATTR_NEGATIVE_SIZE.name());
            try {
              result.minusSize = Integer.valueOf(size);
            } catch (NumberFormatException ex) {
              statechum.Helper.throwUnchecked("negative value is not an integer " + size, ex);
            }
          } else
            throw new IllegalArgumentException("unexpected kind of sequences: " + sequenceName);
        } else throw new IllegalArgumentException("unexpected element " + e.getNodeName());
      }

    if (result.graph == null) throw new IllegalArgumentException("missing graph");
    if (result.plus == null) throw new IllegalArgumentException("missing positive sequences");
    if (result.minus == null) throw new IllegalArgumentException("missing negative sequences");

    return result;
  }
 /**
  * This method stores all the details of initialisation of a learner.
  *
  * @param initialData data to store
  * @return the constructed XML element
  */
 protected Element writeInitialData(InitialData initialData) {
   Element elemInit = doc.createElement(StatechumXML.ELEM_INIT.name());
   Element positive =
       labelio.writeSequenceList(StatechumXML.ATTR_POSITIVE_SEQUENCES.name(), initialData.plus);
   positive.setAttribute(
       StatechumXML.ATTR_POSITIVE_SIZE.name(), Integer.toString(initialData.plusSize));
   Element negative =
       labelio.writeSequenceList(StatechumXML.ATTR_NEGATIVE_SEQUENCES.name(), initialData.minus);
   negative.setAttribute(
       StatechumXML.ATTR_NEGATIVE_SIZE.name(), Integer.toString(initialData.minusSize));
   elemInit.appendChild(initialData.graph.storage.createGraphMLNode(doc));
   elemInit.appendChild(AbstractPersistence.endl(doc));
   elemInit.appendChild(positive);
   elemInit.appendChild(AbstractPersistence.endl(doc));
   elemInit.appendChild(negative);
   elemInit.appendChild(AbstractPersistence.endl(doc));
   return elemInit;
 }
 /**
  * Writes a request to AugmentPTA into an XML node and returns the constructed node.
  *
  * @param data what to write
  * @return constructed XML node.
  */
 protected Element writeAugmentPTA(AugmentPTAData data) {
   Element result = doc.createElement(StatechumXML.ELEM_AUGMENTPTA.name());
   result.setAttribute(StatechumXML.ATTR_KIND.name(), data.kind.name());
   if (data.colour != null)
     result.setAttribute(StatechumXML.ATTR_COLOUR.name(), data.colour.name());
   result.setAttribute(StatechumXML.ATTR_ACCEPT.name(), Boolean.toString(data.accept));
   StringBuffer writer = new StringBuffer();
   labelio.writeInputSequence(writer, data.sequence);
   result.setTextContent(writer.toString());
   return result;
 }
  /**
   * Reads the arguments to AugmentPTA from XML element.
   *
   * <p>At the moment, storage of instances of leaf nodes in trees is not implemented (and leaf
   * nodes are used in filtering), hence I have to rely on storage of the whole set of sequences.
   *
   * @param element data to load from
   * @return constructed arguments.
   */
  protected AugmentPTAData readAugmentPTA(Element element) {
    if (!element.getNodeName().equals(StatechumXML.ELEM_AUGMENTPTA.name()))
      throw new IllegalArgumentException(
          "cannot load augmentPTA data from " + element.getNodeName());
    AugmentPTAData result = new AugmentPTAData();
    if (!element.hasAttribute(StatechumXML.ATTR_ACCEPT.name()))
      throw new IllegalArgumentException("missing accept");
    if (!element.hasAttribute(StatechumXML.ATTR_KIND.name()))
      throw new IllegalArgumentException("missing kind");

    String accept = element.getAttribute(StatechumXML.ATTR_ACCEPT.name()),
        colour = element.getAttribute(StatechumXML.ATTR_COLOUR.name()),
        kind = element.getAttribute(StatechumXML.ATTR_KIND.name()),
        sequence = element.getTextContent();
    if (sequence.length() == 0) throw new IllegalArgumentException("missing sequence");
    result.sequence = labelio.readInputSequence(sequence);
    result.accept = Boolean.valueOf(accept);
    if (colour.length() > 0) result.colour = Enum.valueOf(JUConstants.class, colour);
    result.kind = Enum.valueOf(RestartLearningEnum.class, kind);
    return result;
  }
  /**
   * Data need to construct an experiment and evaluate the results. This is not a part of
   * <em>AbstractExperiment</em> because this is only for testing and hence one would only want to
   * record data from <b>some</b> experiments, not all of them.
   *
   * <p>If possible, this also loads the configuration and uses it for all methods requiring a
   * configuration. Unexpected elements are ignored.
   *
   * <p>{@link LearnerEvaluationConfiguration#labelConverter} is not assigned since it is a function
   * that is supposed to be set globally for an entire experiment.
   */
  public LearnerEvaluationConfiguration readLearnerEvaluationConfiguration(
      Element evaluationDataElement, Configuration defaultConfig) {
    if (!evaluationDataElement.getNodeName().equals(StatechumXML.ELEM_EVALUATIONDATA.name()))
      throw new IllegalArgumentException(
          "expecting to load learner evaluation data but found "
              + evaluationDataElement.getNodeName());
    NodeList
        nodesGraph =
            StatechumXML.getChildWithTag(
                evaluationDataElement, StatechumXML.graphmlNodeNameNS.toString()),
        nodesSequences =
            StatechumXML.getChildWithTag(evaluationDataElement, StatechumXML.ELEM_SEQ.name()),
        nodesLtl =
            StatechumXML.getChildWithTag(
                evaluationDataElement, StatechumXML.ELEM_CONSTRAINTS.name()),
        nodesConfigurations =
            StatechumXML.getChildWithTag(evaluationDataElement, Configuration.configXMLTag),
        graphNumberNodes =
            StatechumXML.getChildWithTag(
                evaluationDataElement, StatechumXML.ELEM_PROGRESSINDICATOR.name()),
        nodesLabelDetails =
            StatechumXML.getChildWithTag(
                evaluationDataElement, StatechumXML.ELEM_LABELDETAILS.name());
    if (nodesGraph.getLength() < 1) throw new IllegalArgumentException("missing graph");
    if (nodesGraph.getLength() > 1) throw new IllegalArgumentException("duplicate graph");
    if (nodesSequences.getLength() < 1) throw new IllegalArgumentException("missing test set");
    if (nodesSequences.getLength() > 1) throw new IllegalArgumentException("duplicate test set");
    if (nodesLtl.getLength() > 1) throw new IllegalArgumentException("duplicate ltl sets");
    if (nodesConfigurations.getLength() > 1)
      throw new IllegalArgumentException("duplicate configuration");
    if (nodesLabelDetails.getLength() > 1)
      throw new IllegalArgumentException("duplicate label details");
    int graphNumber = -1;
    if (graphNumberNodes.getLength() > 1)
      try {
        graphNumber =
            Integer.parseInt(
                ((Element) graphNumberNodes.item(0))
                    .getAttribute(StatechumXML.ATTR_GRAPHNUMBER.name()));
      } catch (Exception e) { // ignore - graphNumber is unchanged.
      }

    LearnerEvaluationConfiguration result = new LearnerEvaluationConfiguration(defaultConfig);
    if (nodesConfigurations.getLength() > 0) result.config.readXML(nodesConfigurations.item(0));

    initIO(evaluationDataElement.getOwnerDocument(), result.config);

    result.graph = new LearnerGraph(result.config);
    AbstractPersistence.loadGraph(
        (Element) nodesGraph.item(0), result.graph, decoratedLearner.getLabelConverter());

    result.testSet =
        labelio.readSequenceList(
            (Element) nodesSequences.item(0), StatechumXML.ATTR_TESTSET.name());
    if (nodesLtl.getLength() > 0)
      result.ifthenSequences = stringio.readInputSequence(nodesLtl.item(0).getTextContent());
    if (nodesLabelDetails.getLength() > 0) {
      result.labelDetails = new SmtLabelRepresentation(result.config, getLabelConverter());
      result.labelDetails.loadXML((Element) nodesLabelDetails.item(0), stringio);
    }
    result.graphNumber = graphNumber;
    return result;
  }