/**
   * Perform a query.
   *
   * @param line The query.
   * @return The probability.
   */
  public double performQuery(String line) {
    if (this.query == null) {
      throw new BayesianError("This Bayesian network does not have a query to define.");
    }

    ParseProbability parse = new ParseProbability(this);
    ParsedProbability parsedProbability = parse.parse(line);

    // create a temp query
    BayesianQuery q = this.query.clone();

    // first, mark all events as hidden
    q.reset();

    // deal with evidence (input)
    for (ParsedEvent parsedEvent : parsedProbability.getGivenEvents()) {
      BayesianEvent event = this.requireEvent(parsedEvent.getLabel());
      q.defineEventType(event, EventType.Evidence);
      q.setEventValue(event, parsedEvent.resolveValue(event));
    }

    // deal with outcome (output)
    for (ParsedEvent parsedEvent : parsedProbability.getBaseEvents()) {
      BayesianEvent event = requireEvent(parsedEvent.getLabel());
      q.defineEventType(event, EventType.Outcome);
      q.setEventValue(event, parsedEvent.resolveValue(event));
    }

    q.locateEventTypes();

    q.execute();
    return q.getProbability();
  }
  /**
   * Define a classification structure of the form P(A|B) = P(C)
   *
   * @param line
   */
  public void defineClassificationStructure(String line) {
    List<ParsedProbability> list = ParseProbability.parseProbabilityList(this, line);

    if (list.size() > 1) {
      throw new BayesianError("Must only define a single probability, not a chain.");
    }

    if (list.size() == 0) {
      throw new BayesianError("Must define at least one probability.");
    }

    // first define everything to be hidden
    for (BayesianEvent event : this.events) {
      this.query.defineEventType(event, EventType.Hidden);
    }

    // define the base event
    ParsedProbability prob = list.get(0);

    if (prob.getBaseEvents().size() == 0) {
      return;
    }

    BayesianEvent be = this.getEvent(prob.getChildEvent().getLabel());
    this.classificationTarget = this.events.indexOf(be);
    this.query.defineEventType(be, EventType.Outcome);

    // define the given events
    for (ParsedEvent parsedGiven : prob.getGivenEvents()) {
      BayesianEvent given = this.getEvent(parsedGiven.getLabel());
      this.query.defineEventType(given, EventType.Evidence);
    }

    this.query.locateEventTypes();

    // set the values
    for (ParsedEvent parsedGiven : prob.getGivenEvents()) {
      BayesianEvent event = this.getEvent(parsedGiven.getLabel());
      this.query.setEventValue(event, parseInt(parsedGiven.getValue()));
    }

    this.query.setEventValue(be, parseInt(prob.getBaseEvents().get(0).getValue()));
  }
 /**
  * Define the probability for an event.
  *
  * @param line The event.
  * @param probability The probability.
  */
 public void defineProbability(String line, double probability) {
   ParseProbability parse = new ParseProbability(this);
   ParsedProbability parsedProbability = parse.parse(line);
   parsedProbability.defineTruthTable(this, probability);
 }
 /**
  * Define a relationship.
  *
  * @param line The relationship to define.
  */
 public void defineRelationship(String line) {
   ParseProbability parse = new ParseProbability(this);
   ParsedProbability parsedProbability = parse.parse(line);
   parsedProbability.defineRelationships(this);
 }
  /**
   * Define the structure of the Bayesian network as a string.
   *
   * @param line The string to define events and relations.
   */
  public void setContents(String line) {
    List<ParsedProbability> list = ParseProbability.parseProbabilityList(this, line);
    List<String> labelList = new ArrayList<String>();

    // ensure that all events are there
    for (ParsedProbability prob : list) {
      ParsedEvent parsedEvent = prob.getChildEvent();
      String eventLabel = parsedEvent.getLabel();
      labelList.add(eventLabel);

      // create event, if not already here
      BayesianEvent e = getEvent(eventLabel);
      if (e == null) {
        List<BayesianChoice> cl = new ArrayList<BayesianChoice>();

        for (ParsedChoice c : parsedEvent.getList()) {
          cl.add(new BayesianChoice(c.getLabel(), c.getMin(), c.getMax()));
        }

        createEvent(eventLabel, cl);
      }
    }

    // now remove all events that were not covered
    for (int i = 0; i < events.size(); i++) {
      BayesianEvent event = this.events.get(i);
      if (!labelList.contains(event.getLabel())) {
        removeEvent(event);
      }
    }

    // handle dependencies
    for (ParsedProbability prob : list) {
      ParsedEvent parsedEvent = prob.getChildEvent();
      String eventLabel = parsedEvent.getLabel();

      BayesianEvent event = requireEvent(eventLabel);

      // ensure that all "givens" are present
      List<String> givenList = new ArrayList<String>();
      for (ParsedEvent given : prob.getGivenEvents()) {
        if (!event.hasGiven(given.getLabel())) {
          BayesianEvent givenEvent = requireEvent(given.getLabel());
          this.createDependency(givenEvent, event);
        }
        givenList.add(given.getLabel());
      }

      // now remove givens that were not covered
      for (int i = 0; i < event.getParents().size(); i++) {
        BayesianEvent event2 = event.getParents().get(i);
        if (!givenList.contains(event2.getLabel())) {
          removeDependency(event2, event);
        }
      }
    }

    // finalize the structure
    finalizeStructure();
    if (this.query != null) {
      this.query.finalizeStructure();
    }
  }