Beispiel #1
0
def try_polynomial(line):
    elements = {0: None, 1: None, 2: None}
    match = re.match(check_polynomial, line)
    if match:
        compute(fn.format_line(line), elements, 0)
    else:
        u.warn("Invalid Input.", "SyntaxError")
Beispiel #2
0
 def __init__(self, function, param, data):
     self.function = function
     exp = u.check_unknown_vars(function, param, data)
     if exp is not None:
         self.formated = u.format_line(exp)
     else:
         u.warn("Too many unknown variables.", "SyntaxError")
     self.param = param
Beispiel #3
0
 def draw(self, xMin, xMax):
     matrices = re.search(regex.checkMatrice, self.formated)
     complexes = re.search(regex.complex, self.formated)
     zeroDiv = re.search("\/\s*0", self.formated)
     if matrices is not None or complexes is not None:
         u.warn("Can't draw a function with matrices or complexes.",
                "DrawError")
     if zeroDiv is not None:
         u.warn("Division by 0.", "ComputeError")
     X = np.array(range(xMin, xMax))
     y = eval(self.formated)
     plt.plot(X, y)
     plt.show()
Beispiel #4
0
 def draw(self, x_min, x_max):
     matrices = re.search(regex.checkMatrice, self.formated)
     complexes = re.search(
         r"(?:\d+(?:\.\d+)?\s*[+-]\s*)?(?:(?!el)\d+(?:\.\d+)\s*\*\s*)?i",
         self.formated)
     zero_div = re.search(r"/\s*\(?\s*0\s*\)?", self.formated)
     if matrices is not None or complexes is not None:
         u.warn("Can't draw a function with matrices or complexes.",
                "DrawError")
     if zero_div is not None:
         u.warn("Division by 0.", "ComputeError")
     X = np.array(range(x_min, x_max))
     y = eval(self.formated)
     plt.plot(X, y)
     plt.show()
Beispiel #5
0
 def parse(self, exp):
     width = None
     height = 0
     match = re.findall(regex.parseMatrice, exp)
     matrice = [[] for _ in range(len(match))]
     for m in match:
         elems = m.split(',')
         if width is None:
             width = len(elems)
         elif width != len(elems):
             u.warn("Matrice not well formated.", "syntaxError")
         for e in elems:
             matrice[height].append(Rational(u.int_float_cast(e)))
         height += 1
     self.height = height
     self.width = width
     self.array = matrice
     self.str = exp
     return self
Beispiel #6
0
    def get_inverse(self, m):
        determinant = self.get_determinant(m)
        if determinant == 0:
            u.warn("Can't compute inverse of matrice, determinant is 0.",
                   "ComputeError")
        if len(m) == 2:
            return [[m[1][1] / determinant, -1 * m[0][1] / determinant],
                    [-1 * m[1][0] / determinant, m[0][0] / determinant]]

        cofactors = []
        for r in range(len(m)):
            cofactor_row = []
            for c in range(len(m)):
                minor = self.get_minor(m, r, c)
                cofactor_row.append(
                    ((-1)**(r + c)) * self.get_determinant(minor))
            cofactors.append(cofactor_row)
        cofactors = self.transpose(cofactors, len(cofactors),
                                   len(cofactors[0]))
        for r in range(len(cofactors)):
            for c in range(len(cofactors)):
                cofactors[r][c] /= determinant
        return cofactors
Beispiel #7
0
    def calc(self, operation, obj):
        type = obj.get_type()

        if operation == '+':
            if type == "rational":
                return Rational(self.value + obj.value)

            if type == "matrice" or type == "complex":
                return obj.calc('+', self)

        elif operation == '-':
            if type == "rational":
                return Rational(self.value - obj.value)

            elif type == "matrice":
                u.warn("Can't substract a matrice to a rational.",
                       "ComputeError")

            elif type == "complex":
                ret = obj.negate()
                return ret.calc('+', self)

        elif operation == '*':
            if type == "rational":
                return Rational(self.value * obj.value)

            elif type == "matrice" or type == "complex":
                return obj.calc('*', self)

        elif operation == '/':
            frac = None
            if type == "complex":
                conj = obj.get_conj()
                div = self.calc('*', conj)
                den = obj.calc('*', conj)
                ret = div.calc('/', den)
                return ret
            elif type == "matrice":
                ret = copy.deepcopy(obj)
                if obj.width != obj.height:
                    u.warn("Can't compute the inverse of an unsquare matrice",
                           "ComputeError")
                if obj.array[0][0].get_type() == "complex":
                    u.warn(
                        "Can't divide by a matrice of complexes (Mat[[complex]])",
                        "ComputeError")
                ret.array = ret.get_inverse(ret.array)
                return ret.calc('*', self)
            if obj.value == 0:
                u.warn("Division by 0.", "ComputeError")
            res = str(self.value / obj.value)
            if '.' in res and '.' not in self.str and '.' not in obj.str:
                cd = u.pgcd(self.value, obj.value)
                frac = str(self.value / cd) + "/" + str(obj.value / cd)
            if frac is not None:
                self.frac = frac
            return Rational(self.value / obj.value)

        elif operation == '%':
            if type != "rational":
                u.warn("Can't modulo a rational by a " + type + ".",
                       "ComputeError")
            return Rational(self.value % obj.value)

        elif operation == '^':
            if type != "rational":
                u.warn("Can't elevate a rational to a " + type + ".",
                       "ComputeError")
            return Rational(self.value**obj.value)
Beispiel #8
0
    def calc(self, operation, obj):
        ret = copy.deepcopy(self)
        type = obj.get_type()

        if operation == "+":
            if type == "rational":
                ret.real += obj.value

            elif type == "complex":
                ret.real += obj.real
                ret.imaginary += obj.imaginary
                ret.imgIsNeg = ret.imaginary < 0

            elif type == "matrice":
                u.warn("Can't add a matrice to a complex.", "ComputeError")

        elif operation == "-":
            if type == "rational":
                ret.real -= obj.value

            elif type == "complex":
                ret.real -= obj.real
                ret.imaginary -= obj.imaginary
                ret.imgIsNeg = ret.imaginary < 0

            elif type == "matrice":
                u.warn("Can't substract a matrice to a complex.",
                       "ComputeError")

        elif operation == "*":
            if type == "rational":
                ret.real *= obj.value
                ret.imaginary *= obj.value
                ret.imgIsNeg = ret.imaginary < 0

            elif type == "complex":
                old = ret.real
                ret.real = ret.real * obj.real - ret.imaginary * obj.imaginary
                ret.imaginary = old * obj.imaginary + ret.imaginary * obj.real

            elif type == "matrice":
                ret = copy.deepcopy(obj)
                for i in range(obj.height):
                    for j in range(obj.width):
                        ret.array[i][j] = self.calc('*', obj.array[i][j])

        elif operation == "/":
            if type == "rational":
                ret.real = round(ret.real / obj.value, 3)
                ret.imaginary = round(ret.imaginary / obj.value, 3)

            elif type == "complex":
                div = Rational(obj.real**2 + obj.imaginary**2)
                conj = obj.get_conj()
                ret = self.calc('*', conj)
                ret = ret.calc('/', div)

            elif type == "matrice":
                if obj.width != obj.height:
                    u.warn("Can't compute the inverse of an unsquare matrice",
                           "ComputeError")
                if obj.array[0][0].get_type() == "complex":
                    u.warn(
                        "Can't divide by a matrice of complexes (Mat[[complex]])",
                        "ComputeError")
                ret = copy.deepcopy(obj)
                ret.array = ret.get_inverse(obj.to_int_tab(obj.array))
                for i in range(ret.height):
                    for j in range(ret.width):
                        ret.array[i][j] = self.calc('*',
                                                    Rational(ret.array[i][j]))

        elif operation == "%":
            if type == "rational":
                ret.real %= obj.value
                ret.imaginary %= obj.value
                ret.imgIsNeg = ret.imaginary < 0

            elif type == "complex" or type == "matrice":
                u.warn("Can't modulo a complex by a " + type + ".",
                       "ComputeError")

        elif operation == '^':
            if type != "rational":
                u.warn("Can't elevate a complex to a " + type + ".",
                       "ComputeError")
            for i in range(obj.value):
                ret = copy.deepcopy(self)
                for j in range(obj.value - 1):
                    ret = ret.calc('*', self)

        if ret.get_type() == "complex":
            ret.real = u.int_float_cast(str(ret.real))
            ret.imaginary = u.int_float_cast(str(ret.imaginary))
            ret.imgIsNeg = ret.imaginary < 0
            ret.str = (
                str(ret.real) +
                (" + " if not ret.imgIsNeg and ret.imaginary != 0 else " ")
                if ret.real != 0 else "") + (
                    (str(ret.imaginary) + "i") if ret.imaginary != 0 else "")
        return ret
Beispiel #9
0
    def calc(self, operation, obj):
        ret = Matrice()
        new = copy.deepcopy(self.array)
        type = obj.get_type()

        if operation == "+":
            if type == "rational" or type == "complex":
                u.warn("Can't add a " + type + " to a matrice.",
                       "ComputeError")
            elif type == "matrice":
                if self.height == obj.height and self.width == obj.width:
                    for i in range(len(new)):
                        for j in range(len(new[i])):
                            new[i][j] = new[i][j].calc('+', obj.array[i][j])
                else:
                    u.warn("Can't add matrices of different dimensions.",
                           "ComputeError")

        elif operation == "-":
            if type == "rational" or type == "complex":
                u.warn("Can't substract a " + type + " to a matrice.",
                       "ComputeError")
            elif type == "complex":
                for i in range(self.height):
                    for j in range(self.width):
                        new[i][j] = new[i][j].calc('-', obj)

            elif type == "matrice" or type == "complex":
                if self.height == obj.height and self.width == obj.width:
                    for i in range(len(new)):
                        for j in range(len(new[i])):
                            new[i][j] = new[i][j].calc('-', obj.array[i][j])
                else:
                    u.warn("Can't substract matrices of different dimensions.",
                           "ComputeError")

        elif operation == "*":
            if type == "rational" or type == "complex":
                for i in range(len(new)):
                    for j in range(len(new[i])):
                        new[i][j] = new[i][j].calc('*', obj)

            elif type == "matrice":
                if self.width == obj.height:
                    new = []
                    i = j = m = 0
                    while i < self.height or j < self.width:
                        new.append([])
                        j = k = 0
                        while k < obj.width:
                            j = l = 0
                            res = 0
                            while j < self.width:
                                res += obj.array[l][k].calc(
                                    '*', self.array[i][j]).value
                                j += 1
                                l += 1
                            new[m].append(Rational(res))
                            k += 1
                        m += 1
                        i += 1
                else:
                    u.warn(
                        "Can't resolve m1 * m2 : Number of raws in m1 doesn't match number of columns in m2.",
                        "ComputeError")

        elif operation == "/":
            if type == "rational" or type == "complex":
                for i in range(self.height):
                    for j in range(self.width):
                        new[i][j] = new[i][j].calc('/', obj)

            elif type == "matrice":
                if obj.width != obj.height:
                    u.warn("Can't compute the inverse of an unsquare matrice",
                           "ComputeError")
                if obj.array[0][0].get_type() == "complex":
                    u.warn(
                        "Can't divide by a matrice of complexes (Mat[[complex]])",
                        "ComputeError")
                new = copy.deepcopy(obj.array)
                for i in range(obj.height):
                    for j in range(obj.width):
                        new[i][j] = obj.array[i][j].value
                new = self.get_inverse(new)
                for i in range(len(new)):
                    for j in range(len(new)):
                        new[i][j] = Rational(new[i][j])
                ret.array = new
                ret.height = obj.height
                ret.width = obj.width
                ret = self.calc('*', ret)
                return ret

        elif operation == "%":
            if type == "rational":
                for i in range(self.height):
                    for j in range(self.width):
                        new[i][j] = new[i][j].calc('%', obj)

            else:
                u.warn("Can't modulo a " + type + " by a matrice",
                       "ComputeError")

        elif operation == '^':
            if type != "rational":
                u.warn("Can't elevate a matrice to a " + type + ".",
                       "ComputeError")
            tmp = copy.deepcopy(self)
            for i in range(obj.value - 1):
                tmp = tmp.calc('*', self)
            new = tmp.array

        ret.array = new.copy()
        ret.height = self.height
        ret.width = self.width
        ret.str = "["
        first_raw = True
        for i in range(len(new)):
            if first_raw:
                first_raw = False
            else:
                ret.str += ';'
            ret.str += '['
            first = True
            for j in range(len(new[0])):
                if first:
                    first = False
                else:
                    ret.str += ","
                ret.str += ret.array[i][j].str
            ret.str += ']'
        ret.str += ']'
        return ret
Beispiel #10
0
def parse(exp, data, i, tmp):
    """
    Replace all the elements in the string by a key and stores the object in the dictionary tmp with the same key.

    :param
        exp : the expression to evaluate
        data : the program dictionary, containing all the assigned variables so far
        i : the index to make the key to store elements in the dictionnary (key = "el" + str(i))
        tmp : the temporary dictinnary where we store all the parsed elements

    :order
        - find and evaluate brackets
        - parse Complexes
        - parse Matrices
        - parse Variables
        - parse negative Rationals
        - parse positive Rationals

    :return
        obj{exp, index, tmp}:
            exp : the formated expression
            index : the key index, to be used by compute
            tmp : the tmp dictionary filled with the parsed objects

    :e.g.
        parse("5 - [[1,2];[2,3]] * 5 + 3i")
        return:
            exp = "el0 - el1 * el2"
            index = 3
            tmp = {"el0": Rational(5), "el1": Matrice([[1,2];[2,3]]), "el2": Complex(5 + 3i)}
    """
    match = True

    brackets = True
    while brackets is not None:
        brackets = u.findBrackets(exp)
        if brackets is not None:
            ret = resolve(brackets, data)
            key = "el" + str(i)
            tmp[key] = ret
            i += 1
            exp = re.sub("(\d+(?:\.\d+)?|[A-Za-z])\s*\(" + brackets + "\)",
                         r"\1 * (" + brackets + ")", exp)
            exp = exp.replace("(" + brackets + ")", key, 1)

    while match:  # find and replace complexes
        match = re.search(regex.complex, exp)
        if match:
            c = Complex()
            string = match.group(0)
            key = "el" + str(i)
            i += 1
            exp = exp.replace(string, key, 1)
            tmp[key] = c.parse(string)

    match = True
    while match:  # find and replace matrices
        match = re.search(regex.checkMatrice, exp)
        if match:
            m = Matrice()
            string = match.group()
            key = "el" + str(i)
            i += 1
            exp = exp.replace(string, key, 1)
            tmp[key] = m.parse(string)

    match = True
    while match:  # find and replace functions
        match = re.search("(fun[a-z]\(([a-z\d\s+\-/*%^]+)\))",
                          exp,
                          flags=re.IGNORECASE)
        if match:
            obj = match.group(1)
            if obj[0:4] in data.keys():
                fn = data[obj[0:4]]
                param = u.intFloatCast(match.group(2))
                if param:
                    key = "el" + str(i)
                    i += 1
                    ret = resolve(fn.formated.replace('X', match.group(2)),
                                  data)
                    exp = exp.replace(obj, key)
                    tmp[key] = ret
                elif match.group(2) in data.keys():
                    param = data[match.group(2)]
                    ret = resolve(fn.formated.replace('X', param.str), data)
                    key = "el" + str(i)
                    i += 1
                    tmp[key] = ret
                    exp = exp.replace(obj, key)
                else:
                    param = resolve(match.group(2), data)
                    if param:
                        ret = resolve(fn.formated.replace('X', param.str),
                                      data)
                        key = "el" + str(i)
                        i += 1
                        tmp[key] = ret
                        exp = exp.replace(obj, key)
            else:
                u.warn("The function " + obj[0:4] + " is not assigned.",
                       "NameError")

    match = True
    while match:
        match = re.search("(?:[^a-z]|^)(?!el)([A-Z]+)",
                          exp,
                          flags=re.IGNORECASE)
        if match:
            obj = match.group(1)
            if obj in data.keys():
                key = "el" + str(i)
                i += 1
                tmp[key] = data[obj]
                exp = re.sub("([^a-z]|^)(?!el)([A-Za-z]+)", r"\1" + key, exp,
                             1)
            else:
                u.warn("The variable " + obj + " is not assigned.",
                       "NameError")

    match = True
    while match:
        match = re.search("(?:[+\-*/%]|^)\s*(-\s*\d+(?:\.\d+)?)",
                          exp)  # find and replace negative rationals
        if match:
            key = "el" + str(i)
            var = Rational(u.intFloatCast(match.group(1).replace(" ", "")))
            i += 1
            tmp[key] = var
            exp = re.sub("([+\-*/%]|^)\s*(-\s*\d+(?:\.\d+)?)", r"\1 " + key,
                         exp, 1)

    match = True
    while match:
        match = re.search("(?<!el)\d+(?:\.\d+)?",
                          exp)  # find and replace positive rationals
        if match:
            key = "el" + str(i)
            var = Rational(u.intFloatCast(match.group(0)))
            i += 1
            tmp[key] = var
            exp = re.sub("(?<!el)\d+(?:\.\d+)?", key, exp, 1)

    return {"exp": exp, "index": i, "tmp": tmp}
Beispiel #11
0
def compute(parsed):
    """
    Replace the calculations by a key and stores the object in the tmp dictionary with the same key.

    :param:
        obj{exp, index, tmp}
        exp : the parsed expression to evaluate
        index : the index to make the key to store elements in the dictionnary (key = "el" + str(i))
        tmp : the temporary dictinnary where we store all the parsed elements

    :order:
        - evaluate powers
        - evaluate * / %
        - evaluate + -

    :return:
        The last object in exp:
            exp should now contain only one key as "el7" if True, then return the corresponding object from tmp
    """
    i = parsed["index"]
    exp = parsed["exp"]
    tmp = parsed["tmp"]

    match = True
    while match:
        match = re.search("(el\d+)\s*(?:\*\*|\^)\s*(el\d+)", exp)
        if match:
            var1 = tmp[match.group(1)]
            var2 = tmp[match.group(2)]
            ret = var1.calc('^', var2)
            key = "el" + str(i)
            i += 1
            tmp[key] = ret
            exp = re.sub("(el\d+)\s*(?:\*\*|\^)\s*(el\d+)", key, exp, 1)

    match = True
    while match:
        match = re.search("(el\d+)\s*([*/%])\s*(el\d+)", exp)
        if match:
            var1 = tmp[match.group(1)]
            var2 = tmp[match.group(3)]
            ope = match.group(2)
            ret = var1.calc(ope, var2)
            key = "el" + str(i)
            i += 1
            tmp[key] = ret
            exp = re.sub("(el\d+)\s*([*/%])\s*(el\d+)", key, exp, 1)

    match = True
    while match:
        match = re.search("(el\d+)\s*([+-])\s*(el\d+)", exp)
        if match:
            var1 = tmp[match.group(1)]
            var2 = tmp[match.group(3)]
            ope = match.group(2)
            ret = var1.calc(ope, var2)
            key = "el" + str(i)
            i += 1
            tmp[key] = ret
            exp = re.sub("(el\d+)\s*([+-])\s*(el\d+)", key, exp, 1)

    if exp.strip() in tmp.keys():
        return tmp[exp.strip()]
    else:
        match = re.match("^-\s*(el\d+)$", exp.strip())
        if match and match.group(1) in tmp.keys():
            return tmp[match.group(1)].negate()
        elif "i" in exp.strip():
            c = Complex()
            return c.parse(exp.strip())
        else:
            u.warn("Invalid input.", "SyntaxError")
Beispiel #12
0
def compute(line, elements, side):
    if details:
        print("\n\033[0;32m[details]\033[0m natural parsing : " + line + "\n")
    line_split = line.split('=')
    reduced = "Reduced form: "
    detail_string = "\n\033[0;32m[details]\033[0m Simplified form : "
    res = 0
    first = True
    detail_first = True
    degree = 0
    count = 0

    while side < 2:
        exp = re.findall(regex_pattern, line_split[side])
        for i in range(len(exp)):
            pwr = int(exp[i][1].replace(' ', ''))
            num = float(exp[i][0].replace(' ', ''))
            try:
                if elements[pwr] is None:
                    elements[pwr] = 0
                elements[pwr] += num if side == 0 else -num
            except KeyError:
                elements[pwr] = num if side == 0 else -num
        side += 1

    for key, value in elements.items():
        if value is not None:
            if value == 0:
                count += 1
            else:
                if key > degree:
                    degree = key

            if first:
                reduced += fn.str_int_float(value) + " * X^" + str(key)
                first = False
            else:
                reduced += (" + " + fn.str_int_float(value) if value >= 0 else " - " + fn.str_int_float(-value)) \
                           + " * X^" + str(key)
            if detail_first:
                value_str = fn.str_int_float(value)
                if key != 0:
                    detail_first = False
            else:
                value_str = (" + " +
                             fn.str_int_float(value) if value >= 0 else " - " +
                             fn.str_int_float(-value))

            if key == 0:
                res -= value
            if key == 1:
                detail_string += value_str + "X"
            if key > 1:
                detail_string += value_str + "X^" + str(key)
        else:
            count += 1
            elements[key] = 0

    if degree == 0:
        if elements[0] == 0:
            print(reduced + " = 0")
            print("This equation accepts all real numbers as solution.")
        else:
            u.warn("Invalid input.", "SyntaxError")
    elif count == len(elements):
        print(reduced + " = 0")
        print("This equation accepts all real numbers as solution.")
    else:
        print(reduced + " = 0")
        print("Polynomial degree: " + str(degree))
        if degree < 3 and details:
            print(detail_string + " = " + fn.str_int_float(res))

        if degree <= 2:
            b = elements[1]
            c = elements[0]
            if degree == 1:
                if b == 0:
                    u.warn("Division by 0.", "ComputeError")
                else:
                    x = -c / b
                    if details:
                        print("\033[0;32m[details]\033[0m X = " +
                              fn.str_int_float(-c) + "/" +
                              fn.str_int_float(b) + "\n")
                    print("The solution is:")
                    fn.print_solution(x, -c, b)

            elif degree == 2:
                a = elements[2]
                delta = b * b - 4 * a * c
                if details:
                    print(
                        "\033[0;32m[details]\033[0m Calculating discriminant : "
                        + fn.str_int_float(b) + "^2 - 4 * " +
                        fn.str_int_float(a) + " * " + fn.str_int_float(c) +
                        " = " + fn.str_int_float(delta) + "\n")
                if delta > 0:
                    x1 = (-b - delta**0.5) / (2 * a)
                    x2 = (-b + delta**0.5) / (2 * a)
                    print(
                        "Discriminant is strictly positive, the two solutions are:"
                    )
                    if details:
                        print(
                            "\n\033[0;32m[details]\033[0m Calculating solution 1 : ("
                            + fn.str_int_float(-b) + " - " +
                            fn.str_int_float(delta) + "^0.5) / " +
                            fn.str_int_float(2 * a))
                        print(
                            "\033[0;32m[details]\033[0m Calculating solution 2 : ("
                            + fn.str_int_float(-b) + " + " +
                            fn.str_int_float(delta) + "^0.5) / " +
                            fn.str_int_float(2 * a) + "\n")
                    fn.print_solution(x1, (-b - delta**0.5), (2 * a))
                    fn.print_solution(x2, (-b + delta**0.5), (2 * a))

                elif delta < 0:
                    print(
                        "The discriminant is strictly negative, the equation has no real solution,"
                        + "only 2 complex solutions:")
                    print("(" + fn.str_int_float(-b) + " − i√" +
                          fn.str_int_float(-delta) + ") / " +
                          fn.str_int_float(2 * a))
                    print("(" + fn.str_int_float(-b) + " + i√" +
                          fn.str_int_float(-delta) + ") / " +
                          fn.str_int_float(2 * a))

                else:
                    if a == 0:
                        u.warn("Division by 0.", "ComputeError")
                    x = -b / (2 * a)
                    print(
                        "The discriminant is 0, the equation has one solution:"
                    )
                    if details:
                        print(
                            "\033[0;32m\n[details]\033[0m Calculating solution : "
                            + fn.str_int_float(-b) + "/" +
                            fn.str_int_float(2 * a) + "\n")
                    fn.print_solution(x, -b, c)
        else:
            u.warn(
                "The polynomial degree is strictly greater than 2, I can't solve.",
                "ComputeError")
    return True
Beispiel #13
0
def tryPolynomial(line):
    elements = {0: None, 1: None, 2: None}
    try:
        compute(fn.formatLine(line), elements, 0)
    except Exception:
        u.warn("Invalid input.", "SyntaxError")