Beispiel #1
0
 def _operate(self, operation, x=0, y=1):
     # TODO equations
     if operation == "is":
         self.define_var(x, str(y))
         return str(x) + " = " + str(y)
     if str(x) in self.constants:
         x = self.constants[str(x)]
     if str(y) in self.constants:
         y = self.constants[str(y)]
     if str(x) in self.variables:
         x = self.variables[str(x)]
     if str(y) in self.variables:
         y = self.variables[str(y)]
     if not is_numeric(x) or not is_numeric(y):
         return str(x) + " " + operation + " " + str(y)
     x = float(x)
     y = float(y)
     if operation == "+":
         return x + y
     if operation == "/":
         return x / y
     if operation == "-":
         return x - y
     if operation == "*":
         return x * y
     if operation == "%":
         return x % y
     if operation == "sqrt":
         return math.sqrt(x)
     if operation == "!":
         return math.factorial(x)
     if operation == "log":
         return math.log(x, y)
     if operation == "exp":
         return math.exp(x)
     if operation in ["^", "**", "pow"]:
         return math.pow(x, y)
     if operation == "sqr":
         return math.pow(x, 2)
     if operation == "qb":
         return math.pow(x, 3)
     # TODO priority
     if operation == "(":
         pass
     if operation == ")":
         pass
     return None
Beispiel #2
0
    def __init__(self, input_str, variables=None, nice=False, lang="en-us"):
        self.lang = lang
        self.nice = nice
        if variables is None:
            variables = {}
        self.variables = variables
        self.raw_str = input_str
        self.string = normalize(input_str, self.lang)

        if is_numeric(self.string):
            self.input_operations = [["0", "+", self.string]]
            self.chain = [self.string]
            self.result = self.chain[0]
        else:
            self.input_operations = extract_expression(self.string, self.lang)
            self.chain, self.result = self._chained_operation(
                self.input_operations)

        self._get_result()
Beispiel #3
0
    def solve(self, debug=False):
        if debug:
            print "normalized string:", self.string
            print "raw string:", self.raw_str

        lang = self.lang
        OP = StringOperation(self.raw_str, lang=lang)
        res = OP.result
        variables = OP.variables
        if debug:
            print "elementar operations:", OP.input_operations
            print "result:", res
            print "chain", OP.chain
        i = 0
        depth = 5
        prev_res = ""
        while not res == prev_res and i < depth:
            prev_res = res
            OP = StringOperation(res, variables=variables, lang=lang)
            res = OP.result
            variables = OP.variables
            if debug:
                print "elementar operations:", OP.input_operations
                print "result:", res
                print "chain", OP.chain
            i += 1
        if debug:
            print "vars:", OP.variables
            print "\n"
        # make nice numbers
        if self.nice:
            words = res.split(" ")
            for idx, word in enumerate(words):
                if is_numeric(word):
                    words[idx] = nice_number(float(word))
            res = " ".join(words)
        return res
Beispiel #4
0
def extract_expression_en(string):
    expressions = {
        "+": ["add", "adding", "plus", "added"],
        "-": ["subtract", "subtracting", "minus", "negative", "subtracted"],
        "/": ["divide", "dividing", "divided"],
        "*": ["multiply", "multiplying", "times", "multiplied"],
        "%": ["modulus"],
        "!": ["factorial"],
        "is": ["set"],  # TODO find better keyword for x = value
        # "=": ["equals"],
        "^": ["**", "^", "pow"
              "elevated", "power", "powered", "raised"],
        "sqr": ["squared"],
        "sqrt": ["square_root"],
        "qb": ["cubed", "qubed"],
        "exp": ["exponent", "exponentiate", "exponentiated"],
        "(": ["open"],
        ")": ["close"]
    }
    # clean string
    noise_words = [
        "by", "and", "the", "in", "at", "a", "for", "an", "to", "with", "off",
        "of"
    ]

    # replace natural language expression
    for op in expressions:
        string = string.replace(op, " " + op + " ")
    words = string.replace(",", "").replace("square root", "sqrt").split(" ")

    for idx, word in enumerate(words):
        if word in noise_words:
            words[idx] = ""
        else:
            for operation in expressions:
                if word in expressions[operation]:
                    words[idx] = operation
    words = [word for word in words if word]
    exps = []
    # convert all numbers
    for idx, word in enumerate(words):
        if not word:
            continue
        if extractnumber(word):
            words[idx] = str(extractnumber(word))
        # join unknown vars nums
        if idx + 1 < len(words) and words[idx + 1] not in operations:
            # 3 x = 3x
            if is_numeric(word) and not is_numeric(words[idx + 1]):
                words[idx] = word + words[idx + 1]
                words[idx + 1] = ""
        if idx - 1 >= 0 and word not in operations:
            # 1 2 x = 1 2x
            if not is_numeric(word) and is_numeric(words[idx - 1]):
                words[idx] = words[idx - 1] + word
                words[idx - 1] = ""

    words = [word for word in words if word]

    # extract operations
    for idx, word in enumerate(words):
        if not word:
            continue
        # is an operation
        if word in expressions:
            operation = word
            if idx > 0:
                woi = words[idx - 1:idx + 2]
                words[idx - 1] = ""
                if idx + 1 < len(words):
                    words[idx + 1] = ""
                words[idx] = ""
                x = woi[0]
                try:
                    y = woi[2]
                except:
                    y = "next"
                if x == "":
                    x = "prev"
                if operation == "sqrt":
                    x = y
                exps.append([x, operation, y])
            else:
                # operation at first, is a sign
                y = words[idx + 1]
                words[idx + 1] = ""
                words[idx] = ""
                if operation == "-":
                    x = "-" + y
                    y = 0
                    operation = "+"
                    exps.append([x, operation, y])
                elif operation == "+":
                    exps.append(["0", operation, y])
                # or square root
                elif operation == "sqrt":
                    x = y
                    y = "next"
                    exps.append([x, operation, y])
                    # TODO exponent, log

    if not exps and extractnumber(string):
        exps = [["0", "+", str(extractnumber(string))]]
    return exps
Beispiel #5
0
    def _chained_operation(self, operations):
        # this operation object will contain all var definitions and be
        # re-set and re used internally
        OP = ElementalOperation()
        OP.variables = self.variables
        # prioritize operations by this order
        passes = [
            # ["="],
            ["is", "!", "exp", "log", "^", "sqrt", "**", "sqr", "qb", "pow"],
            ["*", "/", "%"],
            ["+", "-"]
        ]
        for current_pass in passes:
            for idx, op in enumerate(operations):
                if not op or op[1] not in current_pass:
                    continue
                prev_op = operations[idx - 1] if idx - 1 >= 0 else ""

                # check for numbers
                if op[0] in OP.constants:
                    op[0] = OP.constants[op[0]]
                if op[0] in OP.variables:
                    op[0] = OP.variables[op[0]]
                if op[2] in OP.constants:
                    op[2] = OP.constants[op[2]]
                if op[2] in OP.variables:
                    op[2] = OP.variables[op[2]]

                if is_numeric(op[0]) and op[1] in [
                        "!", "exp", "sqrt", "^", "**", "qb", "sqr", "pow",
                        "log"
                ]:
                    OP.set(op[0], op[0], op[1])
                    result = OP.operate()
                    operations[idx] = [0, "+", result]
                    continue

                # chain operation
                if op[0] == "prev":

                    if prev_op == ["0", "+", "0"]:
                        operations[idx][0] = "0"
                        operations[idx - 1] = ""
                    elif prev_op:

                        if is_numeric(prev_op[2]):
                            OP.set(prev_op[2], op[2], op[1])
                            operations[idx - 1][2] = "next"
                            result = OP.operate()
                            operations[idx] = [0, "+", result]
                        elif prev_op[2] == "next":
                            operations[idx] = [prev_op[0], "+", op[2]]
                            operations[idx - 1] = ""

                # all numbers, solve operation
                if is_numeric(op[0]) and is_numeric(op[2]):
                    OP.set(op[0], op[2], op[1])
                    result = OP.operate()
                    operations[idx] = [0, "+", result]
                    continue

                # handle vars
                if is_numeric(op[0]) and not is_numeric(op[2]):
                    pass
                if not is_numeric(op[0]) and is_numeric(op[2]):
                    pass
                if not is_numeric(op[0]) and not is_numeric(op[2]):
                    if op[0] == op[2]:
                        # find num
                        num = ""
                        for i in range(0, len(op[2])):
                            char = op[2][i]
                            if is_numeric(char) or char == ".":
                                num += char
                        if op[1] == "-":
                            operations[idx] = ["0", "+", "0"]
                            continue
                        if op[1] == "/":
                            operations[idx] = ["0", "+", "1"]
                            continue
                        if op[1] == "*":
                            operations[idx] = [op[0], "sqr", "next"]
                            continue
                        if op[1] == "+":
                            if not num:
                                operations[idx] = ["0", "+", "2" + op[0]]
                                continue
                            op[0] = op[0].replace(str(num), "")
                            num = str(2 * float(num))
                            if len(num) >= 3 and num[-2:] == ".0":
                                num = num[:-2]
                            operations[idx] = ["0", "+", num + op[0]]
                            continue
                            # TODO other ops ^ exp log sqr qb sqrt

                    else:
                        # find nums
                        num1 = ""
                        num2 = ""
                        var1 = 1
                        var2 = 2
                        for i in range(0, len(op[0])):
                            char = op[0][i]
                            if is_numeric(char) or char == ".":
                                num1 += char
                                var1 = op[0][i + 1:]
                        for i in range(0, len(op[2])):
                            char = op[2][i]
                            if is_numeric(char) or char == ".":
                                num2 += char
                                var2 = op[2][i + 1:]
                        if var1 == var2:
                            var = var1
                            if op[1] == "-":
                                num = str(float(num1) - float(num2))
                                if len(num) >= 3 and num[-2:] == ".0":
                                    num = num[:-2]
                                operations[idx] = ["0", "+", str(num) + var]
                                continue
                            if op[1] == "/":
                                num = str(float(num1) / float(num2))
                                if len(num) >= 3 and num[-2:] == ".0":
                                    num = num[:-2]
                                operations[idx] = ["0", "+", str(num) + var]
                                continue
                            if op[1] == "*":
                                num = str(float(num1) * float(num2))
                                if len(num) >= 3 and num[-2:] == ".0":
                                    num = num[:-2]
                                operations[idx] = ["0", "+", str(num) + var]
                                continue
                            if op[1] == "+":
                                num = str(float(num1) + float(num2))
                                if len(num) >= 3 and num[-2:] == ".0":
                                    num = num[:-2]
                                operations[idx] = ["0", "+", str(num) + var]
                                continue
                                # TODO other ops ^ exp log sqr qb sqrt
        self.variables = OP.variables
        # clean empty elements
        result = ""
        chain = []

        for op in operations:
            if op:
                chain.append(op)
            for element in op:
                if element and element != "prev" and element != "next":
                    result += str(element)
        return chain, result