예제 #1
0
def not_handler(formula):
    ''' (str) -> FormulaTree
    REQ: fomula[0] == '-'
    Returns the FormulaTree where NOT is the root of the tree
    Returns None iff the NOT formula is invalid

    >>> not_handler('-(x+y)')
    NotTree(OrTree(Leaf('x'), Leaf('y')))
    >>> None == not_handler('-+x')
    True
    '''
    # A formula with a Not in front has 4 cases
    # case 1 after the NOT there is a variable
    if formula[1] in VARIABLES:
        # then return the NotTree + the Leaf
        tree = NotTree(Leaf(formula[1]))
    # case 2 after the NOT there is a left bracket
    elif formula[1] is LEFT_P:
        # then call binary_handler
        tree = binary_handler(formula[1:])
        # check if the binary tree is valid if it is not we do not evaluate it
        if tree is not None:
            # not the resulting Binary tree
            tree = NotTree(tree)
    # case 3 after the NOT there is another NOT bracket
    elif formula[1] is NOT:
        # then call NOT Handler again
        tree = not_handler(formula[1:])
        # same case applies
        if tree is not None:
            tree = NotTree(tree)
    # anything else and the formula rules are violated so return None
    else:
        tree = None
    return tree
예제 #2
0
def build_tree_helper1(formula):
    '''(list)-> list
    Return the formula tree in the list
    >>>build_tree_helper1(['(', 'x', '*', 'y', ')'])
    [AndTree(Leaf('x'), Leaf('y'))]
    >>>build_tree_helper1(['(', '(', 'x', '+', 'y', ')', '*', 
    '(', '-', 'x', '*', 'y', ')', ')'])
    [AndTree(OrTree(Leaf('x'), Leaf('y')), AndTree(NotTree(Leaf('x')), Leaf('y')))]
    '''
    # return itself if just a variable inside list
    if len(formula) == 1:
        return formula
    else:
        # find the first ')'
        for i in range(len(formula)):
            if formula[i] == ')':
                break
        # find the first'(' in the list from the first ')'
        for k in range(i, -1, -1):
            if formula[k] == '(':
                break
        # find the AND or OR sign between the '()'
        for m in range(k, i + 1):
            if (formula[m] == '*') or (formula[m] == '+'):
                break
        # set the default of left and right child as Leaf
        left_node = Leaf(formula[m - 1])
        right_node = Leaf(formula[i - 1])
        # if the right or left child is already a formulatree then
        # itself is the child and it is not leaf
        if type(formula[m - 1]) != str:
            left_node = formula[m - 1]
        if type(formula[i - 1]) != str:
            right_node = formula[i - 1]
        # find NOT sign if it exist and call Not_tree_helper() function
        # to converte it to formatetree
        if ((formula[m - 2]) == '-'):
            left_node = NotTree(Not_tree_helper(formula[k + 2:m]))
        if ((formula[m + 1]) == '-'):
            right_node = NotTree(Not_tree_helper(formula[m + 2:i]))
        # find the sign and use the right formatetree class to converte it
        if (formula[m] == '*'):
            formula[k:i + 1] = [AndTree(left_node, right_node)]
            formula = build_tree_helper1(formula[:])
        elif (formula[m] == '+'):
            formula[k:i + 1] = [OrTree(left_node, right_node)]
            formula = build_tree_helper1(formula[:])
        return formula
예제 #3
0
def build_tree(formula):
    '''(str of formula) -> obj of FormulaTree
    This function takes in a string of formula and returns the FormulaTree
    that represents <formula> if it is a valid formula.
    Return None if the formula is not valid
    >>> build_tree('x')
    Leaf('x')
    >>> build_tree('-x')
    NotTree(Leaf('x'))
    >>> build_tree('(x+y)')
    OrTree(Leaf('x'), Leaf('y'))
    '''
    # default the result to be None
    # if it doesn't change the result (not go into any if statements),
    # then formula is invalid
    res = None
    # check if the formula is an empty string, b/c I need to use formula[0]
    if formula == '':
        # formula is invalid
        # do nothing since setted default of the result
        pass
    # base case when there is only one valid variable inside, like: 'x'
    elif len(formula) == 1 and formula.islower():
        # then it is a Leaf
        res = Leaf(formula)
    # check if the formula starts with '-'
    elif formula[0] == '-':
        # then it is a NotTree
        # keep recursing the formula after '-'
        res = NotTree(build_tree(formula[1:]))
    # check if the formula starts with '('
    elif formula[0] == '(' and formula[-1] == ')':
        # then it is an OrTree or AndTree
        # use get_root_index helper, find the index of the root in formula
        index = get_root_index(formula)
        # if we find the root (valid formula)
        if index != len(formula) - 1:
            # if the root is '+'
            if formula[index] == '+':
                # then it is an OrTree
                # split the formula into left child and right child
                # left child is on the left hand side of the '+' and vice versa
                res = OrTree(build_tree(formula[1:index]),
                             build_tree(formula[index + 1:-1]))
            # if the root is '*'
            elif formula[index] == '*':
                # then it is an AndTree
                # split the formula into left child and right child
                # left child is on the left hand side of the '*' and vice versa
                res = AndTree(build_tree(formula[1:index]),
                              build_tree(formula[index + 1:-1]))
    # if result have changed, but any of its child is None (formula invalid)
    if res and None in res.get_children():
        # adjust the result to be None again
        res = None
    # return the result
    return res
예제 #4
0
def build_tree(formula):
    '''(str) -> FormulaTree
    If the str <formula> meets the criteria
    of being a valid formula, create and return
    the FormulaTree representation of the string.
    Otherwise returns None.
    REQ: formula is not empty
    >>> build_tree('x')
    Leaf('x')
    '''
    # Check if formula is valid
    if is_valid(formula):
        # Base case when length of list is one
        if len(formula) == 1:
            tree = Leaf(formula)
        # Second base case is special case of the NotTree
        elif formula[0] == '-':
            # Recursively create the rest of the formula '--(..)'
            if formula[1] == '-':
                tree = NotTree(build_tree(formula[1:]))
            # Create the NotTree for the rest of the bracket '-(..)'
            elif formula[1] == '(':
                tree = NotTree(build_tree(formula[1:formula.index(')') + 1]))
            # Create the NotTree only for the variable
            elif formula[1].islower():
                tree = NotTree(build_tree(formula[1]))
        else:
            # Get the root and the index of the root
            (r, index) = find_root(formula)
            # Build the 'And' and/or 'Or' trees respectively
            if r == '*':
                tree = AndTree(build_tree(formula[1:index]),
                               build_tree(formula[index + 1:len(formula) - 1]))
            elif r == '+':
                tree = OrTree(build_tree(formula[1:index]),
                              build_tree(formula[index + 1:len(formula) - 1]))
    else:
        tree = None

    return tree
예제 #5
0
def build_tree(formula):
    if len(formula) is 1 and formula in "abcdefghijklmnopqrstuvwxyz":
        node = Leaf(formula)

    else:
        if len(formula) > 1 and formula[0] == "(" and formula[-1] == ")":
            formula = formula[1:-1]
            connective_found = False
            counter = 0
            found_L_brac = False
            while not connective_found:

                if counter >= len(formula):
                    node = None
                    connective_found = True

                elif found_L_brac and formula[counter] is ")":
                    found_L_brac = False

                elif formula[counter] is "(":
                    found_L_brac = True

                elif formula[counter] in "+" and not found_L_brac:

                    (node) = OrTree(build_tree(formula[:counter]), build_tree(
                        formula[counter + 1:]))
                    if (node.get_children())[0] is None or node.get_children()[1] is None:
                        node = None
                    connective_found = True
                elif formula[counter] in "*" and not found_L_brac:

                    (node) = AndTree(build_tree(formula[:counter]), build_tree(
                        formula[counter + 1:]))
                    if (node.get_children())[0] is None or node.get_children()[1] is None:
                        node = None
                    connective_found = True
                counter += 1

        elif len(formula) >= 2 and formula[0] is "-":
            if formula[1] not in "abcdefghijklmnopqrstuvwxyz-(":
                connective_found = True
                node = None
            else:
                node = NotTree(build_tree(formula[1:]))
                if (node.get_children())[0] is None:
                    node = None

        else:
            node = None
    return (node)
예제 #6
0
def Not_tree_helper(formula):
    '''(list) -> FormateTree
    Return the formateTree form by inputing just the NOT signs and it variable
    
    >>>Not_tree_helper(['-', '(', 'x', '*', 'y', ')'])
    Leaf('y')
    '''
    # find all '-'s and usinf recursion to get the Formulatree format
    for n in range(0, len(formula), 1):
        if formula[n] == '-':
            result = NotTree(Not_tree_helper(formula[n + 1:]))
        elif (type(formula[n])) != str:
            result = formula[n]
        elif (formula[n].isalpha() is True):
            result = Leaf(formula[n])
    return result
예제 #7
0
def build_tree(formula):
    '''
    (string) -> FormulaTree
    This function takes in a string representation of formula.
    Returns the FormulaTree which represents the given formula if vaild.
    Otherwise None is returned.
    REQ: the formula given must be a string representation
    '''
    # idea: this functon use recursion to be efficient
    #       apart the formula into small parts and build each leaf
    '''
    this is a fail part for testing valid formula
    symbol_list = "xyz+-*()"
    for char in formula:
        if symbol_list.find(char) != -1:
            pass
        else:
            return None
    '''
    # the base case of a leaf on the tree is that only one lowercase letter
    if len(formula) == 1 and formula[0].islower():
        # build one leaf of the tree
        return Leaf(formula)
    # if the formula starts with "-", it means a not tree
    elif formula[0] == "-":
        # build a NotTree and send the rest of the formula into the recursion
        return NotTree(build_tree(formula[1:]))
    # for the symbol "+", "*", there must be a blanket before and after them
    elif formula[0] == "(":
        # here calls a helper function to find the place where the first symbol in the blanket is
        index = _get_place(formula)
        # build an AndTree, remove the blanket
        # apart the formula to two parts: before the "*" and after
        # send both parts into the recursion to get result for the AndTree
        if formula[index] == "*":
            return AndTree(build_tree(formula[1:index]),
                           build_tree(formula[index + 1:-1]))
        # same step of "+" as the "*" above
        elif formula[index] == "+":
            return OrTree(build_tree(formula[1:index]),
                          build_tree(formula[index + 1:-1]))
    # 'else' means the formula is not valid, therefore None is returned as required
    else:
        return None
def build_tree(formula):
    '''(str) -> FormulaTree
    given a string formula, return the FormulaTree representation of the
    formula if it is a valid formula. Otherwise return None. *, +, - represent
    AND OR NOT respectively. A node that represents * or + has 2 child nodes,
    which in turn represent the two subformulas that are ANDed or ORed to
    form the larger formula. A node that represents - has one child node,
    which in turn represents the formula that is NOTed.
    REQ:
    - formula is not empty
    - the variables in the formula must be lower case
    - the representation of the formula must contain enough paranthesis(except
    for '-'
    >>> build_tree('X')
    None
    >>> build_tree('x*y')
    None
    >>> build_tree('-(x)')
    None
    >>> build_tree('(x+(y)*z)')
    None
    >>> build_tree('((-x+y)*-(-y+x))')
    AndTree(OrTree(NotTree(Leaf('x')), Leaf('y')),
                             NotTree(OrTree(NotTree(Leaf('y')), Leaf('x'))))
    >>> build_tree('(x*y)')
    AndTree(Leaf('x'), Leaf('y'))
    >>> build_tree('-y')
    Leaf('y')
    >>> build_tree('x')
    Leaf('x')
    >>> build_tree('v')
    Leaf('v')
    >>>build_tree('((x+y)*(z+-k))')
    AndTree(OrTree(Leaf('x'), Leaf('y')), OrTree(Leaf('z'),
                                                        NotTree(Leaf('k'))))
    '''
    try:
        # set the upper case checker as False
        upper = False
        # create lists
        tokenlist = []
        var = []

        # loop through the formula do determine the symbols
        for element in formula:
            # if the formula does not contain a paranthesis:
            if '(' not in formula:
                return None
            # if the element is '-'
            elif element == "-":
                # append the character to the list
                tokenlist.append(element)
            # if the element is '+'
            elif element == "+":
                # append the character to the list
                tokenlist.append(element)
            # if the element is '('
            elif element == "(":
                # append the character to the list
                tokenlist.append(element)
            # if the element is '*'
            elif element == "*":
                # append the character to the list
                tokenlist.append(element)
            # if the element is ')'
            elif element == ")":
                # remove and return the last object from the list and set it
                # as a new variable
                token = tokenlist.pop()
                # loop through that variable
                while token != '(':
                    # if the object is -
                    if token == "-":
                        # set the object as a variable, return the last object
                        # from the list to determine the character
                        var_formula = var.pop()
                        # append it to the list by using NotTree since the
                        # object has '-'
                        var.append(NotTree(var_formula))
                        token = tokenlist.pop()
                    # if the object is *
                    elif token == "*":
                        # set the left side of the *
                        var_formula = var.pop()
                        # now set the right side of the *
                        var_2 = var.pop()
                        # append it to the list by using And Tree class, since
                        # the symbol is '*'
                        var.append(AndTree(var_2, var_formula))
                        # remove and return the last item from the list
                        token = tokenlist.pop()
                    # if the object is '+'
                    elif token == "+":
                        # if the last item is '-'
                        if tokenlist[-1] == "-" and tokenlist[-1] is not None:
                            # set the left side of the '+'
                            var_formula = var.pop()
                            # set the right side of the '+'
                            var_2 = var.pop()
                            # since the object is '-', set it as NotTree
                            var_2 = NotTree(var_2)
                            # append it to the list by using OrTree class
                            var.append(OrTree(var_2, var_formula))
                            # pop the object twice/ remove and return the last
                            # item do it twice because of the '-' symbol
                            token = tokenlist.pop()
                            token = tokenlist.pop()
                        # otherwise
                        else:
                            # set the left side
                            var_formula = var.pop()
                            # set the right side
                            var_2 = var.pop()
                            # append it to the list by using OrTree class
                            var.append(OrTree(var_2, var_formula))
                            # remove and return the last object in the list
                            token = tokenlist.pop()

            # if the element is a alphabetical character,
            elif element.isalpha() is True:
                # if the character is lower,
                if element.islower() is True:
                    # then append to the list as 'Leaf'
                    var.append(Leaf(element))
                # otherwise return None
                else:
                    upper = True
                    return None
            # if the character is ')'
            elif element == ")":
                # remove and return the last object from token list and set it
                # as a variable
                token = tokenlist.pop()
                # loop through the list
                while token != '(':
                    # if the object is '-'
                    if token == "-":
                        # remove and return the last object, that is next to
                        # the '-' sign.
                        var_formula = var.pop()
                        # append the charachter as a NotTree because of the
                        # '-' sign
                        var.append(NotTree(var_formula))
                        #  set a new variable that is the last object
                        # from the list
                        token = tokenlist.pop()
                    # if the object is '*'
                    elif token == "*":
                        # remove and return the last object, the right side of
                        # the '*'
                        var_formula = var.pop()
                        # now the left side of the '*' sign.
                        var_2 = var.pop()
                        # append the left side and right side by using AndTree
                        # class
                        var.append(AndTree(var_2, var_formula))
                        token = tokenlist.pop()

                    # if the object is '+'
                    elif token == "+":
                        # if the last item is not none and '-' in the list,
                        if tokenlist[-1] is not None and tokenlist[-1] == "-":
                            # remove and return the last object, the right side
                            # of the '+'
                            var_formula = var.pop()
                            # now do the same process for the left side
                            var_2 = var.pop()
                            # since the item is '-', we need to assign it as
                            # NotTree
                            var_2 = NotTree(var_2)
                            # append the left side and right side by using
                            # OrTree class
                            var.append(OrTree(var_2, var_formula))
                            # pop the item twice/ remove and return the last
                            # item do it twice because of the '-' symbol
                            token = tokenlist.pop()
                            token = tokenlist.pop()
                        # otherwise
                        else:
                            # set the right side of the Or Tree
                            var_formula = var.pop()
                            # set the left side of the Or Tree
                            var_2 = var.pop()
                            # append the left side and right side by using
                            # OrTree
                            var.append(OrTree(var_2, var_formula))
                            # remove and return the last item in the list
                            token = tokenlist.pop()

        # return the first item in the list
        return var[0]
    except IndexError:
        return None
예제 #9
0
def subtree_helper(formula):
    ''' (str, int) -> FormulaTree
    Returns the FormulaTree built for the formula <formula>
    REQ: length of the formula >= 1
    >>> subtree = subtree_helper('(a+b)')
    >>> print(subtree)
    'OrTree(Leaf('a'), Leaf('b'))'
    >>> subtree = subtree_helper('(-a)')
    >>> print(subtree)
    None
    >>> subtree = subtree_helper('(((a+b)+c)*c)')
    >>> print(subtree)
    AndTree(OrTree(OrTree(Leaf('a'), Leaf('b')), Leaf('c')), Leaf('c'))
    '''
    # initialize your tree as none
    tree = None
    # 4 base cases:
    # 1- if the formula length is 0
    if (len(formula) == 0):
        tree = None
    # 2- check if its a just a variable (and lower case). If it is, then make
    # that into a leaf
    elif (len(formula) == 1) and (formula[0].isalpha()) and \
         (formula[0].islower()):
        tree = Leaf(formula[0])
    # 3- if the formula doesn't start with a bracket or a
    # not operator (and isn't alpha + lower case either -> checked that in the
    # previous condition) then the tree is invalid -> return none
    elif not (formula.startswith('(') or formula.startswith('-')):
        tree = None
    # 4- check if its a negator. If it is, make a not tree and send the rest of
    # the string as a recursive call
    elif (formula[0] == '-'):
        # make the child of the Not Tree
        child = subtree_helper(formula[1:])
        # if the child is a valid formula, then make a Not tree, else make the
        # tree None since the child is an invalid sub tree
        if child:
            tree = NotTree(child)
        # else the child is invalid, therefore the whole tree becomes invalid
        else:
            tree = None
    # else if it starts with an open bracket and ends with a closed bracket
    # then we have an AND tree or an OR tree
    elif (formula[0] == '(') and (formula[-1] == ')'):
        # then find the root of the tree (find root checks if we have a valid
        # root, otherwise would return none)
        root_index = find_root(formula)
        # if the root exists in the formula
        if (root_index is not None):
            # then make the left sub tree by making a recursive call on
            # everything from the left +1 (not including the bracket) to the
            # root
            left_subtree = subtree_helper(formula[1:root_index])
            # similarly, make the right sub tree by making a recursive call on
            # everything from one character after the root till one index
            # before the string ends (we don't want the bracket, because it
            # will make the child invalid)
            right_subtree = subtree_helper(formula[root_index + 1:-1])
            # check if the sub trees are valid sub trees, if they are then
            if (left_subtree and right_subtree):
                # (finally!) make the tree. If the root is a + sign make an OR
                # tree using the subtrees we have made
                if (formula[root_index] == '+'):
                    tree = OrTree(left_subtree, right_subtree)
                # else if its a * sign make an add tree using the sub trees we
                # have made
                elif (formula[root_index] == '*'):
                    tree = AndTree(left_subtree, right_subtree)
                # if its neither (and we handled the case where we have -) then
                # the tree is invalid because of an invalid symbol or placing
                # an valid symbol some where wrong.
                # therefore the whole tree becomes invalid/none
                else:
                    tree = None
            # else the left and right sub trees are not valid sub trees. hence
            # making the entire tree invalid (aka none)
            else:
                tree = None
        # if the root does not exist, then there is no tree to make. Hence the
        # tree becomes none
        else:
            tree = None
    # else, the string is too complicated! just leave it as it is, and hope the
    # marker figures it out, lol
    # jk
    # else, the string is complicated.
    else:
        # so your find the root of the formula and split it from there.
        root_index = find_root(formula)
        # if there is a root in the formula
        if (root_index is not None):
            # make a recursive call on everything left from the root and
            left_subtree = subtree_helper(formula[:root_index])
            # make a recursive call on everything from the right of the root
            right_subtree = subtree_helper(formula[root_index + 1:])
            # if the left and right sub trees are valid
            if (left_subtree and right_subtree):
                # then make the tree based on the root
                # if it is a +, then make an or tree
                if (formula[root_index] == '+'):
                    tree = OrTree(left_subtree, right_subtree)
                # else if its a *, then make an and tree
                elif (formula[root_index] == '*'):
                    tree = AndTree(left_subtree, right_subtree)
                # else the operator is invalid, hence making the entire tree
                # invalid/None
                else:
                    tree = None
            # else the left or right subtrees are invalid -> the whole tree is
            # invalid
            else:
                tree = None
        # if the root does not exist, then there is no tree to make. Hence the
        # tree becomes none
        else:
            tree = None
    # return the tree
    return tree
예제 #10
0
def build_tree(formula):
    '''(str) -> FormulaTree
    Builds a tree out of the formula given to the function an returns an obj
    representation of it. A proper tree does not have any capitalized
    variables, any extraneous parenthesses, unmatches parenthesses, or missing
    parenthesses.
    >>> build_tree('X')
    None
    >>> build_tree('(x*y)')
    AndTree(Leaf('x'), Leaf('y'))
    >>> build_tree("(x+y*(z))")
    None
    >>> build_tree("((-x+y)*-(-y+x))")
    AndTree(OrTree(NotTree(Leaf('x')), Leaf('y')),
    NotTree(OrTree(NotTree(Leaf('y')), Leaf('x'))))
    '''
    # Set an arbitrary tree solely for error detection
    tree = NotTree(None)
    # Base case when the formula is empty
    if (len(formula) == 0):
        tree = None
    # Base case when the formula is just a variable/leaf
    elif (len(formula) == 1 and formula.islower()):
        tree = Leaf(formula)
    # Base case when the formula has a Not connective
    elif (len(formula) >= 2 and formula.startswith('-')):
        tree = NotTree(build_tree(formula[1:]))
    else:
        # Set the variables required for the while loop
        # i is the index, o_p_c stands for Open Parenthesses Count and
        # root found confirms when the outermost root is found, this variable
        # reduces the amount of iteration increasing overall efficency
        i, o_p_c, root_found = 0, 0, False
        # Loop through the entire string. The outermost root is found when the
        # o_p_c is 1; once its found, loop cancels. If the outermost root isn't
        # found by some unrecognizable form, the loop cancels and the tree
        # stays as the same arbitrary tree assigned earlier.
        while (root_found is False and i < len(formula)):
            # Increment o_p_c by 1 if an open parenthesses is found
            if (formula[i] == '('):
                o_p_c += 1
            # Decrement o_p_c by 1 if a closed parenthesses is found
            elif (formula[i] == ')'):
                o_p_c -= 1
            # Recur over the outermost Or connective when found; root is found
            elif (formula[i] == '+' and o_p_c == 1):
                tree, root_found = OrTree(build_tree(formula[1:i]),
                                          build_tree(formula[i + 1:-1])), True
            # Recur over the outermost And connective when found; root is found
            elif (formula[i] == '*' and o_p_c == 1):
                tree, root_found = AndTree(build_tree(formula[1:i]),
                                           build_tree(formula[i + 1:-1])), True
            # Increment index by 1
            i += 1
    # If statement to know when the tree is in an unrecognizable form
    if (tree is None):
        tree = None
    elif (None in tree.get_children()):
        tree = None
    # Return the built tree
    return tree
예제 #11
0
def validation_1(formula, index, length):
    '''(int) -> tuple of (FormulaTree, int)
    Given a formula, a index and the length the function check whether
    it is valid recursively. Then build it as formulatree, return the tuple of
    formula tree and its index if it is valid, otherwise, return None

    >>> formula = "x+(-y)"
    >>> index = 0
    >>> length = 6
    >>> validation_1(formula, index, length)
    None
    >>> formula = "-----a"
    >>> index = 0
    >>> length = 6
    >>> validation_1(formula, index, length)
    NotTree(NotTree(NotTree(NotTree(NotTree(Leaf('a'))))))
    >>> formula = "x"
    >>> index = 0
    >>> length = 1
    >>> validation_1(formula, index, length)
    Leaf('x')
    >>> formula = "-y"
    >>> index = 0
    >>> length = 2
    >>> validation_1(formula, index, length)
    NotTree((Leaf('y'))
    '''
    # define a result which equal to None
    result = None
    # if the it is not the end of formula according to the index
    if index != length:
        # get the letter of the string in the index
        ch = formula[index]
        # check whether it is in lower letters
        if ch in 'abcdefghijklmnopqrstuvwxyz':
            # if it is build it as leaf, and continuethe index for checking
            result = Leaf(ch), index + 1
        # else if the letter of string in the index is the left bracket
        elif ch == '(':
            # call the validation2 function to check whether the stuff in the
            # brackets is valid
            ret = validation_2(formula, index + 1, length)
            # if it is valid
            if ret is not None:
                # get the tuple of the operand and the index
                operand, index = ret
                # if it is not the end of formula
                if index != length:
                    # if the letter of string in the index is right bracket
                    if formula[index] == ')':
                        # get the operand and continue index for checking
                        result = operand, index + 1
        # else if letter of string in the index is "-"
        elif ch == '-':
            # recurse the validation1 for checking whether the stuff is valid
            # after the "-" symbol
            ret = validation_1(formula, index + 1, length)
            # if it is valid
            if ret is not None:
                # get the tuple of operand and the index
                operand, index = ret
                # build the operand as not tree and make tuple with
                # current index
                result = NotTree(operand), index

    return result
예제 #12
0
def build_tree(formula):
    ''' (str) -> FormulaTree
    Returns True if the <formula> is valid. Else returns False.
    How is a formula valid?
    > all the variable names should be lower case
    > there can be only be 26 unique varaibles, aka the total number of
    alphabets in english language
    > the only valid operators are the AND ('*'), the NOT ('-') and the
    OR ('+') operator.
    > when using the AND ('*') and OR ('+') operator, it is necessary to use
    parentheses. e.g. '(x*y)' is a valid formula, but 'x*y' is not a valid
    formula because it is missing parentheses
    > Parentheses are not needed when using the NOT ('-') operator. e.g. '-x'
    is a valid formula, but '-(x)' is not a valid formula because it has
    extraneous brackets
    > the simplest formula is of a string containing just one variable. e.g.
    'x' is the simplest formula
    Any formula that does not follow the above rules is an invalid formula
    REQ: <formula> can not be an empty string
    REQ: <formula> only has symbols '*', '-', '+' and all the lower case
    letters from a - z
    >>> build_tree('-x')
    NotTree(Leaf('x'))
    >>> build_tree('-(x)')
    None
    >>> build_tree('-(x*y)')
    NotTree(AndTree(Leaf('x'), Leaf('y')))
    >>> build_tree('x*y')
    None
    >>> build_tree('x')
    Leaf('x')
    '''
    # initialize an empty tree
    tree = None
    # find the root using the root helper function
    root_index = find_root(formula)
    # if the root exists,
    if root_index is not None:
        # then see if the root is an OR operator
        if (formula[root_index] == '+'):
            # make the left sub tree (everything from the start to one index
            # before the root
            left_tree = subtree_helper(formula[1:root_index])
            # make the right subtree (everything from one index after the root
            # to the end)
            right_tree = subtree_helper(formula[root_index + 1:-1])
            # if the left sub tree or the right sub tree is not empty (meaning
            # its not invalid), then make an OR tree
            if (left_tree and right_tree):
                tree = OrTree(left_tree, right_tree)
            # else, left sub tree or right sub tree is invalid and therefore
            # makes the entire tree invalid. Hence the tree is none
            else:
                tree = None
        # else check if the root is an AND operator
        elif (formula[root_index] == '*'):
            # make the left sub tree (everything from the start to one index
            # before the root
            left_tree = subtree_helper(formula[1:root_index])
            # make the right subtree (everything from one index after the root
            # to the end)
            right_tree = subtree_helper(formula[root_index + 1:-1])
            # if the left sub tree or the right sub tree is not empty (meaning
            # its not invalid), then make an OR tree
            if (left_tree and right_tree):
                tree = AndTree(left_tree, right_tree)
            # else, left sub tree or right sub tree is invalid and therefore
            # makes the entire tree invalid. Hence the tree is none
            else:
                tree = None
        # else if the root is a NOT operator
        elif (formula[root_index] == '-'):
            # make the sub tree (everything from the root_index + 1 to the end
            # since not only has one child/ excluding the not operator)
            child = subtree_helper(formula[root_index + 1:])
            # if the child is a valid tree
            if child:
                # then make a Not tree
                tree = NotTree(child)
            # else, the child is not valid, making the whole tree invalid/none
            else:
                tree = None
        # if the operator is not from +, -, *, then the operator is invalid
        # making the entire tree invalid
        else:
            tree = None
    # else if the str a lower case alphabet of len 1, then make it into a leaf
    # and return that as a tree
    elif (len(formula) == 1) and (formula.isalpha()) and (formula.islower()):
        tree = Leaf(formula)
    # else if the root does not exist, then the tree is invalid
    else:
        tree = None
    # return the tree that was built (or built but destroyed by the multiple
    # checks, oof!)
    return tree
예제 #13
0
def build_tree(formula):
    '''
    (string) -> formula_tree
    This function takes a string and puts it
    into a proper formula tree. If the string
    is not in the correct format, then return
    None.

    >>> build_tree('-x')
    NotTree(Leaf('x'))
    >>> build_tree('((-x+y)*-(-y+x))')
    AndTree(OrTree(NotTree(Leaf('x')), Leaf('y')), \
    NotTree(OrTree(NotTree(Leaf('y')), Leaf('x'))))
    >>> x = build_tree('Pancer Square')
    >>> x == None
    True
    '''
    # find length of formula
    length = len(formula)

    # base case, if only one character
    if (length == 1):
        # return a leaf
        return Leaf(formula)
    # if a not symbol occurs
    if (formula[0] == "-"):
        # create NotTree and continue building
        return NotTree(build_tree(formula[1:]))

    # this means that the root will either be
    # a AndTree or OrTree
    if (formula[0] == '('):

        # create counters and initialize variables
        counter = 0
        root = ''
        # to use in while loop
        x = 0
        # this loop finds the root
        while x < len(formula) and root == '':

            # subtract 1 if rigth bracket is found
            if formula[x] == ")":
                counter = counter - 1

            # if a not symbol is used
            if formula[x] == '-':
                x = x + 1
            # add 1 if left bracket is found
            if formula[x] == "(":
                counter = counter + 1

            # if the counter reaches 1
            elif counter == 1:
                root = formula[x + 1]
            x = x + 1

        # if root is a +
        if root == '+':
            return OrTree(build_tree(formula[1:x]),
                          build_tree(formula[x + 1:-1]))

        # if the root is a *
        if root == '*':
            return AndTree(build_tree(formula[1:x]),
                           build_tree(formula[x + 1:-1]))

    # in case of incorrect format
    if formula[0].isalpha() is False:
        return None
예제 #14
0
def build_tree(formula):
    '''(str) -> FormulaTree
    Takes in a string representation of a boolean formula, returns the
    corresponding FormulaTree representation of the formula, given that it is
    valid. If the formula is not valid, None is returned.
    Valid formulas are of one of the following types:
    F1
    (F1 * F2)
    (F1 + F2)
    - F1
    where F1 and F2 are also valid boolean formulas.
    REQ: all characters in formula are in VARIABLES and SYMBOLS
    >>> build_tree("x-y") is None
    True
    >>> build_tree("(-x+y)")
    OrTree(NotTree(Leaf('x')), Leaf('y'))
    >>> build_tree("((x*y)+z)")
    OrTree(AndTree(Leaf('x'), Leaf('y')), Leaf('z'))
    '''
    # Defaulted the variable for the FormulaTree to an invalid input
    tree = None

    # Base Case, formula is empty: invalidate the formula
    if not formula:
        tree = None

    # Base Case, formula is a boolean variable
    elif formula in VARIABLES:
        tree = Leaf(formula)

    # Recursive Case 1: Formula is a negation of a boolean formula (NotTree)
    # Set that formula's children to be everything after the symbol
    elif formula[0] == '-':
        tree = NotTree(build_tree(formula[1:]))

    # Recursive Case 2: Formula is a boolean formula
    elif formula[0] == '(' and formula[-1] == ')':
        # Loop through the formula string
        ind = 1

        while ind < len(formula) - 1:
            # Check if formula contains nested boolean formulas
            if formula[ind] == '(':
                brackets = 1
                ind += 1

                while brackets != 0 and ind < len(formula) - 1:
                    # For each open bracket, add a new level of nesting
                    if formula[ind] == '(':
                        brackets += 1

                    # For each closing bracket, remove a level of nesting
                    elif formula[ind] == ')':
                        brackets -= 1

                    # Invalidate the tree if an invalid character is found
                    elif not (formula[ind] in VARIABLES
                              or formula[ind] in SYMBOLS):
                        tree = None
                        ind = len(formula) - 2

                    ind += 1

            # Check if formula is an AndTree/OrTree formula
            # Set the formula's children to be everything before the symbol,
            # and everything after the symbol, then stop the while loop
            if formula[ind] == '*':
                tree = AndTree(build_tree(formula[1:ind]),
                               build_tree(formula[ind + 1:-1]))
                ind = len(formula) - 1

            elif formula[ind] == '+':
                tree = OrTree(build_tree(formula[1:ind]),
                              build_tree(formula[ind + 1:-1]))
                ind = len(formula) - 1

            ind += 1

    # Check if there is an invalid formula nested in the boolean formula
    # The whole tree is then made invalid
    if 'None' in str(tree):
        tree = None

    return tree
예제 #15
0
def build_tree(formula):
    ''' (str) -> FormulaTree or NoneType

    Given a string representation of a formula, return a tree representation
    of it with FormulaTree objects, if the formula is invalid then return
    None instead

    >>> build_tree("") == None
    True
    >>> build_tree("(-x)") == None
    True
    >>> build_tree("x+y") == None
    True
    >>> build_tree("x*y") == None
    True
    >>> build_tree("x-y") == None
    True
    >>> build_tree("(x+2)") == None
    True
    >>> build_tree("X") == None
    True
    >>> build_tree("(x+y+z)") == None
    True
    >>> build_tree("(x+(y)+z)") == None
    True
    >>> build_tree("((x)(x+y))") == None
    True
    >>> build_tree("(((x+)(x+y)))") == None
    True
    >>> build_tree("x") == Leaf("x")
    True
    >>> build_tree("(n+m)") == OrTree(Leaf("n"), Leaf("m"))
    True
    >>> build_tree("(c*v)") == AndTree(Leaf("c"), Leaf("v"))
    True
    >>> build_tree("-x") == NotTree(Leaf("x"))
    True
    >>> build_tree("-((x+y)*(a*-b))") == NotTree(AndTree(OrTree(Leaf("x"),\
Leaf("y")), AndTree(Leaf("a"), NotTree(Leaf("b")))))
    True
    '''
    # If formula is 1 character, create a leaf from it if it's a valid
    # variable name, otherwise return None
    if (len(formula) == 1):
        if (formula.isalpha() and formula.islower()):
            result = Leaf(formula)
        else:
            result = None
    # If the formula is an empty string, it is invalid therefore return None
    elif (len(formula) == 0):
        result = None
    else:
        # If the first character is -, then first build the smaller subtree
        # and create a NotTree for the subtree if the subtree is valid
        if (formula[0] == "-"):
            child1 = build_tree(formula[1:])
            if (child1 is None):
                result = None
            else:
                result = NotTree(child1)
        # if the first and last characters are brackets then
        elif (formula[0] == "(" and formula[-1] == ")"
              and formula.count("(") == formula.count(")")):
            # find the operator that accompanies the bracket pair
            index = find_operator_index(formula)
            # if the operator is found, build the smaller subtree called
            # child1 from the left, build the smaller subtree called child2
            # from the right, and from those create an AndTree or
            # OrTree based on the operator.
            if (index != -1):
                child1 = build_tree(formula[1:index])
                child2 = build_tree(formula[index + 1:-1])
                if (child1 is None or child2 is None):
                    result = None
                else:
                    if (formula[index] == "*"):
                        result = AndTree(child1, child2)
                    else:
                        result = OrTree(child1, child2)
            # if index is -1, it means there is no corresponding operator,
            # which means the formula is invalid
            else:
                result = None
        # If the leading character is neither a single variable, "-",
        # nor "(", then the formula is invalid
        else:
            result = None
    # Return the resulting root of the FormulaTree
    return result
def build_tree(formula):
    '''(str) -> FormulaTree
    Takes the infix expression represented by formula 
    and outputs the corresponding formula tree. build_tree works 
    with to_postfix in order to convert an equation into postfix notation
    and then create the tree. (probably the cleanest function I've ever written)
    build_tree also uses validate to make sure that a formula is valid before 
    attempting to construct the tree.
    >>> build_tree('((a+b)*(x*m))'))
    AndTree(OrTree(Leaf('a'), Leaf('b')), AndTree(Leaf('x'), Leaf('m')))
    >>> build_tree('-a')
    NotTree(Leaf('a'))
    >>> build_tree('(a+X)')
    None
    '''
    # first, we need to validate the formula using our helper
    # validate function. If the function is valid, we can proceed 
    # constructing the tree
    if validate(formula) == True:
        # first, let's convert our equation into postfix notation
        # using our to_postfix helper function
        fixedFormula = to_postfix(formula)
       # create an empty stack that we're gonna use to store
       # sub-expressions and connect them later
        stack = []
        # looping through every character in the postfix expression
        for character in fixedFormula:
            # if we encounter an operand, make a new subtree
            #we'll make the parent-child links as we go 
            if character in letters:
                newTree = Leaf(character)
            # if we encounter an and operator, we know that 
            # we have to have a left and right child, because and 
            # is binary, so pop two characters from the stack
            # and set them to the left and right children of the 
            # AndTree we're constructing. We're guaranteed to have 
            # two or more characters in the stack because of the way 
            # postfix expression works.
            elif character == '*':
                right = stack.pop()
                left = stack.pop()
                newTree = AndTree(left,right)
            # because not is a unary operator, all we need to do 
            # is set its one child to the subexpression that's 
            # highest up in the stack
            elif character == '-':
                newTree = NotTree(stack.pop())
            # an or tree behaves the same way as an and tree, it just needs
            # its own statement because we'll be using a different type of 
            # tree 
            elif character == '+':
                right = stack.pop()
                left = stack.pop()
                newTree = OrTree(left,right)
            # no matter what kind of sub-tree we've created, we need to re-add it back onto the stack
            # so that we can later create the parent-child relationships of that tree
            stack.append(newTree)
    # in the case where the formula is invalid, we know that we can set the newTree to None and simply
    # return that valud
    else:
        newTree = None
    # return the tree represnted by the given equation
    return newTree
예제 #17
0
def build_tree(formula):
    '''(str) -> FormulaTree or NoneType
    Returns the root of the equivalent FormulaTree that represents the given
    formula. Said formula must be a vaid formula, and if not, NoneType is
    instead returned.

    >>> formula_1 = 'x'
    >>> expected_1 = "Leaf('x')"
    >>> result_1 = str(build_tree(formula_1))
    >>> expected_1 == result_1
    True

    >>> formula_2 = "(x*-c)"
    >>> expected_2 = "AndTree(Leaf('x'), NotTree(Leaf('c')))"
    >>> result_2 = str(build_tree(formula_2))
    >>> expected_2 == result_2
    True

    >>> formula_3 = "((x+(z*e))+-x)"
    >>> expected_3 = "OrTree(OrTree(Leaf('x'), AndTree(Leaf('z'),\
 Leaf('e'))), NotTree(Leaf('x')))"
    >>> result_3 = str(build_tree(formula_3))
    >>> expected_3 == result_3
    True

    >>> formula_4 = "-((x+(a+c))+((b+d)*f))"
    >>> expected_4 = "NotTree(OrTree(OrTree(Leaf('x'), OrTree(Leaf('a'),\
 Leaf('c'))), AndTree(OrTree(Leaf('b'), Leaf('d')), Leaf('f'))))"
    >>> result_4 = str(build_tree(formula_4))
    >>> expected_4 == result_4
    True

    >>> formula_5 = "(-(x+(x*f))*(((z+y)*-g)*((h*d)+(z*-b))))"
    >>> expected_5 = "AndTree(NotTree(OrTree(Leaf('x'), AndTree(Leaf('x'),\
 Leaf('f')))), AndTree(AndTree(OrTree(Leaf('z'), Leaf('y')),\
 NotTree(Leaf('g'))), OrTree(AndTree(Leaf('h'), Leaf('d')),\
 AndTree(Leaf('z'), NotTree(Leaf('b'))))))"
    >>> result_5 = str(build_tree(formula_5))
    >>> expected_5 == result_5
    True

    >>> formula_6 = "(((-x*-y)*-h)+-(-f*((z+(g+c))+((z+-a)+(((e*c)+e)*\
(f+(a+g)))))))"
    >>> expected_6 = ("OrTree(AndTree(AndTree(NotTree(Leaf('x')),\
 NotTree(Leaf('y'))), NotTree(Leaf('h'))),\
 NotTree(AndTree(NotTree(Leaf('f')), OrTree(OrTree(Leaf('z'),\
 OrTree(Leaf('g'), Leaf('c'))), OrTree(OrTree(Leaf('z'),\
 NotTree(Leaf('a'))), AndTree(OrTree(AndTree(Leaf('e'), Leaf('c')),\
 Leaf('e')), OrTree(Leaf('f'), OrTree(Leaf('a'), Leaf('g')))))))))")
    >>> result_6 = str(build_tree(formula_6))
    >>> expected_6 == result_6
    True

    >>> formula = "(((-x*-y)*-h)+-(-f*((z+(g+c))++((z+-a)+(((e*c)+e)*\
 (f+(a+g)))))))"
    >>> expected_7 = None
    >>> result_7 = build_tree(formula)
    >>> expected_7 == result_7
    True
    '''
    # Assume that the formula is void
    result = None
    # Obtain the length of the formula
    formula_len = len(formula)
    # If the formula has 1 character and is a lowercase letter
    if ((formula_len == 1) and (formula in LOWERCASE_LETTERS)):
        # A Leaf node that contains the character (variable) is created
        result = Leaf(formula)
    # Else, if the formula has 2 characters, where the 1st character is '-' and
    # the 2nd character is a lowercase letter
    elif ((formula_len == 2) and
          ((formula[0] == NOT) and
          (formula[-1] in LOWERCASE_LETTERS))):
        # A Not node connected to a leaf node that contains the 2nd character
        # (variable) is created
        result = NotTree(Leaf(formula[-1]))
    # Else, if the formula has more than 2 characters
    elif (formula_len > 2):
        # Obtain the 1st character from the formula
        first_char = formula[0]
        # If the 1st character is '-'
        if (first_char == NOT):
            # Create a Not node:
            # The Not node's child will be the recursive call to the function,
            # with the 1st character removed from the formula
            sub_tree = build_tree(formula[1:])
            result = NotTree(sub_tree)
            # If the Not node's child does not exist
            if (not sub_tree):
                # This formula is void
                result = None
        # Else, if the formula is closed by brackets
        elif ((first_char == OPEN_BRACKET) and
              (formula[-1] == CLOSED_BRACKET)):
            # Remove those brackets
            formula = formula[1:-1]
            # Update the length of the formula
            formula_len = len(formula)
            # Get the indices of '+' or '*' in the formula that allows the
            # formula to be split into 2 sub formulas:
            # Holds all the indices where we have possibly found '+' or '*'
            # that satisfies the above condition
            indices_of_interest = set()
            # A formula can be split into 2 sub formulas if when either '+' or
            # '*' is found, we are not in a sub formula. Therefore, we must
            # have balanced brackets when either '+' or '*' is found
            sub_formulas = 0
            # Go through each character in the formula
            for index in range(formula_len):
                # Obtain the current character
                char = formula[index]
                # If the character is '('
                if (char == OPEN_BRACKET):
                    # We have entered a sub formula
                    sub_formulas += 1
                # Else, if the character is ')'
                elif (char == CLOSED_BRACKET):
                    # We have exited a sub formula
                    sub_formulas -= 1
                # Else, if the character is either '+' or '*', and we are not
                # in any sub formulas
                elif (((char == OR) or
                       (char == AND)) and
                      (sub_formulas == 0)):
                    # Add the index to our set
                    indices_of_interest.add(index)
            # If the set of indices is not empty, and does not contain more
            # than 1 entry
            if ((indices_of_interest) and (len(indices_of_interest) == 1)):
                # Obtain the index of interest to split the formula into 2
                # sub formulas
                index_of_interest = indices_of_interest.pop()
                # Create either a Or node or a And node:
                node = CONNECTIVES[formula[index_of_interest]]
                # The specified node's left child will be the recursive call to
                # the function, with the string slice to the left of where
                # either '+' or '*' was found in the formula
                left_sub_tree = build_tree(formula[:index_of_interest])
                # The specified node's right child will be the recursive call
                # to the function, with the string slice to the right of where
                # either '+' or '*' was found in the formula
                right_sub_tree = build_tree(formula[index_of_interest + 1:])
                result = node(left_sub_tree, right_sub_tree)
                # If either left or right child does not exist
                if ((not left_sub_tree) or (not right_sub_tree)):
                    # This formula is void
                    result = None
    # Returns the FormulaTree equivalent to the given formula
    return result
예제 #18
0
def build_tree_helper(formula, start, end):
    '''
    (str) -> FormulaTree
    takes string <formula> and returns the FormulaTree representing the
    formula.
    returns None is there are invalid bracketing
    end is inclusive
    >>>
    >>>
    True
    '''
    # if no conditions are met
    result = None

    # base case/ charcter check:
    if (start == end):

        if (formula[start].isalpha() and formula[start].islower()):
            # result is a leaf node with var
            result = Leaf(formula[start])

    # base case, formula starts with
    elif (formula[start] == '-'):
        sub_result = build_tree_helper(formula, start + 1, end)
        if sub_result is None:
            result = None
        else:
            result = NotTree(build_tree_helper(formula, start + 1, end))
    # else:
    else:

        # vars to keep track of '(' and ')'
        left_bracket_count = 0
        right_bracket_count = 0

        exit_loop = False
        i = start

        # find the most outer brackets and the connective associated with them
        while (i <= end and not exit_loop):

            bracket_difference = left_bracket_count - right_bracket_count

            if (formula[i] == '('):
                left_bracket_count += 1
            elif (formula[i] == ')'):
                right_bracket_count += 1

            if bracket_difference < 0:
                exit_loop = True

            # connective count to throw exceptions****************
            elif ((formula[i] == '*' or formula[i] == '+')
                  and bracket_difference <= 1):  # might not need this one
                connective = formula[i]

                # use divide and conquer, and build the tree
                left = build_tree_helper(formula, start + 1, i - 1)

                right = build_tree_helper(formula, i + 1, end - 1)
                if (left is None or right is None):
                    result = None

                elif (connective == '*'):
                    result = AndTree(left, right)

                elif (connective == '+'):
                    result = OrTree(left, right)

                # exit the rest of the while loop
                exit_loop = True

            # increment the loop
            i += 1

    return result
예제 #19
0
def build_tree(formula):
    ''' (str) -> FormulaTree

    The function will create a FormulaTree based on
    the input formula str.
    The input str has to be in the right form otherwise,
    return None.
    The function will return a root of FormulaTree if input
    formula is in the valid form.

    The input str has to be in a valid form, which is:
    1. "+" and "*" connect to leaf and arounded by "(" and ")"
    2. for "-", there is no need for parenthesis.

    The function will start at an empty root,
    when we have a "(", we will create a left child, if
    we have a leaf, we will create that leaf and then go back to
    its parent and continune. When we have a ")" we will go
    back to parent. It has used concept of stack, which is
    a list to store parents.

    The function will change input formula into a good form, which is
    for each "-" sign, we have a matching ")" after its leaf.
    For example "-x" will change to "-x)"; "-(-x+y)" will change to
    "-(-x)+y))"

    >>> build_tree('a+b') == None
    True
    >>> build_tree('(a)') == None
    True
    >>> build_tree('-(a)') == None
    True
    >>> build_tree('(a+b+c)') == None
    True

    >>> tree = build_tree('(b+(c+d))')
    >>> tree == OrTree(Leaf('b'), OrTree(Leaf('c'), Leaf('d')))
    True
    >>> tree = build_tree('(x+y)')
    >>> tree == OrTree(Leaf('x'), Leaf('y'))
    True
    >>> tree = build_tree('-(--x+y)')
    >>> tree == NotTree(OrTree(NotTree(NotTree(Leaf('x'))), Leaf('y')))
    True
    >>> tree = build_tree('------x')
    >> tree == NotTree(NotTree(NotTree(NotTree(NotTree(NotTree(Leaf('x')))))))
    True
    '''
    # create a list to store all parents
    stack = []
    # create an empty tree, add it into stack and let curr be it
    tree = FormulaTree(None, [])
    stack.append(tree)
    curr = tree
    # try to do the following
    try:
        # change formula into a good form for code
        formula = build_tree_helper(formula)
        # loop through each symbol in formula
        for s in formula:
            # if we have "("
            if s == '(':
                # create a left subtree, and store parent in stack
                left = FormulaTree(None, [])
                curr.children.append(left)
                stack.append(curr)
                curr = curr.children[0]
            # if we have a laef
            elif s not in ['+', '*', '-', ')']:
                # if s is not alphabet or it is upper case, return None
                if not s.isalpha() or s.isupper():
                    return None
                # create a leaf of its symbol
                leaf = Leaf(s)
                # get the parent from stack
                parent = stack.pop()
                # if curr node has parent
                if curr in parent.children:
                    # let parent pointer to this leaf
                    index = parent.children.index(curr)
                    parent.children[index] = leaf
                    # let curr be parent (go back)
                    curr = parent
                # if curr node has no parent
                else:
                    # let tree be curr leaf
                    tree = leaf
                # if after any leaf, stack is empty, then
                # it must be in invalid form, raise error
                if len(formula) != 1 and stack == []:
                    raise SyntaxError
            # if we have "+", "*", or "-"
            elif s in ['+', '*', '-']:
                # get the parent from stack
                parent = stack[-1]
                # create a new node for its child
                new_node = FormulaTree(None, [])
                # if symbol is * then create AndTree
                if s == '*':
                    replace = AndTree(curr.children[0], new_node)
                # if symbol is + then create OrTree
                elif s == '+':
                    replace = OrTree(curr.children[0], new_node)
                # if symbol is - then create NotTree
                else:
                    replace = NotTree(new_node)
                # if curr node has parent
                if curr in parent.children:
                    # get the index and let parent pointer to curr node
                    index = parent.children.index(curr)
                    parent.children[index] = replace
                    # get the new curr node
                    curr = replace
                # if curr node has no parent
                else:
                    # let tree be replace node
                    tree = replace
                    # get new curr node and reset stack
                    curr = tree
                    stack = [curr]
                # put curr into stack as parent and get next curr
                stack.append(curr)
                curr = curr.children[0] if s == '-' else curr.children[1]
            # if we have ")", then let curr go back to parent
            elif s == ')':
                curr = stack.pop()
            # if there is other situation, it must be error
            else:
                raise SyntaxError
    # if any error, then return None since it is an invalid form
    except:
        return None
    # if stack has anything which means invalid form, or
    # there are still some FormulaTree in result tree, return None
    if stack != [] or 'FormulaTree' in str(tree):
        return None
    return tree
예제 #20
0
def build_tree(formula):
    '''(str) -> FormulaTree or None
    take a string which represents the formula and return the FormulaTree when
    the formula is valid or None when the formula is invalid
    REQ: formula should be the right combinations of lower case
    latter, '-', '+', '*', '(' and ')'
    >>> build_tree("(x*y+z*x)")

    >>> build_tree('(x*y)')
    AndTree(Leaf('x'), Leaf('y'))
    '''
    # create two list:
    # one is the list which stores the operators
    # the other is the list which stores the lower case letters
    operator = list()
    letter = list()
    # go through the formula and the formula need to be valid
    index = 0
    is_valid = True
    while (index < len(formula) and is_valid is True):
        # the first element in formula[index:] is '(', '-', '+' or '*'
        if (formula[index] in ('(', '+', '-', '*')):
            # put this element into the operator list
            operator.append(formula[index])
        # the first element in formula[index:] is lower case letter
        elif (formula[index].islower() is True):
            # the previous str is also a letter
            if (index > 0 and formula[index - 1].islower() is True):
                is_valid = False
            # the last element in operator list is '-'
            # that means '-' is the parent of the current leaf
            elif (len(operator) > 0 and operator[-1] == '-'):
                # pop the last element in the operator list
                # build a NotTree whose child is the current leaf
                # push this subtree to letter list
                operator.pop()
                letter.append(NotTree(Leaf(formula[index])))
                # there is still symbol '-' exists in operator list
                while (len(operator) > 0 and operator[-1] == '-'):
                    operator.pop()
                    current_formula = letter.pop()
                    letter.append(NotTree(current_formula))
            # the last element in operator is not '-'
            else:
                # push this letter to letter list
                letter.append(Leaf(formula[index]))
        # the first element in formula[index:] is ')'
        elif (formula[index] == ')'):
            # the operator list is empty
            # or the letter list does not have two element
            if (len(operator) <= 1 or len(letter) < 2):
                is_valid = False
            else:
                # pop the last element in the operator list
                symbol = operator.pop()
                # pop two element from letter list
                # the last one is right child
                # and the second last one is left child
                right_child = letter.pop()
                left_child = letter.pop()
                # the symbol is '+'
                if (symbol == '+'):
                    # build a OrTree for this subtree
                    subtree = OrTree(left_child, right_child)
                # the symbol is '+'
                elif (symbol == '*'):
                    # build a AndTree for this subtree
                    subtree = AndTree(left_child, right_child)
                # the other symbol should be a invalid formula
                else:
                    is_valid = False
                if (is_valid is True):
                    # pop the last element in operator, it should be '('
                    # otherwise, it should be invalid
                    previous_symbol = operator.pop()
                    if (previous_symbol != '('):
                        is_valid = False
                    else:
                        # the last element in operator is '-'
                        # pop '-' and it is the parent of the subtree
                        if (len(operator) > 0 and operator[-1] == '-'):
                            operator.pop()
                            # push this subtree to letter list
                            letter.append(NotTree(subtree))
                            while (len(operator) > 0 and operator[-1] == '-'):
                                operator.pop()
                                current_formula = letter.pop()
                                letter.append(NotTree(current_formula))
                        # the last element in operator is not '-'
                        # push subtree to letter list straightly
                        else:
                            letter.append(subtree)
        # there are other symbol in the formula
        else:
            is_valid = False
        # increase the index
        index += 1
    # the is_valid is True, the operator list is empty
    # and there is only one element in the letter list
    # the last element in the letter list is the FormulaTree
    if (is_valid is True and len(operator) == 0 and len(letter) == 1):
        result = letter.pop()
    else:
        result = None
    return result
예제 #21
0
def build_tree(formula):
    '''(str) -> FormulaTree
    Takes a string representing a formula. If the formula is valid, returns the
    FormulaTree representation of the formula, else returns None.
    There are some invalid formulas and reasons.
    "X" variable not lower case letter
    "x*y" missing parentheses
    "-(x)" extraneous parentheses
    "(x+(y)*z)" mismatched parentheses
    REQ: formula is a string representing a boolean formula.
    >>> build_tree('(x*y)') == AndTree(Leaf('x'), Leaf('y'))
    True
    >>> build_tree('(x+-y)') == OrTree(Leaf('x'), NotTree(Leaf('y')))
    True
    >>> build_tree('(((x*y)*z)*w)') == AndTree(AndTree(AndTree(Leaf('x'), Leaf\
    ('y')), Leaf('z')), Leaf('w'))
    True
    >>> build_tree('X') == None
    True
    >>> build_tree('x*y') == None
    True
    >>> build_tree('(x+(y)*z)') == None
    True
    '''
    # set a condition for empty string
    empty = len(formula) == 0
    # if given an empty string, it is invalid
    if (empty):
        # result is None
        result = None
    # if given a string containing 1 lowercase letter, it is valid
    elif (len(formula) == 1):
        # set a condition for single variable
        variable = formula.isalpha() and formula.islower()
        if (variable):
            # create a leaf of the letter
            result = Leaf(formula)
        # else it is invalid
        else:
            # result is None
            result = None
    else:
        # set a condition for Not operation
        no = formula[0] == "-"
        # set a condition for formula closed by parentheses
        # and the numbers of open parentheses and close parentheses are equal
        paired = formula[0] == "(" and formula[-1] == ")" and\
            formula.count("(") == formula.count(")")
        # if - is the first character
        if (no):
            # build the subtree
            sub = build_tree(formula[1:])
            # if the subtree is valid
            if (sub is not None):
                # create a NotTree of the subtree
                result = NotTree(sub)
            # else the subtree is invalid
            else:
                # result is None
                result = None
        # if parentheses are to begin and end the string, and they are paired
        elif (paired):
            # find the root operator
            i = build_help(formula)
            # if the operator doesn'turns exist
            if (i == -1):
                # result is None
                result = None
            # else the operator exists
            else:
                # build a left subtree of the string before the operator
                lc = build_tree(formula[1:i])
                # build a right subtree of the string after the operator
                rc = build_tree(formula[i + 1:-1])
                # if one of the strings before & after the operator is invalid
                if (lc is None) or (rc is None):
                    # result is None
                    result = None
                # else the strings are both valid
                else:
                    # if the operator is +
                    if (formula[i] == "+"):
                        # create an OrTree
                        result = OrTree(lc, rc)
                    # if the operator is *
                    elif (formula[i] == "*"):
                        # create a AndTree
                        result = AndTree(lc, rc)
        # else the first character is not a lowercase letter, -, nor (
        else:
            # result is None
            result = None
    # return the result FormulaTree
    return result
예제 #22
0
def build_tree_helper(formula, start, end):
    '''
    (str, int, int) -> FormulaTree/None
    takes string <formula> and returns the root of the FormulaTree that
    represents <formula>. Returns None if formula is not valid
    <start> is starting index of <formula> to start building tree
    <end> is ending index of <formula> to start building tree, is inclusive
    this function is recursive
    a valid formula contains the following:
    - boolean variables: lowercase alphabetical letters
    - connectives: '*' represents AND, '+' represent OR, '-' represent NOT
    - parentheses: '(' and ')'
    rules for formula:
    - the simpliest formula is just a boolean variable
    - more complex formulas uses connectives and variables
    - arguments for '*' and '+' are always enclosed by parentheses
    - arugments for connectives are formulas
    any string that cannot be constructed with rules above are not valid
    (i.e empty, invalid characters, using connectives without using brackets)
    >>> a = build_tree_helper('(x+y)', 0 ,len('(x+y)') - 1)
    >>> repr(a) == "OrTree(Leaf('x'), Leaf('y'))"
    True
    >>> a = build_tree_helper('(-x*(y+z))', 1, 2)
    >>> repr(a) == "NotTree(Leaf('x'))"
    True
    '''
    # initialize result as None, so iff no valid conditions are met, ret None
    result = None

    # base case: 1 character
    if (start == end):

        # if the charcter is lowercase alphabetical letter
        if (formula[start].isalpha() and formula[start].islower()):

            # result is a Leaf node with the given letter
            result = Leaf(formula[start])

    # base case: formula starts with '-'
    elif (formula[start] == '-'):

        # check whether rest of the formula is valid
        sub_result = build_tree_helper(formula, start + 1, end)

        # if the rest of the formula is not valid
        if sub_result is None:

            # the whole formula is not valid
            result = None

        else:
            # else attach the FormulaTree representing the rest of the formula
            # to NotTree and ret
            result = NotTree(sub_result)

    # else recursive step
    else:

        # vars to keep track of '(' and ')'
        left_bracket_count = 0
        right_bracket_count = 0

        # vars for efficient while loop
        exit_loop = False
        i = start

        # find the most outer brackets and the connective associated with them
        # iterate through forumula until they are found
        while (i <= end and not exit_loop):

            bracket_difference = left_bracket_count - right_bracket_count

            # keep track of how many of each bracket is in the formula
            if (formula[i] == '('):
                left_bracket_count += 1
            elif (formula[i] == ')'):
                right_bracket_count += 1

            # if there are more ')' than '(' then formula is invalid
            # exit loop and return None
            if bracket_difference < 0:
                exit_loop = True

            # connective for outer brackets is when <bracket_difference>  <= 1
            # and the current character is '*' or '+'
            elif ((formula[i] == '*' or formula[i] == '+')
                  and bracket_difference <= 1):

                connective = formula[i]

                # divide and conquer, and build the tree to the left and right
                # of the connective
                left = build_tree_helper(formula, start + 1, i - 1)
                right = build_tree_helper(formula, i + 1, end - 1)

                # if any part of that is invalid, then whole forulma is invalid
                if (left is None or right is None):
                    result = None

                # set the left and right tree as the children of the found
                # connective
                elif (connective == '*'):
                    result = AndTree(left, right)
                elif (connective == '+'):
                    result = OrTree(left, right)

                # exit the rest of the while loop, if connective is found
                exit_loop = True

            # increment the loop
            i += 1

    # return result
    return result
def build_tree_helper(formula):
    ''' (str) -> FormulaTree
    Takes in a string (formula) and returns the FormulaTree that represents
    formula if it is a valid formula. Otherwise None is returned
    REQ: formula must be a valid string formula
    >>> asdf = build_tree("((-x+y)*-(-y+x))")
    >>> print(asdf)
    AndTree(OrTree(NotTree(Leaf('x')), Leaf('y')),
    NotTree(OrTree(NotTree(Leaf('y')), Leaf('x'))))
    >>> asdf = build_tree("((-x+y)*-(-y+x)")
    >>> print(asdf)
    None
    >>> asdf = build_tree("(x+y")
    >>> print(asdf)
    None
    >>> asdf = build_tree("x+y")
    >>> print(asdf)
    None
    >>> asdf = build_tree("x+y)")
    >>> print(asdf)
    None
    >>> asdf = build_tree("x+y*x")
    >>> print(asdf)
    None
    >>> asdf = build_tree("x")
    >>> print(asdf)
    Leaf('x')
    >>> asdf = build_tree("-y")
    >>> print(asdf)
    NotTree(Leaf('y'))
    >>> asdf = build_tree("(x*y)")
    >>> print(asdf)
    AndTree(Leaf('x'), Leaf('y'))
    >>> asdf = build_tree("X")
    >>> print(asdf)
    None
    >>> asdf = build_tree("x*y")
    >>> print(asdf)
    None
    >>> asdf = build_tree("-(x)")
    >>> print(asdf)
    None
    >>> asdf = build_tree("(x+(y)*z)")
    >>> print(asdf)
    None
    '''
    # Checks if current character is a NOT operation
    if (formula[0] == "-"):
        # Adds a NotTree to the FormulaTree
        return NotTree(build_tree_helper(formula[1:]))
    # Checks if current character is a valid variable
    if (len(formula) == 1 and formula[0].islower()):
        # Adds a Leaf to the FormulaTree
        return Leaf(formula[0])
    # Counter for keeping track of brackets
    counter = 0
    # Keeps track of the formula(s) within the current bracket
    lastIndex = len(formula) - 1
    # Goes through each character of the current string
    for i in range(1, lastIndex):
        # Keeps track of brackets
        if (formula[i] == "("):
            counter += 1
        elif (formula[i] == ")"):
            counter -= 1
        # If it finds the current operation
        elif (counter == 0):
            # If current operation is an OR
            if (formula[i] == "+"):
                # Adds an OrTree to the FormulaTree
                return OrTree(build_tree_helper(formula[1:i]),
                              build_tree_helper(formula[i + 1:lastIndex]))
            # If current operation is an AND
            if (formula[i] == "*"):
                # Adds an AndTree to the FormulaTree
                return AndTree(build_tree_helper(formula[1:i]),
                               build_tree_helper(formula[i + 1:lastIndex]))
    # For invalid formulas so a NoneType can be returned
    raise Exception()