From 199fa45cf5b446b260e32da23a767ff07a67c9b6 Mon Sep 17 00:00:00 2001 From: Mateusz Gemzicki Date: Thu, 7 Jun 2018 10:44:41 +0200 Subject: [PATCH] Initial Commit with Script --- README.md | 39 +++++++++++++++++++++++++++ logic_formula_checker/__init__.py | 3 +++ logic_formula_checker/__main__.py | 28 +++++++++++++++++++ logic_formula_checker/types.py | 27 +++++++++++++++++++ logic_formula_checker/utils.py | 45 +++++++++++++++++++++++++++++++ requirements.txt | 0 run.py | 9 +++++++ tests.py | 26 ++++++++++++++++++ 8 files changed, 177 insertions(+) create mode 100644 README.md create mode 100644 logic_formula_checker/__init__.py create mode 100644 logic_formula_checker/__main__.py create mode 100644 logic_formula_checker/types.py create mode 100644 logic_formula_checker/utils.py create mode 100644 requirements.txt create mode 100644 run.py create mode 100644 tests.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..db21550 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# Logic formula checker +Script for checking is formula is correct + +### Installation +You can run this script without downloading any other libraries. + +### Usage +There are several ways of usage. ++ You can use is as a library in your project: +``` + from logic_formula_checker import is_formula_correct +``` ++ With run.py for interactive console ++ From bash +``` + $ python -m logic_formula_checker -f (a∧b) +``` + +### Testing +Some tests is written in tests.py file. They check if formula single tests work properly. + + +## Script logic explaination +It takes two test of formula for checking formula's correctness. +Firstly check if all brackets are properly opened and closed. +``` + ( { } ) - Good + ( { ) } - Wrong + ( { } - Wrong +``` +Next script checks if signs are rightly put. Brackets are bypassed. Steps: +1. Read sign, check what kind it is (Types are in logic_formula_checker/types.py). +2. Check if it is in expected_sign list. +3. Update expected_sign list base on current sign +``` + a ^ ¬ b // take a, write to expected_sign conjuction symbols and negation symbols + ^ ¬ b // take ^, check is it in expected_sign, update expected_sign with asci lowercase sings (formula variables) and negation signs + +``` \ No newline at end of file diff --git a/logic_formula_checker/__init__.py b/logic_formula_checker/__init__.py new file mode 100644 index 0000000..bdd77e7 --- /dev/null +++ b/logic_formula_checker/__init__.py @@ -0,0 +1,3 @@ +from .__main__ import * +from .utils import * +from .types import * \ No newline at end of file diff --git a/logic_formula_checker/__main__.py b/logic_formula_checker/__main__.py new file mode 100644 index 0000000..ecaf77f --- /dev/null +++ b/logic_formula_checker/__main__.py @@ -0,0 +1,28 @@ +from .utils import * + +from argparse import ArgumentParser +import json + + +def parse_args(): + parser = ArgumentParser(description="Check correctness of logic formula") + parser.add_argument('-f', '--formula', dest=formula, metavar='FORMULA') + parser.add_argument('-fl', '--formula-list', dest=list_formula, metavar='[FORMULA, FORMULA]') + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + if args.list_formula: + list_formula = json.loads(args.list_formula) + if not isinstance(list_formula, list): + print('Type of --formula-list is not a list') + else: + for formula in list_formula: + print( + "{}: {}".format(formula, is_formula_correct(formula)) + ) + elif args.formula: + print( + "{}: {}".format(args.formula, is_formula_correct(args.formula)) + ) \ No newline at end of file diff --git a/logic_formula_checker/types.py b/logic_formula_checker/types.py new file mode 100644 index 0000000..09a7cf5 --- /dev/null +++ b/logic_formula_checker/types.py @@ -0,0 +1,27 @@ +import string + + +class SentenceVariable(object): + symbols = string.ascii_lowercase + + +class SupportSign(object): + symbols_open = ['[', '{', '('] + symbols_close = [']', '}', ')'] + symbols = symbols_open + symbols_close + + @classmethod + def get_closed_symbol(cls, open_symbol): + return cls.symbols_close[cls.symbols_open.index(open_symbol)] + + +class SentenceConjunction(object): + symbols_conjunction = ['.', '*', '&', '∧', 'AND'] + symbols_alternative = ['+', '∧', 'A', 'OR'] + symbols_implication = ['⇒', '→', '⊃'] + symbols_equivalence = ['⇔', '≡', '↔'] + symbols = symbols_conjunction + symbols_alternative + symbols_implication + symbols_implication + + +class Negation(object): + symbols = ['!', '¬', '˜'] diff --git a/logic_formula_checker/utils.py b/logic_formula_checker/utils.py new file mode 100644 index 0000000..ae5c90a --- /dev/null +++ b/logic_formula_checker/utils.py @@ -0,0 +1,45 @@ +from .types import SupportSign, SentenceConjunction, SentenceVariable, Negation + + +def is_formula_correct(formula): + """ Run all test on formula """ + if not formula: + return True + + else: + formula = formula.replace(' ', '') + return all([check_order(formula), check_parenthesis(formula)]) + + +def check_parenthesis(formula: str) -> bool: + """ Check if all brackets are opened and closed correctly """ + stack_of_expected_sings = [] + + for sign in formula: + if sign in SupportSign.symbols_open: + inverse_of_sign = SupportSign.get_closed_symbol(sign) + stack_of_expected_sings.append(inverse_of_sign) + elif sign in SupportSign.symbols_close: + if stack_of_expected_sings.pop() != sign: + return False + + return not stack_of_expected_sings + + +def check_order(formula: str) -> bool: + """ Check if all sings have correct preceding and next sign """ + expected_sign = [] + + for sign in formula: + if sign in SupportSign.symbols: + continue + if expected_sign and sign not in expected_sign: + return False + if sign in Negation.symbols: + expected_sign = SentenceVariable.symbols + elif sign in SentenceConjunction.symbols: + expected_sign = Negation.symbols + SentenceVariable.symbols + elif sign in SentenceVariable.symbols: + expected_sign = SentenceConjunction.symbols + + return any(symbol in expected_sign for symbol in SentenceVariable.symbols) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/run.py b/run.py new file mode 100644 index 0000000..4f14d02 --- /dev/null +++ b/run.py @@ -0,0 +1,9 @@ +from logic_formula_checker import is_formula_correct + + +if __name__ == '__main__': + formula = input('Type your formula to check: ') + if is_formula_correct(formula): + print('Formula is correct') + else: + print('Formula is incorrect') diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..aa9eac5 --- /dev/null +++ b/tests.py @@ -0,0 +1,26 @@ +import unittest +from logic_formula_checker.utils import * +from logic_formula_checker.types import * + + +class TestsLogicallySentenceChecker(unittest.TestCase): + + def test_check_parenthis(self): + correct_formula_short = '[a∧b]' + incorrect_formula_short = '[a∧b' + self.assertTrue(check_parenthesis(correct_formula_short)) + self.assertFalse(check_parenthesis(incorrect_formula_short)) + + def test_check_formula(self): + correct_formula_short = '[a∧b!∧b]' + incorrect_formula_short = '[a∧b∧' + self.assertTrue(check_parenthesis(correct_formula_short)) + self.assertFalse(check_parenthesis(incorrect_formula_short)) + + def test_get_closed_symbol(self): + self.assertEqual(')', SupportSign.get_closed_symbol('(')) + self.assertNotEqual(']', SupportSign.get_closed_symbol('{')) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file