public ImpliesProposition(ASTOpBinary ast) : base(ast) { if (ast.value != Language.Symbol.IMPLICA) { throw new Exception("An ImpliesProposition can only be created from an AST if this is a ASTOpBinary of type IMPLICA."); } }
/// <summary> /// Formula extraction. /// </summary> /// <param name="branch">The current branch to extract from</param> private void Extract(AST branch = null) { if (m_formulas == null) { m_formulas = new List <AST>(); } AST current = branch != null ? branch : m_formula; switch (current.GetType().Name) { case "ASTProp": case "ASTOpUnary": m_formulas.Add(current); break; case "ASTOpBinary": ASTOpBinary binOp = (ASTOpBinary)current; switch (binOp.value) { case Language.Symbol.E: // Extraction must continue. Extract(binOp.left); Extract(binOp.right); break; case Language.Symbol.OU: // Already a disjuction. Extraction must return. m_formulas.Add(current); break; default: // There should not be other symbols in an CNF formula. break; } break; } }
public EquivalentProposition(ASTOpBinary ast) : base(ast) { if (ast.value != Language.Symbol.EQUIVALE) { throw new Exception("An EquivalentProposition can only be created from an AST if this is a ASTOpBinary of type EQUIVALE."); } }
public DisjunctiveProposition(ASTOpBinary ast) : base(ast) { if (ast.value != Language.Symbol.OU) { throw new Exception("A DisjunctiveProposition can only be created from an AST if this is a ASTOpBinary of type OU."); } }
protected IEnumerable <Proposition> ConvertFromAST(AST ast, Language.Symbol oper) { if (ast == null) { return(null); } List <Proposition> result = new List <Proposition>(); string type = ast.GetType().Name; if (type == "ASTOpBinary") { ASTOpBinary opBin = ast as ASTOpBinary; if (opBin.value == oper) { result.AddRange(ConvertFromAST(opBin.left, oper)); result.AddRange(ConvertFromAST(opBin.right, oper)); return(result); } } // else result.Add(Proposition.FromAST(ast)); return(result); }
private static string StrPlain(AST ast, bool innerOR = false) { if (ast == null) { return("CLAÚSULA NULA"); } switch (ast.GetType().Name) { case "ASTProp": return(((ASTProp)ast).value.ToString().ToLower()); case "ASTOpUnary": return("(~" + StrPlain(((ASTOpUnary)ast).ast) + ")"); case "ASTOpBinary": ASTOpBinary opBin = (ASTOpBinary)ast; bool nextOR = (opBin.value == Language.Symbol.OU); string plain = StrPlain(opBin.left, nextOR) + " " + opBin.value + " " + StrPlain(opBin.right, nextOR); if (!innerOR) { plain = "(" + plain + ")"; } return(plain); } // switch return(""); }
public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return(false); } ASTOpBinary other = obj as ASTOpBinary; return (this.left.Equals(other.left) && this.right.Equals(other.right) && this.value == other.value ); }
/// <summary> /// Separates a formula in CNF in its OR components clauses. /// </summary> /// <param name="astInCnf">An AST in CNF form.</param> /// <returns>A enumerable of CnfOr clauses.</returns> public static IEnumerable <CnfOr> Separate(AST astInCnf, bool order = false) { if (astInCnf == null) { return(null); } List <CnfOr> result = new List <CnfOr>(1); switch (astInCnf.GetType().Name) { case "ASTProp": case "ASTOpUnary": result.Add(new CnfOr(astInCnf)); break; case "ASTOpBinary": ASTOpBinary opBin = (ASTOpBinary)astInCnf; switch (opBin.value) { case Language.Symbol.OU: // Form (A|B). result.Add(new CnfOr(astInCnf)); break; case Language.Symbol.E: // Form (A&B). result.AddRange(Separate(opBin.left)); result.AddRange(Separate(opBin.right)); break; case Language.Symbol.IMPLICA: // Form (P->Q). case Language.Symbol.EQUIVALE: // Form (P<->Q). throw new System.Exception("AST in CNF separation failed. There can't be other binary operator beside & or | in a formula in CNF."); } break; } if (order) { result.Sort(); } return(result); }
private void Extract(AST astInCNF) { switch (astInCNF.GetType().Name) { case "ASTProp": char letter = (astInCNF as ASTProp).value; m_content.Add(new Component(letter)); break; case "ASTOpUnary": ASTOpUnary astNeg = astInCNF as ASTOpUnary; if (astNeg.ast.GetType().Name != "ASTProp") { // In CNF form, the negation can only refers to a simple proposition. throw new Exception("Error creating a CnfOr : In CNF form, the negation can only refers to a simple proposition."); } letter = (astNeg.ast as ASTProp).value; m_content.Add(new Component(letter, true)); break; case "ASTOpBinary": ASTOpBinary opBin = astInCNF as ASTOpBinary; switch (opBin.value) { case Language.Symbol.OU: // Form (A|B). Extract(opBin.left); Extract(opBin.right); break; case Language.Symbol.E: // Form (A&B). case Language.Symbol.IMPLICA: // Form (P->Q). case Language.Symbol.EQUIVALE: // Form (P<->Q). throw new Exception("Error creating a CnfOr : In CNF form, OR formulas can't contain other operators than OR."); } break; } }
// Transitional function. Convert from AST. public static Proposition FromAST(AST ast) { switch (ast.GetType().Name) { case "ASTProp": return(new SingleProposition(ast as ASTProp)); case "ASTOpUnary": return(new NegationProposition(ast as ASTOpUnary)); case "ASTOpBinary": ASTOpBinary opBin = ast as ASTOpBinary; switch (opBin.value) { case Language.Symbol.E: return(new ConjunctiveProposition(opBin)); case Language.Symbol.OU: return(new DisjunctiveProposition(opBin)); case Language.Symbol.IMPLICA: return(new ImpliesProposition(opBin)); case Language.Symbol.EQUIVALE: return(new EquivalentProposition(opBin)); default: throw new Exception(string.Format( "The operation {0} is not supported for conversion to Proposition", opBin.value )); } } return(null); }
/// <summary> /// Parsing recursive implementation. /// </summary> /// <param name="precede">does precedence must be considered in this recursive call?</param> /// <returns>the resulting AST node.</returns> AST Walk(bool precede = false) { // Increment the global index. m_idx++; if (m_idx >= Tokens.Count) { return(null); } // Read the current index's token value. Token token = Tokens[m_idx]; AST ast = null; switch (token.type) { case Language.Symbol.PROP: // a propositional letter. ast = new ASTProp(token.value); break; case Language.Symbol.NAO: // negation operation. ast = new ASTOpUnary(Walk(true), token.type); break; case Language.Symbol.E: // conjunction operation. case Language.Symbol.OU: // disjunction operation. ast = new ASTOpBinary(m_current, Walk(true), token.type); break; case Language.Symbol.IMPLICA: // implication operation. case Language.Symbol.EQUIVALE: // double implication operation. // double implication has lesser precedence over single implication. bool bi = token.type == Language.Symbol.EQUIVALE; // must continue to parse? bool forward = // we continue parsing if... m_implFlag == 0 || // ... there is no implications awaiting or ... (m_implFlag == 2 && !bi); // ... a double implication awaits and the current is a single implication. if (forward) { // must continue the parsing. // save current implication flag value... int implications = m_implFlag; // and update the global value. m_implFlag = bi ? 2 : 1; // enter another recursion. ast = new ASTOpBinary(m_current, Walk(false), token.type); // did the last recursive call finished precedence analysis? if (m_implFlag == 0) { precede = false; } // restore previous (saved) implication flag value. m_implFlag = implications; } else { // must not continue and must return to the last call. m_idx--; ast = m_current; precede = true; m_implFlag = 0; break; } break; case Language.Symbol.ABERTURA: // opening expression symbol. // enter a new recursive call, as an AST node must come from the parenthesis' content analysis. while (Walk(precede) != null) { ast = m_current; } break; case Language.Symbol.FECHAMENTO: // closing expression symbol. return(null); } // update current AST node. m_current = ast; // continue the processing as long as there are tokens and no precedence. if (!precede && m_idx < Tokens.Count) { Walk(); } return(m_current); }
} // Extractor class #endregion Inner classes #region Public functions /// <summary> /// Convert the formula to conjuntive normal form. /// </summary> /// <param name="ast">original abstract syntatic tree representinf the formula.</param> /// <returns>formula in CNF.</returns> public static AST Convert(AST ast) { if (ast == null) { return(ast); } switch (ast.GetType().Name) { case "ASTProp": return(ast); case "ASTOpBinary": ASTOpBinary opBin = ast as ASTOpBinary; switch (opBin.value) { case Language.Symbol.E: // Form (P&Q). AST left = Convert(opBin.left); AST right = Convert(opBin.right); return(new ASTOpBinary(left, right, Language.Symbol.E)); case Language.Symbol.OU: // Form (P|Q). left = Convert(opBin.left); right = Convert(opBin.right); return(Distribute(left, right)); case Language.Symbol.IMPLICA: // Form (P->Q). Equivalent to (~P|Q) return(Convert( new ASTOpBinary( new ASTOpUnary(opBin.left, Language.Symbol.NAO), opBin.right, Language.Symbol.OU) )); case Language.Symbol.EQUIVALE: // Form (P<->Q). Equivalent to (P&Q)|(~P&~Q). left = new ASTOpBinary(opBin.left, opBin.right, Language.Symbol.E); right = new ASTOpBinary( new ASTOpUnary(opBin.left, Language.Symbol.NAO), new ASTOpUnary(opBin.right, Language.Symbol.NAO), Language.Symbol.E ); return(Convert(new ASTOpBinary(left, right, Language.Symbol.OU))); } break; case "ASTOpUnary": AST p = (ast as ASTOpUnary).ast; switch (p.GetType().Name) { case "ASTProp": // Form ~P ... return ~P return(ast); case "ASTOpUnary": // Form ~(~P) - double negation ... return Convert(P) return(Convert((p as ASTOpUnary).ast)); case "ASTOpBinary": opBin = (ASTOpBinary)p; Language.Symbol op = opBin.value; if (op != Language.Symbol.E && op != Language.Symbol.OU) { // Not yet in CNF. AST pInNcf = Convert(p); return(Convert(new ASTOpUnary(pInNcf, Language.Symbol.NAO))); } AST left = new ASTOpUnary(opBin.left, Language.Symbol.NAO); AST right = new ASTOpUnary(opBin.right, Language.Symbol.NAO); Language.Symbol deMorganOp = Language.Symbol.INVALIDO; if (opBin.value == Language.Symbol.E) { // Form ~(P&Q): from DeMorgan's Law, return Convert(~P|~Q) deMorganOp = Language.Symbol.OU; } else if (opBin.value == Language.Symbol.OU) { // Form ~(P|Q): from DeMorgan's Law, return Convert(~P&~Q) deMorganOp = Language.Symbol.E; } return(Convert(new ASTOpBinary(left, right, deMorganOp))); } break; } return(null); }
// transitional constructor public BinaryOperation(ASTOpBinary ast) { Left = Proposition.FromAST(ast.left); Right = Proposition.FromAST(ast.right); }