/** * Updates the state of the watcher, given reception of a new message. * * @param m * The message that was received. */ private void update(WatcherMessage m) { WatcherNode wn2; HashSet<WatcherNode> spawnedNodes; HashSet<WatcherNode> newNodes = new HashSet<WatcherNode>(); int size = 0, atoms = 0; foreach (WatcherNode wn in m_nodes) { wn2 = new WatcherNode(); wn2.setGamma(wn.getDelta()); spawnedNodes = wn2.spawn(m); foreach (WatcherNode wn3 in spawnedNodes) { newNodes.Add(wn3); } } m_nodes = newNodes; // Updates statistics about maximum number of nodes size = m_nodes.Count; if (size > m_maxNodes) { m_maxNodes = size; } // Updates statistics about total number of formulae size = 0; atoms = 0; foreach (WatcherNode wn in m_nodes) { size += wn.getSize(); atoms += wn.getAtoms(); } if (size > m_maxFormulae) { m_maxFormulae = size; } if (atoms > m_maxAtoms) { m_maxAtoms = atoms; } }
/** * Determines the value of an LTL-FO+ formula using a 3-valued logic. In * addition to TRUE and FALSE, we add a third value "?". The following rules * apply: * <ul> * <li>¬ ? = ?</li> * <li>TRUE ∧ ? = ?</li> * <li>FALSE ∧ ? = FALSE</li> * <li>TRUE ∨ ? = TRUE</li> * <li>FALSE ∨ ? = ?</li> * <li>X φ = G φ = ? no matter φ</li> * <li>F φ = φ ∨ ?</li> * <li>φ U ψ = ψ ∨ ?</li> * <li>∃<sub>p</sub> x: φ = φ(x<sub>1</sub>) ∨ ... ∨ * φ(x<sub>n</sub>) for x<sub>i</sub> in Dom<sub>s</sub>(p)</li> * <li>∀<sub>p</sub> x: φ = φ(x<sub>1</sub>) ∧ ... ∧ * φ(x<sub>n</sub>) for x<sub>i</sub> in Dom<sub>s</sub>(p)</li> * * @param o * @param m * TODO * @return */ protected static Outcome isSatisfiedInCurrentState(Operator o, WatcherMessage m) { // This method uses getClass to branch on the type of operator // used; TODO: redesign with method overriding Outcome oc1, oc2; Operator o1, o2, o3; if (o.GetType() == typeof(OperatorNot)) { o1 = ((OperatorNot)o).getOperand(); oc1 = isSatisfiedInCurrentState(o1, m); return threeValuedNot(oc1); } else if (o.GetType() == typeof(OperatorX) || o.GetType() == typeof(OperatorG)) { // TODO // assert(false); return Outcome.INCONCLUSIVE; } else if (o.GetType() == typeof(OperatorEquals)) { o1 = ((OperatorEquals)o).getLeftOperand(); o2 = ((OperatorEquals)o).getRightOperand(); if (o1.GetType () == typeof(ConstantPath)) { // Left member is a path; we compare that path // to the right member HashSet<Atom> dom = m.getDomain((ConstantPath) o1); foreach (Atom a in dom) { // We return true if at least one value at the end // of the path equals o2 if (a.Equals(o2)) return Outcome.TRUE; } return Outcome.FALSE; } else { // We compare directly the two members if (o1.Equals(o2)) return Outcome.TRUE; } return Outcome.FALSE; } else if (o.GetType() == typeof(OperatorAnd)) { o1 = ((OperatorAnd)o).getLeftOperand(); oc1 = isSatisfiedInCurrentState(o1, m); o2 = ((OperatorAnd)o).getRightOperand(); oc2 = isSatisfiedInCurrentState(o2, m); return threeValuedAnd(oc1, oc2); } else if (o.GetType() == typeof(OperatorOr)) { o1 = ((OperatorOr)o).getLeftOperand(); oc1 = isSatisfiedInCurrentState(o1, m); o2 = ((OperatorOr)o).getRightOperand(); oc2 = isSatisfiedInCurrentState(o2, m); return threeValuedOr(oc1, oc2); } else if (o.GetType() == typeof(OperatorF)) { o1 = ((OperatorF)o).getOperand(); oc1 = isSatisfiedInCurrentState(o1, m); return threeValuedOr(oc1, Outcome.INCONCLUSIVE); } else if (o.GetType() == typeof(OperatorImplies)) { o1 = ((OperatorImplies)o).getLeftOperand(); oc1 = isSatisfiedInCurrentState(o1, m); o2 = ((OperatorImplies)o).getRightOperand(); oc2 = isSatisfiedInCurrentState(o2, m); return threeValuedOr(threeValuedNot(oc1), oc2); } else if (o.GetType() == typeof(OperatorU)) { o1 = ((OperatorU)o).getLeftOperand(); oc1 = isSatisfiedInCurrentState(o1, m); o2 = ((OperatorU)o).getRightOperand(); oc2 = isSatisfiedInCurrentState(o2, m); return threeValuedOr(oc1, threeValuedAnd(oc1, Outcome.INCONCLUSIVE)); } else if (o.GetType() == typeof(OperatorV)) { o1 = ((OperatorV)o).getLeftOperand(); oc1 = isSatisfiedInCurrentState(o1, m); o2 = ((OperatorV)o).getRightOperand(); oc2 = isSatisfiedInCurrentState(o2, m); return threeValuedAnd(oc1, threeValuedOr(oc2, Outcome.INCONCLUSIVE)); } else if (o.GetType() == typeof(FOExists)) { // Iterate over domain // TODO: supposes that the string qualifier is an atom Atom p = new Atom(((FOExists)o).getQualifier()); Atom x = ((FOExists)o).getQuantifiedVariable(); HashSet<Atom> s = m.getDomain(p); oc1 = Outcome.FALSE; foreach (Atom a in s) { o2 = ((FOExists)o).getOperand(); o3 = o2.evaluate(x, a); oc2 = isSatisfiedInCurrentState(o3, m); oc1 = threeValuedOr(oc1, oc2); } return oc1; } else if (o.GetType() == typeof(FOForAll)) { // Iterate over domain // TODO: supposes that the string qualifier is an atom Atom p = new Atom(((FOForAll)o).getQualifier()); Atom x = ((FOForAll)o).getQuantifiedVariable(); HashSet<Atom> s = m.getDomain(p); oc1 = Outcome.TRUE; foreach (Atom a in s) { o2 = ((FOForAll)o).getOperand(); o3 = o2.evaluate(x, a); oc2 = isSatisfiedInCurrentState(o3, m); oc1 = threeValuedAnd(oc1, oc2); } return oc1; } else if (o.GetType() == typeof(Constant)) { // TODO: true and false are checked by comparing their // string representations; there should be a more graceful // way to check for true and false if (((Constant)o).getSymbol() == Operator.m_trueAtom.getSymbol()) { return Outcome.TRUE; } else if (((Constant)o).getSymbol() == Operator.m_falseAtom.getSymbol()) { return Outcome.FALSE; } return Outcome.INCONCLUSIVE; } return Outcome.INCONCLUSIVE; }
/** * Updates the state of the watcher, given reception of a new message in a * stringified, XML-ised form. * * @param s * A String containing the XML snippet corresponding to the message. * For the format of XML supported by the method, see {@link * WatcherMessage(String)}. */ public override void update(string s) { WatcherMessage m = new WatcherMessage(s); // Prepends the default message name to the queried paths //m.setPrependPath("/" + m_messageName + "/"); update(m); }
/** * Decomposes a watcher's node, given a received message. * * @param m * The message on which to make the decomposition * @return A Set of WatcherNodes consisting of the resulting decomposition * for that node. If the left-hand side of the node is empty, * returns an empty set. */ public HashSet<WatcherNode> spawn(WatcherMessage m) { // This method uses getClass to branch on the type of operator // used; TODO: redesign with method overriding HashSet<WatcherNode> spawnedSet, outSet = new HashSet<WatcherNode>(); WatcherNode wn; Operator o2, o3; // Picks a formula and removes it from Gamma foreach (Operator o in m_gamma) { m_gamma.Remove(o); // Optimization from original algorithm: if formula can readily // be decided in current state, bypass decomposition Outcome oc = isSatisfiedInCurrentState(o, m); if (oc == Outcome.TRUE) { // Formula is true: stop decomposition of this formula and // continue spawning return spawn(m); } else if (oc == Outcome.FALSE) { // Formula is false: stop branch and return empty set return outSet; } // Operator OR else if (o.GetType() == typeof(OperatorOr)) { // Do for left operand wn = new WatcherNode(this); o2 = ((OperatorOr)o).getLeftOperand(); wn.addToGamma(o2); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } // Do for right operand wn = new WatcherNode(this); o2 = ((OperatorOr)o).getRightOperand(); wn.addToGamma(o2); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator IMPLIES else if (o.GetType() == typeof(OperatorImplies)) { // Do for right operand wn = new WatcherNode(this); o2 = ((OperatorImplies)o).getRightOperand(); wn.addToGamma(o2); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } // Do for right operand wn = new WatcherNode(this); o2 = ((OperatorImplies)o).getLeftOperand().getNegated(); wn.addToGamma(o2.getNegatedNormalForm()); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator AND else if (o.GetType() == typeof(OperatorAnd)) { // Do for left operand wn = new WatcherNode(this); o2 = ((OperatorAnd)o).getLeftOperand(); wn.addToGamma(o2); // Do for left operand o2 = ((OperatorAnd)o).getRightOperand(); wn.addToGamma(o2); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator X else if (o.GetType() == typeof(OperatorX)) { wn = new WatcherNode(this); o2 = ((OperatorX)o).getOperand(); wn.addToDelta(o2); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator G else if (o.GetType() == typeof(OperatorG)) { // Do for left operand wn = new WatcherNode(this); o2 = ((OperatorG)o).getOperand(); wn.addToGamma(o2); wn.addToDelta(o); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator F else if (o.GetType() == typeof(OperatorF)) { // Do for left node wn = new WatcherNode(this); o2 = ((OperatorF)o).getOperand(); wn.addToGamma(o2); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } // Do for right node wn = new WatcherNode(this); wn.addToDelta(o); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator U else if (o.GetType() == typeof(OperatorU)) { // Do for left node wn = new WatcherNode(this); o2 = ((OperatorU)o).getRightOperand(); wn.addToGamma(o2); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } // Do for right node wn = new WatcherNode(this); wn.addToDelta(o); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator V else if (o.GetType() == typeof(OperatorV)) { // Do for left node wn = new WatcherNode(this); o2 = ((OperatorV)o).getLeftOperand(); wn.addToGamma(o2); o2 = ((OperatorV)o).getRightOperand(); wn.addToGamma(o2); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } // Do for right node wn = new WatcherNode(this); o2 = ((OperatorV)o).getRightOperand(); wn.addToGamma(o2); wn.addToDelta(o); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator [p=x] else if (o.GetType() == typeof(FOForAll)) { // Iterate over domain wn = new WatcherNode(this); // TODO: supposes that the string qualifier is an atom Atom p = new Atom(((FOForAll)o).getQualifier()); Atom x = ((FOForAll)o).getQuantifiedVariable(); HashSet<Atom> s = m.getDomain(p); foreach (Atom v in s) { o2 = ((FOForAll)o).getOperand(); o3 = o2.evaluate(x, v); wn.addToGamma(o3); } spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } // Operator <p=x> else if (o.GetType() == typeof(FOExists)) { // Iterate over domain // TODO: supposes that the string qualifier is an atom Atom p = new Atom(((FOExists)o).getQualifier()); Atom x = ((FOExists)o).getQuantifiedVariable(); HashSet<Atom> s = m.getDomain(p); foreach (Atom v in s) { wn = new WatcherNode(this); o2 = ((FOExists)o).getOperand(); o3 = o2.evaluate(x, v); wn.addToGamma(o3); spawnedSet = wn.spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } } // TODO (Dominic): Validate this ? return outSet; } // Operator = else if (o.GetType() == typeof(OperatorEquals)) { // This should never happen! When down to the evaluation // of an equality, all variables should be evaluated! //assert(false); return outSet; } // Operator NOT else if (o.GetType() == typeof(OperatorNot)) { // Do for operand wn = new WatcherNode(this); o2 = ((OperatorNot)o).getOperand(); if (o2.GetType() != typeof(Constant)) { // This should not happen! Negations should be pushed // to atoms //assert(false); return outSet; } // TODO: true and false are checked by comparing their // string representations; there should be a more graceful // way // to check for true and false if (((Constant)o).getSymbol() == Operator.m_trueAtom.getSymbol()) { // Constant TRUE, i.e. evaluates to FALSE: this branch // does not return anything // i.e. do nothing } else if (((Constant)o).getSymbol() == Operator.m_falseAtom.getSymbol()) { // Constant FALSE, i.e. evaluates to TRUE: just pass on // the recursive evaluation spawnedSet = spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } return outSet; } else { // This should never happen! All atoms should evaluate // down // to either true or false. System.Diagnostics.Debug.Assert (false, "Unrecognized operator in watcher node"); return outSet; } } // Constants (true or false) else if (o.GetType() == typeof(Constant)) { // TODO: true and false are checked by comparing their // string representations; there should be a more graceful // way // to check for true and false if (((Constant)o).getSymbol() == Operator.m_trueAtom.getSymbol()) { // Constant TRUE: just pass on the recursive evaluation spawnedSet = spawn(m); foreach (WatcherNode wn2 in spawnedSet) { outSet.Add(wn2); } } else if (((Constant)o).getSymbol() == Operator.m_falseAtom.getSymbol()) { // This branch is stopped: this branch does not return // anything // i.e. do nothing return outSet; } else { // This should never happen! All atoms should evaluate // down to either true or false. //assert(false); return outSet; } } } if (m_gamma.Count == 0) { // Gamma is empty: return a set with myself outSet.Add(this); } return outSet; }