/// <summary>Make proposiiton with operator, atom and two sub-proposition</summary> /// <param name="op">Operator of proposition</param> /// <param name="atom">Atom of proposition</param> /// <param name="expr1">First sub-proposition of proposition</param> /// <param name="expr2">Second sub-proposition of proposition</param> public Proposition(Operator op, Atom atom, Proposition expr1, Proposition expr2) { this.left = expr1; this.right = expr2; this.atom = atom; this.op = op; }
/// <summary>Evaluate at given proposition</summary> /// <param name="expr">Proposition to evaluate</param> /// <returns>Result of evaluation</returns> private bool Evaluate(Proposition expr) { switch (expr.op) { case Operator.Atom: string s = expr.atom.Symbol; if (s == ParseEngine.SYMBOL_T) { return(true); } else if (s == ParseEngine.SYMBOL_F) { return(false); } return(evalData[s]); case Operator.Or: return(Evaluate(expr.left) || Evaluate(expr.right)); case Operator.And: return(Evaluate(expr.left) && Evaluate(expr.right)); case Operator.Not: return(!Evaluate(expr.left)); case Operator.Imply: return(!Evaluate(expr.left) || Evaluate(expr.right)); case Operator.IfOnlyIf: return(!(Evaluate(expr.left) ^ Evaluate(expr.right))); default: return(false); } }
/// <summary>Parse from current position with given priority</summary> /// <param name="prec">Priority</param> /// <returns>Parsed proposition</returns> private Proposition ParseWithPrec(int prec) { Proposition expr1, expr2; expr1 = GetNextExpression(); backIndex = index; while (index != input.Length) { string s = GetNextToken(); if (s == SYMBOL_RP) { index = backIndex; return(expr1); } Operator op = GetOperator(s); int pr = GetPrecedence(op); if (pr > prec) { index = backIndex; return(expr1); } else { expr2 = ParseWithPrec(pr); expr1 = new Proposition(op, expr1, expr2); } } return(expr1); }
/// <summary>Check whether give proposition is contradiction</summary> /// <param name="expr">Proposition to check</param> /// <exception cref="InvaildPropositionException"></exception> /// <returns>True if contradiction</returns> public bool IsContradiction(Proposition expr) { if (expr == null || !expr.IsVaild()) { throw new InvalidPropositionException("INVAILD"); } return(GetTrueAssignmentList(expr).Count == 0); }
/// <summary>Find assignment list which each assignment table make give proposition true</summary> /// <param name="expr">Proposition to get true assignment list</param> /// <exception cref="InvaildPropositionException"></exception> /// <returns>Assignment list</returns> public List <Dictionary <string, bool> > GetTrueAssignmentList(Proposition expr) { if (expr == null || !expr.IsVaild()) { throw new InvalidPropositionException("INVAILD"); } trueList = new List <Dictionary <string, bool> >(); GetTrueAssignmentListCore(expr, new Dictionary <string, bool>()); return(trueList); }
/// <summary>Check whether give proposition is tautology</summary> /// <param name="expr">Proposition to check</param> /// <exception cref="InvaildPropositionException"></exception> /// <returns>True if tautology</returns> public bool IsTautology(Proposition expr) { if (expr == null || !expr.IsVaild()) { throw new InvalidPropositionException("INVAILD"); } if (!expr.IsCNF()) { expr = ConvertToCNF(ConvertToNNF(expr)); } return(IsTautologyCore(expr)); }
/// <summary>Convert given NNF proposition to CNF proposition</summary> /// <param name="expr">NNF proposition to convert</param> /// <exception cref="PropositionNotSupportException"></exception> /// <returns>CNF proposition</returns> public Proposition ConvertToCNF(Proposition expr) { if (expr == null || !expr.IsNNF()) { throw new PropositionNotSupportedException("NOT_NNF"); } if (expr.op == Operator.Atom) { return(expr); } else if (expr.op == Operator.And) // S(P&Q) => S(P)&S(Q) { return(new Proposition(Operator.And, ConvertToCNF(expr.left), ConvertToCNF(expr.right))); } else if (expr.op == Operator.Or) // S(P|Q) => { Proposition c1 = ConvertToCNF(expr.left); Proposition c2 = ConvertToCNF(expr.right); if (c1.op != Operator.And && c2.op != Operator.And) // S(P|Q) => S(P)|S(Q) { return(new Proposition(Operator.Or, c1, c2)); } if (c1.op != Operator.And) { Proposition tmp = c1; c1 = c2; c2 = tmp; // S((A&B)|C) => S(A|C)&S(B|C) } return(new Proposition(Operator.And, ConvertToCNF(new Proposition(Operator.Or, c1.left, c2)), ConvertToCNF(new Proposition(Operator.Or, c1.right, c2)))); } else if (expr.op == Operator.Not) // S(P) => S(P) { if (expr.left.op == Operator.Atom) // Must Be Unit According to Def. of NNF { return(expr); } } return(null); }
/// <summary>Evaluate proposition with given data</summary> /// <param name="value">Result of evaluation</param> /// <param name="error">Error Message</param> /// <param name="expr">Proposition to evaluate</param> /// <param name="data">Assignment table</param> /// <returns>True if successed evaluate</returns> public bool TryEvaluate(out bool value, out string error, Proposition expr, Dictionary <string, bool> data) { value = false; error = ""; if (expr == null || !expr.IsVaild()) { error = InvalidPropositionException.REASON_INVAILD; return(false); } List <string> atomList = expr.GetAtomList(); List <string> keyList = data.Keys.ToList(); if (atomList.Intersect(keyList).Count() != atomList.Count) { error = "모든 atom에 대해 적절한 대입값이 없습니다."; return(false); } evalData = data; value = Evaluate(expr); return(true); }
/// <summary>Build all possible assignment and calculate</summary> /// <param name="expr">Proposition to calculate</param> /// <param name="dict">Assignment list</param> private void GetTrueAssignmentListCore(Proposition expr, Dictionary <string, bool> dict) { if (expr.GetAtomList().Count == dict.Count) { bool value; string result; calcEng.TryEvaluate(out value, out result, expr, dict); if (value) { trueList.Add(dict.DeepCopy()); } } else { string target = expr.GetAtomList().Except(dict.Keys.ToList()).First(); Dictionary <string, bool> dict1 = dict.DeepCopy(), dict2 = dict.DeepCopy(); dict1.Add(target, false); dict2.Add(target, true); GetTrueAssignmentListCore(expr, dict1); GetTrueAssignmentListCore(expr, dict2); } }
/// <summary>Parse string to proposition object</summary> /// <param name="expr">Parsed proposition object</param> /// <param name="result">Result of parsing</param> /// <param name="str">String to parse</param> /// <returns>True if success parsing</returns> public bool TryParse(out Proposition expr, out string result, string str) { expr = null; result = ""; backIndex = 0; index = 0; try { input = Normalize(str).ToCharArray(); expr = ParseWithPrec(PREC_MAX); } catch (ParseException e) { result = e.Message; return(false); } if (index != input.Length) { result = ParseException.REASON_NOT_READ_ALL; return(false); } return(true); }
/// <summary>Find next proposition from current position</summary> /// <returns>Proposition</returns> private Proposition GetNextExpression() { string s = GetNextToken(); if (s == SYMBOL_LP) { Proposition expr = ParseWithPrec(PREC_MAX); if (!MoveNext(SYMBOL_RP)) { throw new ParseException("NOT_MATCH_PARN", index.ToString()); } return(expr); } else if (s == SYMBOL_NOT) { Proposition expr = ParseWithPrec(PREC_NOT); return(new Proposition(Operator.Not, expr)); } else { return(new Proposition(Operator.Atom, new Atom(s))); } }
/// <summary>Tautology core engine</summary> /// <param name="expr">Proposition to check</param> /// <returns>True if tautology</returns> private bool IsTautologyCore(Proposition expr) { if (expr.op == Operator.Atom) { if (expr.atom.Symbol == "T") { return(true); } else { return(false); } } else if (expr.op == Operator.Not) { if (expr.atom.Symbol == "F") { return(true); } else { return(false); } } else if (expr.op == Operator.And) { return(IsTautologyCore(expr.left) && IsTautologyCore(expr.right)); } else if (expr.op == Operator.Or) { return(expr.IsTautologyClause()); } else { return(false); } }
/// <summary>Make proposiiton with operator and two sub-proposition</summary> /// <param name="op">Operator of proposition</param> /// <param name="expr1">First sub-proposition of proposition</param> /// <param name="expr2">Second sub-proposition of proposition</param> public Proposition(Operator op, Proposition expr1, Proposition expr2) : this(op, null, expr1, expr2) { }
/// <summary>Convert given proposition to negative normal form</summary> /// <param name="expr">Proposition to convert</param> /// <exception cref="InvaildPropositionException"></exception> /// <returns>NNF proposition</returns> public Proposition ConvertToNNF(Proposition expr) { if (expr == null || !expr.IsVaild()) { throw new InvalidPropositionException("INVAILD"); } if (expr.op == Operator.Atom) { return(expr); } else if (expr.op == Operator.Or) // S(P|Q) => S(P)|S(Q) { return(new Proposition(Operator.Or, ConvertToNNF(expr.left), ConvertToNNF(expr.right))); } else if (expr.op == Operator.And) // S(P&Q) => S(P)&S(Q) { return(new Proposition(Operator.And, ConvertToNNF(expr.left), ConvertToNNF(expr.right))); } else if (expr.op == Operator.Imply) // S(P->Q) => S(~P)|S(Q) { return(new Proposition(Operator.Or, ConvertToNNF(new Proposition(Operator.Not, expr.left)), ConvertToNNF(expr.right))); } else if (expr.op == Operator.IfOnlyIf) // S(P<->Q) => S(P->Q)&S(Q->P) { return(new Proposition(Operator.And, ConvertToNNF(new Proposition(Operator.Imply, expr.left, expr.right)), ConvertToNNF(new Proposition(Operator.Imply, expr.right, expr.left)))); } else if (expr.op == Operator.Not) // S(~P) => { Proposition nexpr = expr.left; if (nexpr.op == Operator.Atom) // S(T) => F, S(F) => T, S(~P) => ~P { if (nexpr.atom.Symbol == "T") { return(new Proposition(Operator.Atom, new Atom("F"))); } else if (nexpr.atom.Symbol == "F") { return(new Proposition(Operator.Atom, new Atom("T"))); } else { return(expr); } } if (nexpr.op == Operator.Imply) // S(P->Q) => S(~P)|S(Q) { nexpr = new Proposition(Operator.Or, ConvertToNNF(new Proposition(Operator.Not, nexpr.left)), ConvertToNNF(nexpr.right)); } else if (nexpr.op == Operator.IfOnlyIf) // S(P<->Q) => S(P->Q)&S(Q->P) { nexpr = new Proposition(Operator.And, ConvertToNNF(new Proposition(Operator.Imply, nexpr.left, nexpr.right)), ConvertToNNF(new Proposition(Operator.Imply, nexpr.right, nexpr.left))); } if (nexpr.op == Operator.Or) // S(~(P|Q)) => ~S(P)&~S(Q) { return(new Proposition(Operator.And, ConvertToNNF(new Proposition(Operator.Not, nexpr.left)), ConvertToNNF(new Proposition(Operator.Not, nexpr.right)))); } else if (nexpr.op == Operator.And) // S(~(P&Q)) => ~S(P)|~S(Q) { return(new Proposition(Operator.Or, ConvertToNNF(new Proposition(Operator.Not, nexpr.left)), ConvertToNNF(new Proposition(Operator.Not, nexpr.right)))); } else if (nexpr.op == Operator.Not) // S(~(~P))) => S(P) { return(ConvertToNNF(nexpr.left)); } } return(null); }