public static void Main(string[] args) { Atom x2 = new Atom("x2"); Atom x1 = new Atom("x1"); OperatorEquals f1 = new OperatorEquals(x2, new Constant("ElephantUpgrade")); OperatorNot f2 = new OperatorNot(); f2.setOperand(f1); FOForAll fo = new FOForAll(); fo.setOperand(f2); fo.setQuantifiedVariable(x2); fo.setQualifier("/event/name"); OperatorG f3 = new OperatorG(); f3.setOperand(fo); OperatorX secondPart = new OperatorX(); secondPart.setOperand(f3); OperatorEquals f4 = new OperatorEquals(new Atom(x1), new Constant("ElephantUpgrade")); FOForAll fo2 = new FOForAll(); fo2.setOperand(f4); //fo2.setOperand(secondPart); fo2.setQuantifiedVariable(x1); fo2.setQualifier("/event/name"); OperatorImplies f5 = new OperatorImplies(fo2,secondPart); OperatorG formula = new OperatorG(); formula.setOperand(f5); OperatorImplies oi = new OperatorImplies(); oi.setLeftOperand(Constant.m_trueAtom); oi.setRightOperand (fo); SymbolicWatcher w = new SymbolicWatcher(); w.setFormula(oi); w.reset(); w.update ("<event><name>ElephantUpgrade</name></event>"); w.update ("<event><name>ElephantUpgrade</name></event>"); }
/** * Constructs an Operator based on a string. With the exception of possible * superfluous parentheses and whitespace, the resulting operator is such * that getFromString(s).toString() == s. The input string must respect the * following BNF grammar (which corresponds to LTL + first-order; * parentheses are important): * <ol> * <li>string := atom | binary_op | unary_op | quantified * <li>binary_op := (string) bin_operator (string) * <li>unary_op := un_operator (string) * <li>quantified := [qualif_var] (string) | <qualif_var> (string) * <li>bin_operator := & | -> | the "pipe" character | U | = | < | * > | - * <li>un_operator := ! | G | X | F * <li>qualif_var := atom qualif (there is a whitespace character between * atom and qualif) * <li>atom := any literal composed of alphanumerical characters, with the * exception of reserved sequences such as operators * <li>qualif:= any literal composed of alphanumerical characters, with the * exception of reserved sequences such as operators * </ol> * * @param s * The input string * @param domains * A map from a set of paths to a set of values (atoms), providing * finite domains for quantifiers. This parameter is facultative; * domains need to be provided only when quantifiers need to be * expanded into explicit conjunctions/disjunctions of values, or * when messages must be generated (instead of monitored). * * @return An Operator equivalent to the string passed as an argument, null * if the string does not correspond to a valid Operator. */ public static Operator parseFromString(string s, IDictionary<string, HashSet<Constant>> domains) { bool flag = false; int quantRight = 0, parLeft = 0; Operator o = null, o2 = null; FOQuantifier foq = null; UnaryOperator uo = null; BinaryOperator bo = null; Atom a = null; // First removes/converts extra whitespace s = LTLStringParser.formatString(s); string sTrim = s.Trim(); if (sTrim.Length == 0) { return null; } // Handles first-order quantifiers flag = false; if (sTrim[0] == '[') { foq = new FOForAll(); quantRight = sTrim.IndexOf("]"); flag = true; } if (sTrim[0] == '<') { foq = new FOExists(); quantRight = sTrim.IndexOf(">"); flag = true; } if (flag) { Regex r = new Regex("^(\\w+)\\s*(.*)$"); MatchCollection m = r.Matches(sTrim.Substring(1, quantRight - 1)); if (m.Count > 0) { Match m2 = m[0]; GroupCollection g = m2.Groups; Atom qvar = new Atom(g[1].ToString()); string qualifier = g[2].ToString(); foq.setQuantifiedVariable(qvar); foq.setQualifier(qualifier); if (domains != null) { // If a domain is provided, attaches it to the quantifier HashSet<Constant> dom = new HashSet<Constant>(); foreach (KeyValuePair<string, HashSet<Constant>> con in domains) { if (con.Key == qualifier) { dom = con.Value; } } foq.setDomain(dom); } } //foq.setQualifiedVariable(sTrim.substring(1, quantRight)); parLeft = sTrim.IndexOf("(", (quantRight + 1)); //parRight = sTrim.indexOf(")", parLeft); o = parseFromString(sTrim.Substring((parLeft + 1), sTrim.Length - 1 - (parLeft + 1)), domains); foq.setOperand(o); return foq; } // Handles unary operators flag = false; if (sTrim.Substring(0, 1) == "!") { uo = new OperatorNot(); flag = true; } if (sTrim.Substring(0, 1) == "F") { uo = new OperatorF(); flag = true; } if (sTrim.Substring(0, 1) == "G") { uo = new OperatorG(); flag = true; } if (sTrim.Substring(0, 1) == "X") { uo = new OperatorX(); flag = true; } if (sTrim.Length >= 2) { // This is for CTL, nothing to do here } if (flag) { parLeft = sTrim.IndexOf("("); o = parseFromString(sTrim.Substring((parLeft + 1), sTrim.Length - 1 - (parLeft + 1)), domains); uo.setOperand(o); return uo; } // Handles binary operators flag = false; if (sTrim[0] == '(') { // At this point in the method, if first char is a "(", // the formula is necessarily a binary operator int parNum = 0; string sLeft = "", sRight = ""; string binaryOp = ""; Regex r = new Regex("(\\(|\\))"); MatchCollection m = r.Matches(sTrim); int mend = -1; for (int i = 0; i < m.Count; i++) { Match m2 = m[i]; mend = m[i].Groups[0].Index + m[i].Groups[0].Length; GroupCollection g = m2.Groups; if (g[0].ToString().Equals("(")) { parNum++; } else { parNum--; } if (parNum == 0) { sLeft = sTrim.Substring(1, mend - 1 - 1); break; } } parLeft = sTrim.IndexOf("(", mend); int left_var = mend + 1; binaryOp = sTrim.Substring(left_var, parLeft - left_var - 1).Trim(); sRight = sTrim.Substring(parLeft + 1, sTrim.Length - 1 - (parLeft + 1)).Trim(); o = parseFromString(sLeft, domains); o2 = parseFromString(sRight, domains); if (binaryOp == "&") { bo = new OperatorAnd(); flag = true; } if (binaryOp == "|") { bo = new OperatorOr(); flag = true; } if (binaryOp == "=") { bo = new OperatorEquals(o, o2); flag = true; } if (binaryOp == "->") { bo = new OperatorImplies(o, o2); flag = true; } if (binaryOp == "-") { bo = new OperatorMinus(o, o2); flag = true; } if (binaryOp == "<") { bo = new OperatorSmallerThan(o, o2); flag = true; } if (binaryOp == "<=") { bo = new OperatorSmallerThan(o, o2, true); flag = true; } if (binaryOp == ">") { bo = new OperatorGreaterThan(o, o2); flag = true; } if (binaryOp == ">=") { bo = new OperatorGreaterThan(o, o2, true); flag = true; } if (binaryOp == "U") { bo = new OperatorU(o, o2); flag = true; } if (binaryOp == "V") { bo = new OperatorV(o, o2); flag = true; } if (flag) { return bo; } } else { // At this point, the only case left is that of a single atom // (either a constant or a variable) if (sTrim[0] == '{') { // Constants are surrounded by braces a = new Constant(sTrim.Substring(1, sTrim.Length - 1 - 1)); } else if (sTrim[0] == '/') { // XPaths are surrounded by forward slashes a = new ConstantPath(sTrim.Substring(1, sTrim.Length - 1 - 1)); } else { // Otherwise, we have an atom a = new Atom(sTrim); } return a; } // Down there, none of the previous cases has fired: return o, which is // null System.Diagnostics.Debug.Assert (false); return o; }
public override Operator getNegated() { FOForAll fq = new FOForAll(); fq.m_quantifiedVariable = m_quantifiedVariable; fq.m_qualifier = m_qualifier; fq.m_operand = m_operand.getNegated(); return fq; }
/** * Evaluates a CTL-FO+ formula by replacing an atom by another in it. You * can actually replace an atom by a whole formula. * * @param variable * The atom to look for. * @param value * The value to replace it with. * @return The evaluated formula */ public override Operator evaluate(Atom variable, Operator val) { /* * TODO: The code for evaluate here and in the FOExists class are * identical except for the first line (construction of a new instance * of either an FOExists or an FOForAll). Isn't there a way to * centralize that function up in the FOQuantifier class? */ FOForAll fq = new FOForAll(); fq.m_quantifiedVariable = m_quantifiedVariable; fq.m_qualifier = m_qualifier; fq.m_domain = m_domain; fq.m_operand = m_operand.evaluate(variable, val); return fq; }
public HashSet<GeneratorNode> spawn(FOForAll op) { HashSet<GeneratorNode> spawnedSet, outSet = new HashSet<GeneratorNode>(); Atom x = op.getQuantifiedVariable(); string qualifier = op.getQualifier(); // Iterate over domain HashSet<Constant> oplus_domain = getOPlusDomain(qualifier); HashSet<Constant> domain = op.getDomain(); SubsetIterator<Constant> it; if (!m_encounteredQualifiers.Contains(qualifier)) { // We haven't decomposed a For All in the past, so we can // add elements to the message it = new SubsetIterator<Constant>(domain, oplus_domain); } else { // Otherwise, we stick to the elements we already have to // evaluate this quantifier it = new SubsetIterator<Constant>(oplus_domain); } m_encounteredQualifiers.Add(op.getQualifier()); m_decomposedAForAll = true; if (op.isPathNegation()) { // The quantifier asserts the absence of a path GeneratorNode wn = new GeneratorNode(this); OPlus opl = new OPlus(); opl.setQualifier(op.getQualifier()); opl.setOperand(Operator.m_falseAtom); if (!wn.addToOPluses(opl)) { // We can't add this OPlus to the current set. Contradiction! Return the empty set return new HashSet<GeneratorNode>(); } return wn.spawn(); } if (op.isPathAssertion()) { // In negated form, the quantifier may assert the existence of a path GeneratorNode wn = new GeneratorNode(this); OPlus opl = new OPlus(); opl.setQualifier(op.getQualifier()); opl.setOperand(Operator.m_trueAtom); if (!wn.addToOPluses(opl)) { // We can't add this OPlus to the current set. Contradiction! Return the empty set return new HashSet<GeneratorNode>(); } return wn.spawn(); } while (it.hasNext()) { GeneratorNode wn = new GeneratorNode(this); HashSet<Constant> subset = it.next(); foreach (Atom v in subset) { Operator o2 = op.getOperand(); Operator o3 = o2.evaluate(x, v); OPlus opl = new OPlus(qualifier, v); wn.addToGamma(o3); if (!wn.addToOPluses(opl)) { // Contradiction! Skip that branch continue; } } spawnedSet = wn.spawn(); if (spawnedSet != null) { foreach (GeneratorNode gn in spawnedSet) { outSet.Add(gn); } } } return outSet; }