Ejemplo n.º 1
0
 def test_expression_evalutate(self):
     # Need to handle cases like ((1*1)*(1))
     # Stack is empty after we evaulate (1) so we see
     # the last ')', and that triggers a pop on empty stack
     exp = Expression('(((2.05+20)x(100÷2))x((5-2)+2))')
     self.assertTrue(5512.5 == exp.evaluate())
     del exp
     exp = Expression('((2.55x6.1)÷2)')
     self.assertTrue(7.777499999999999 == exp.evaluate())
     del exp
     exp = Expression('(((2.21x4.1)÷2)x0)')
     self.assertTrue(0 == exp.evaluate())
     del exp
     exp = Expression('(((1x1)x1)x1)')
     self.assertTrue(1 == exp.evaluate())
     del exp
     exp = Expression('(5+10)')
     self.assertTrue(15 == exp.evaluate())
     del exp
     exp = Expression('(((5+10)x10)÷10)')
     self.assertTrue(15 == exp.evaluate())
     del exp
     exp = Expression('((((5+10)x10)÷10)-(200.2x2))')
     self.assertTrue(-385.4 == exp.evaluate())
     del exp
Ejemplo n.º 2
0
 def __handle_expression(self, expr):
     if len(expr) > 0:
         e = Expression()
         try:
             result = e.evaluate(expr, self.vars_dict)
             if len(result) > 0:
                 print(result)
         except ValueError as e:
             print(str(e))
Ejemplo n.º 3
0
    def testMock1(self):
        expression = Expression(self.expr1)
        expression.rpn.evaluate = Mock(return_value=0)
        print('\nmock test 1')
        expression.print()
        self.assertEqual(expression.evaluate(math.pi), 0)

        expression.rpn.evaluate.assert_called_once()
        expression.rpn.evaluate.assert_called_with(x=math.pi)
Ejemplo n.º 4
0
def part1(lines):

    sum = 0
    for line in lines:
        expr = Expression(line)
        expr.parse()
        sum += expr.evaluate()

    return sum
Ejemplo n.º 5
0
    def testMock3(self):
        expression = Expression(self.expr2)

        get_rpn = Mock()
        get_rpn.side_effect = self.log_eval
        expression.rpn = get_rpn(math.pi)
        print('\nmock test 3')
        expression.print()
        self.assertEqual(expression.evaluate(math.pi), 0)
        get_rpn.assert_called_once_with(math.pi)
Ejemplo n.º 6
0
    def __init__(self, ast_node, func):
        self.func = func
        self.ast_node = ast_node
        self.asm = ""

        # Assignment
        if ast_node.token.text == "ASSIGN":
            # Get the variable and expression
            var, expr = ast_node.children
            var = func.getVar(var.text)

            # Calculate the answer
            expr = Expression(expr, func)
            factor = expr.evaluate()

            # Add the calculations to the function body
            self.asm += str(expr)
            self.asm += self.header()
            self.asm += var.assign(factor, func.prog.next_loop.next())

        if ast_node.token.text == "IF":
            cond, true_body, false_body = ast_node.children
            idnum = self.func.prog.next_loop.next()
            self.true = ".truebranch%s" % idnum
            self.false = ".falsebranch%s" % idnum
            self.asm += IF_ASM.format(
                cond=Condition(cond, self),
                id=idnum,
                true_body=''.join(
                    map(str,
                        [Statement(s, self.func)
                         for s in true_body.children])),
                false_body=''.join(
                    map(str,
                        [Statement(s, self.func)
                         for s in false_body.children])))

        if ast_node.token.text == "WHILE":
            cond, body = ast_node.children
            idnum = self.func.prog.next_loop.next()
            self.true = ".loopbegin%s" % idnum
            self.false = ".loopexit%s" % idnum
            self.asm += WHILE_ASM.format(
                id=idnum,
                cond=Condition(cond, self),
                body=''.join(
                    map(str,
                        [Statement(s, self.func) for s in body.children])))
Ejemplo n.º 7
0
    def testExpressionEvaluate1(self):
        expression = Expression(self.expr2)

        tokens = expression.rpn.tokens
        self.assertEqual(tokens, [
            '2', '*', 'sin', '(', '1', '/', '(', 'exp', '(', '3', '*', 'x',
            ')', '+', '1', ')', '-', 'tg', '(', 'x', '+', 'PI', '/', '2', ')',
            ')'
        ])

        notation = expression.rpn.notation
        self.assertEqual(notation, [
            '2', '1', '3', 'x', '*', 'exp', '1', '+', '/', 'x', 'PI', '2', '/',
            '+', 'tg', '-', 'sin', '*'
        ])

        self.assertEqual(expression.evaluate(math.pi), 1.630394220705093)
Ejemplo n.º 8
0
  def __init__(self, ast_node, func):
    self.func = func
    self.ast_node = ast_node
    self.asm = ""

    # Assignment
    if ast_node.token.text == "ASSIGN":
      # Get the variable and expression
      var, expr = ast_node.children
      var = func.getVar(var.text)

      # Calculate the answer
      expr = Expression(expr, func)
      factor = expr.evaluate()
      
      # Add the calculations to the function body
      self.asm += str(expr)
      self.asm += self.header()
      self.asm += var.assign(factor, func.prog.next_loop.next())

    if ast_node.token.text == "IF":
      cond, true_body, false_body = ast_node.children
      idnum = self.func.prog.next_loop.next()
      self.true = ".truebranch%s" % idnum
      self.false = ".falsebranch%s" % idnum
      self.asm += IF_ASM.format(
        cond = Condition(cond, self),
        id = idnum,
        true_body = ''.join(map(str, [Statement(s, self.func) for s in true_body.children])),
        false_body = ''.join(map(str, [Statement(s, self.func) for s in false_body.children]))
      )

    if ast_node.token.text == "WHILE":
      cond, body = ast_node.children
      idnum = self.func.prog.next_loop.next()
      self.true = ".loopbegin%s" % idnum
      self.false = ".loopexit%s" % idnum
      self.asm += WHILE_ASM.format(
        id = idnum,
        cond = Condition(cond, self),
        body = ''.join(map(str, [Statement(s, self.func) for s in body.children]))
      )
Ejemplo n.º 9
0
 def test_equality_false(self):
     expr = Expression('x == y')
     self.assertEqual(False, expr.evaluate(self.data), 'Should be equal')
Ejemplo n.º 10
0
 def test_two_properties_equal(self):
     expr = Expression('x == z')
     self.assertEqual(True, expr.evaluate(self.data), 'Should be equal')
Ejemplo n.º 11
0
 def test_gt_true(self):
     expr = Expression('y > x')
     self.assertEqual(True, expr.evaluate(self.data), 'Should be equal')
Ejemplo n.º 12
0
 def test_equality_true(self):
     expr = Expression('x == z')
     self.assertEqual(True, expr.evaluate(self.data), 'Should be equal')
Ejemplo n.º 13
0
class Tree:
    BOOLEAN = Lark("""
        start: orexpr
        ?orexpr: (orexpr ("+" | "|" ~ 1..2 | "or" | "OR"))? andexpr
        ?andexpr: (andexpr ("*" | "&" ~ 1..2 | "and" | "AND"))? xorexpr
        ?xorexpr: (xorexpr ("^" | "xor" | "XOR"))? xnorexpr
        ?xnorexpr: (xnorexpr ("-^" | "xnor" | "XNOR"))? norexpr
        ?norexpr: (norexpr ("-+" | "nor" | "NOR"))? nandexpr
        ?nandexpr: (nandexpr ("-*" | "nand" | "NAND"))? term
        ?term: nexpr
            | pexpr
            | IDENT
        ?nexpr: TILDE orexpr
        ?pexpr: "(" orexpr ")"
            | "[" orexpr "]"
        TILDE: "~" | "!" | "not" | "NOT"

        %import common.CNAME -> IDENT
        %import common.WS
        %ignore WS
        """)

    @staticmethod
    def __create_dict(parse_tree) -> tuple:
        """Creates a parsable JSON object that can be parsed through LogicNode and LogicVar
        objects to be used to represent a boolean expression

        :param parse_tree: A Lark grammar tree object to parse through
        :type parse_tree: lark.tree.Tree

        :return: A tuple containing the parsed expression as a JSON object and a list of variables the expression
        :rtype: tuple
        """

        variables = []

        # Check if the parse_tree is a Tree
        if isinstance(parse_tree, LarkTree):

            # Check if the expression is an orexpr (OR) or andexpr (AND)
            if parse_tree.data != "nexpr":

                # Get the left and right expression along with any new variables that may exist
                left, variables_new_left = Tree.__create_dict(
                    parse_tree.children[0])
                right, variables_new_right = Tree.__create_dict(
                    parse_tree.children[1])
                for variable in variables_new_left + variables_new_right:
                    if variable not in variables:
                        variables.append(variable)

                # Return the expression and the variables
                return {
                    "left":
                    left,
                    "operator":
                    parse_tree.data[:parse_tree.data.find("expr")].upper(),
                    "right":
                    right,
                    "has_not":
                    False
                }, variables

            # Check if the expression is an nexpr (NOT)
            else:

                # Get the expression along with any new variables that may exist
                expression, variables_new = Tree.__create_dict(
                    parse_tree.children[1])
                expression["has_not"] = not expression["has_not"]
                for variable in variables_new:
                    if variable not in variables:
                        variables.append(variable)

                # Return the expression and the variables
                return expression, variables

        # The parse_tree is an ident (Variable)
        return {
            "value": parse_tree.value,
            "has_not": False
        }, [parse_tree.value]

    def __init__(self, expr: str):

        # Try to parse the expression
        try:
            self.__root, self.__variables = Tree.__create_dict(
                Tree.BOOLEAN.parse(expr).children[
                    0]  # This ignores the "start" Tree
            )
            self.__variables.sort()

            # Check if the expression is a LogicNode or LogicVar
            if "value" in self.__root:
                # noinspection PyTypeChecker
                self.__root = Variable(json=self.__root)
            else:
                # noinspection PyTypeChecker
                self.__root = Expression(json=self.__root)

        # If parsing the expression fails, the boolean expression is invalid
        except Exception:
            raise ValueError("The expression given is invalid")

    def __str__(self):
        if isinstance(self.__root, Expression):
            return str(self.__root)[1:-1]
        return str(self.__root)

    # # # # # # # # # # # # # # # # # # # #
    # Getters
    # # # # # # # # # # # # # # # # # # # #

    def get_variables(self) -> list:
        """Returns a list of variables used in this Tree"""
        return self.__variables

    def get_table(self, as_list: bool = False) -> Union[str, list]:
        """Returns a truth table of the root expression of this Tree

        :param as_list: Whether or not to return the truth table as a list of lines
        :type as_list: bool
        """

        # Create the header row which holds the variables and result like the following:
        #   | a | b | c | (a * b) + c |
        header = "| {} | {} |".format(" | ".join(self.get_variables()),
                                      str(self))

        # Create the separator row which uses symbols to look like the following:
        #   +---+---+---+-------------+
        separator = "+-{}-+-{}-+".format(
            "-+-".join(["-" * len(var) for var in self.get_variables()]),
            "-" * len(str(self)))

        # Create the truth values and their evaluations which just consists of 1's and 0's
        #   to look like the following:
        #   | 0 | 1 | 0 |      0      |
        evaluations = self.evaluate()
        values = "\n".join([
            "| {} | {} |".format(
                " | ".join([
                    ("1" if evaluation["truth_values"][value] else "0").center(
                        len(value)) for value in evaluation["truth_values"]
                ]), ("1" if evaluation["truth_value"] else "0").center(
                    len(str(self)))) for evaluation in evaluations
        ])

        if as_list:
            return [header, separator, values]
        return f"{header}\n{separator}\n{values}"

    # # # # # # # # # # # # # # # # # # # #
    # Evaluation Methods
    # # # # # # # # # # # # # # # # # # # #

    def evaluate(self) -> list:
        """Evaluates the root of this Tree to get boolean values where the root expression
        is 1 or 0

        :return: A list of evaluations and their truth values that make up the evaluation
        """

        # Iterate through all the integer values from 2 ** len(variables)
        evaluations = []
        for binary in range(2**len(self.get_variables())):

            # Create a JSON object for each variable and whether or not this variable
            #   is true at the current binary value
            truth_values = {
                self.get_variables()[i]:
                binary & (1 << (len(self.get_variables()) - 1 - i)) != 0
                for i in range(len(self.get_variables()))
            }

            # Add the evaluation for this binary value to the list of evaluations
            evaluations.append({
                "truth_values":
                truth_values,
                "truth_value":
                self.__root.evaluate(truth_values)
            })
        return evaluations

    def simplify(self, get_minterm: bool = None) -> 'Tree':
        """Simplifies the boolean expression at the root
        and returns the most simplified expression obtained
        from either minterm or maxterm evaluation.

        :param get_minterm: Whether to get the minterm expression or maxterm expression.
            By default, the function returns the shortest of the two
        :type get_minterm: bool

        :return: The simplified boolean expression inside a Tree
        :rtype: Tree
        """

        # Get the minterm and maxterm true-at values
        #   Note that a minterm expression is true where the expression evaluates
        #   to true (1) and a maxterm expresion is true where the expression evaluates
        #   to false (0)
        evaluations = self.evaluate()
        true_at_minterms = [
            decimal for decimal in range(len(evaluations))
            if evaluations[decimal]["truth_value"]
        ]
        true_at_maxterms = [
            decimal for decimal in range(len(evaluations))
            if not evaluations[decimal]["truth_value"]
        ]

        minterm_qm = QM(self.get_variables(), true_at_minterms).get_function()
        maxterm_qm = QM(self.get_variables(),
                        true_at_maxterms,
                        is_maxterm=True).get_function()

        tree_minterm = Tree(
            minterm_qm) if minterm_qm not in "01" else minterm_qm
        tree_maxterm = Tree(
            maxterm_qm) if maxterm_qm not in "01" else maxterm_qm

        if get_minterm is not None:
            if get_minterm:
                return tree_minterm
            return tree_maxterm
        return min(tree_minterm, tree_maxterm, key=lambda qm: len(str(qm)))

    def functional(self) -> str:
        """Returns this Tree object in a functional notation

        For example:
            - ``a or b and c`` is functionally equivalent to ``and(or(a, b), c)``
        """
        return self.__root.functional()
Ejemplo n.º 14
0
def question1(expr, x):
    expr = Expression(expr)
    return expr.evaluate(x)
Ejemplo n.º 15
0
class GUI:
    def __init__(self, title="Python Calculator", size="290x230"):
        self._gui = Tk()
        self._title = title
        self._size = size
        placeholder = StringVar().set("Enter your expression")
        self._field = Entry(self._gui, textvariable=placeholder)
        self._expression = None
        self._positions = {
            ' ( ': (2, 0),
            ' ) ': (2, 1),
            ' CE ': (2, 2),
            ' - ': (2, 3),
            ' 7 ': (3, 0),
            ' 8 ': (3, 1),
            ' 9 ': (3, 2),
            ' ÷ ': (3, 3),
            ' 4 ': (4, 0),
            ' 5 ': (4, 1),
            ' 6 ': (4, 2),
            ' x ': (4, 3),
            ' 1 ': (5, 0),
            ' 2 ': (5, 1),
            ' 3 ': (5, 2),
            ' + ': (5, 3),
            ' 0 ': (6, 0),
            ' . ': (6, 2),
            ' = ': (6, 3),
        }

    def create(self):
        self._configure()
        self._create_input_field()
        self._create_buttons()
        self._gui.mainloop()

    def _configure(self):
        self._gui.configure(background="black")
        self._gui.title(self._title)
        self._gui.geometry(self._size)

    def _create_input_field(self):
        self._field.grid(rowspan=2, columnspan=4, ipadx=49, ipady=12)

    def _create_buttons(self):
        for buttonText in self._positions.keys():
            button = Button(
                self._gui,
                text=buttonText,
                height=2,
                width=1,
                command=lambda action=buttonText: self._button_action(action))
            colspan = 2 if buttonText == " 0 " else 1
            # sticky removes extra space btwn buttons
            button.grid(row=self._positions[buttonText][0],
                        column=self._positions[buttonText][1],
                        columnspan=colspan,
                        sticky="nsew")

    def _button_action(self, action):
        action = action.strip()
        if action == '=':
            final_expression = self._field.get()
            if final_expression == '' or '(' not in final_expression or ')' not in final_expression:
                self._field.delete(0, END)
                self._field.insert(0, 'Invalid Expression')
            else:
                self._expression = Expression(final_expression)
                self._field.delete(0, END)
                self._field.insert(0, self._expression.evaluate())
                del self._expression
        elif action == 'CE':
            current = str(self._field.get())[:-1]
            self._field.delete(0, END)
            self._field.insert(0, str(current))
        else:
            current = self._field.get()
            self._field.delete(0, END)
            self._field.insert(0, str(current) + str(action))