def _parse_expression(self): print("Expression before parsing : ", self.expression) if self._verbose is True else None # Removing all spaces self.expression = self.expression.replace(" ", "") print("Removing all space from the expression : ", self.expression) if self._verbose is True else None # Checking if there is any sign or operator in the expression ok = False for operator in _OPERATORS + _SIGN + "=": if operator in self.expression: ok = True if ok is False: raise NothingToDoError( "There is no operators or sign in the expression. Nothing to do here." ) # To put before convert_signed_number because it is creating parenthesis self.expression = parse_sign(self.expression) print("Parsing signs : ", self.expression) if self._verbose is True else None self._get_vars() print("vars = ", self._vars_set) if self._verbose is True else None self.expression = convert_signed_number(expression=self.expression, accept_var=True) print("Convert signed numbers : ", self.expression) if self._verbose is True else None self._add_implicit_cross_operator_when_parenthesis() self.expression = add_implicit_cross_operator_for_vars( self._vars_set, self.expression) print("Convert implicit multiplication : ", self.expression) if self._verbose is True else None # Checking args here before converting to token self._check_args() # Transforming expression to tokens self.expression = convert_to_tokens(self.expression) print("Convert to token : ", self.expression) if self._verbose is True else None self._removing_trailing_zero_and_converting_numbers_to_float() print("Removing extra zero and converting numbers to float: ", self.expression) if self._verbose is True else None
def _push_right_to_left(self): for key, right_value in self._polynom_dict_right.items(): try: left_value = self._polynom_dict_left[key] except: left_value = 0.0 tokens = convert_to_tokens( convert_signed_number( parse_sign( add_implicit_cross_operator_for_vars(list(self.var_name), str(left_value)) + "-" + add_implicit_cross_operator_for_vars( list(self.var_name), str(right_value) ) ), accept_var=True, ) ) self._polynom_dict_left[key] = self._calculator.solve( tokens=tokens, verbose=self._force_calculator_verbose )
def solve( self, tokens: list, verbose: bool = False, force_calculator_verbose: bool = False, internal: bool = False, ) -> str: """ Resolving str calc. If internal is set to true, it means that the calc is from inside the class and should check For vars because it should be already set. """ self._tokens = tokens self._verbose = verbose print("Token inside Calculator : ", tokens) if self._verbose is True else None if not internal: self._check_vars() npi = self.npi_converter(self._tokens, accept_var=True if self.var_name else False) print("Token converted to npi system : ", npi) if self._verbose is True else None result = parse_sign(self.resolve_npi(npi)) return result
def _reduced_form(self): self._reduced_form = "" a, b, c = "0.0", "0.0", "0.0" for key, value in self._polynom_dict_left.items(): if key == "a": a = value elif key == "b": b = value else: c = value if a != "0.0": self._reduced_form = a if b != "0.0": self._reduced_form = self._reduced_form + "+" + b if c != "0.0": self._reduced_form = self._reduced_form + "+" + c if len(self._reduced_form) == 0: self._reduced_form = "0.0" self._reduced_form = parse_sign(self._reduced_form) + "=0.0" print("Reduced form : ", self._reduced_form)
def _solve_polynom_degree_two(self): try: a = get_var_multiplier(self._polynom_dict_left["a"], var_name=self.var_name) except: a = 0.0 try: b = get_var_multiplier(self._polynom_dict_left["b"], var_name=self.var_name) except: b = 0.0 try: c = float(self._polynom_dict_left["c"]) except: c = 0.0 print("a = ", a, " b = ", b, " c = ", c) if self._verbose is True else None discriminant = self._get_discriminant(a, b, c) if discriminant > 0: print("The discriminant is strictly positive.") elif discriminant == 0: print("The discriminant is exactly zero.") else: print("The discriminant is strictly negative.") print("discriminant = ", discriminant) if discriminant > 0: self.solution = [] if a == 0: raise ValueError( "The expression lead to a division by zero : ", float(str((-b + my_sqrt(discriminant)))), " / ", a, ) solution_one = str((-b + my_sqrt(discriminant)) / (2 * a)) solution_two = str((-b - my_sqrt(discriminant)) / (2 * a)) if solution_one == "-0.0": solution_one = "0.0" if solution_two == "-0.0": solution_two = "0.0" self.solution.append(str(my_round(float(solution_one), 6))) self.solution.append(str(my_round(float(solution_two), 6))) elif discriminant == 0: if a == 0: raise ValueError( "The expression lead to a division by zero : ", float(str((-b + my_sqrt(discriminant)))), " / ", a, ) self.solution = str((-b) / (2 * a)) if self.solution == "-0.0": self.solution = "0.0" else: print("There is two solutions in complex number.") self.solution = [] discriminant = -discriminant solution_one = convert_signed_number( f"{-b} / (2 * {a}) + i * {my_sqrt(discriminant)} / (2 * {a})".replace(" ", "") ) tokens = convert_to_tokens( convert_signed_number(parse_sign(solution_one), accept_var=True) ) self.solution.append( self._calculator.solve(tokens=tokens, verbose=self._force_calculator_verbose) ) solution_two = f"{-b} / (2 * {a}) - i * {my_sqrt(discriminant)} / (2 * {a})".replace( " ", "" ) tokens = convert_to_tokens( convert_signed_number(parse_sign(solution_two), accept_var=True) ) self.solution.append( self._calculator.solve(tokens=tokens, verbose=self._force_calculator_verbose) )
def resolve_npi(self, npi_list) -> str: stack = [] c = 0.0 var_is_present = True if self.var_name else False for elem in npi_list: if is_number(elem) or (var_is_present and elem in self.var_name): stack.append(elem) else: last_two_in_stack = stack[-2:] del stack[-2:] if len(last_two_in_stack) < 2: raise IndexError( "There is a problem in the npi resolver, the npi_list isn't well formated." ) # Doing var calc if there is a var if var_is_present and ( self._check_have_var(str(last_two_in_stack[0])) or self._check_have_var(str(last_two_in_stack[1])) ): # - or + operator, adding to c if elem in _SIGN: if not self._check_have_var(str(last_two_in_stack[0])): if elem == "-": c = my_round(c + float(last_two_in_stack[0])) # Inverting the sign of the var because it is the second element. result = self._multiply_a_var("-1", str(last_two_in_stack[1])) else: c = my_round(c + float(last_two_in_stack[0])) result = str(last_two_in_stack[1]) elif not self._check_have_var(str(last_two_in_stack[1])): if elem == "-": c = my_round(c - float(last_two_in_stack[1])) else: c = my_round(c + float(last_two_in_stack[1])) result = str(last_two_in_stack[0]) else: # Adding var to var result = self._add_or_substract_var_to_var( operator=elem, first_var=str(last_two_in_stack[0]), second_var=str(last_two_in_stack[1]), ) elif elem == "*": result = self._multiply_a_var( str(last_two_in_stack[0]), str(last_two_in_stack[1]) ) elif elem == "/": result = self._divide_a_var( str(last_two_in_stack[0]), str(last_two_in_stack[1]) ) elif elem == "^": result = self._power_a_var( str(last_two_in_stack[0]), str(last_two_in_stack[1]) ) else: raise NotImplementedError( "This type of operation with vars is not accepted for the moment." ) # Doing usual calc elif elem == "^": result = my_round( my_power(float(last_two_in_stack[0]), float(last_two_in_stack[1])) ) elif elem == "*": result = my_round(float(last_two_in_stack[0]) * float(last_two_in_stack[1])) elif elem == "/": if float(last_two_in_stack[1]) == 0.0: raise ValueError( "The expression lead to a division by zero : ", float(last_two_in_stack[0]), " / ", float(last_two_in_stack[1]), ) result = my_round(float(last_two_in_stack[0]) / float(last_two_in_stack[1])) elif elem == "%": if float(last_two_in_stack[1]) == 0.0: raise ValueError( "The expression lead to a modulo zero : ", float(last_two_in_stack[0]), " % ", float(last_two_in_stack[1]), ) result = my_round(float(last_two_in_stack[0]) % float(last_two_in_stack[1])) elif elem == "+": result = my_round(float(last_two_in_stack[0]) + float(last_two_in_stack[1])) elif elem == "-": result = my_round(float(last_two_in_stack[0]) - float(last_two_in_stack[1]), 6) stack.append(result) if len(stack) > 1: raise Exception( "Unexpected error when trying to resolve npi. Maybe your input format is not accepted?" ) if var_is_present: if c != 0.0: # Parse sign because could have duplicate sign with the add of the + return parse_sign(str(c) + "+" + str(stack[0])) else: return str(stack[0]) else: return str(stack[0])
def _add_or_substract_var_to_var(self, operator: str, first_var: str, second_var: str): pattern = self.var_name # Checking if multiple var in first_var (ex : x + X ^ 2) if len(re.findall(pattern=pattern, string=first_var)) > 1: second_var_power = str(float(self._get_power(second_var))) if second_var_power != "1.0": # regex that match any sign or none, followed by any number or none # followed by the var name followed by the power of the var pattern = "[{sign}]*[.\d]*[\*]*{var_name}\^{second_var_power}".format( var_name=self.var_name, second_var_power=second_var_power, sign=_SIGN ) else: # Same for simple X, the var name shouln't be followed by a power operator pattern = "[{sign}]*[.\d]*[\*]*{var_name}(?!\^)".format( var_name=self.var_name, second_var_power=second_var_power, sign=_SIGN ) split = re.split(pattern=pattern, string=first_var) if len(split) > 1: search = re.search(pattern=pattern, string=first_var) if search is not None: # Cutting respective power and convert signed numbers first_var = add_implicit_cross_operator_for_vars( vars_list=list(self.var_name), expression=convert_signed_number(search.group(0), accept_var=True), ) second_var = add_implicit_cross_operator_for_vars( vars_list=list(self.var_name), expression=convert_signed_number(second_var, accept_var=True), ) tokens = convert_to_tokens(first_var + operator + second_var) result = self.solve(tokens=tokens, internal=True) if result == "0.0": return parse_sign("".join(split)) else: return parse_sign(result + "+" + "".join(split)) first_var_power = str(self._get_power(first_var)) second_var_power = str(self._get_power(second_var)) # Different power if first_var_power != second_var_power: return first_var + operator + second_var # Cutting respective power and convert signed numbers first_var = add_implicit_cross_operator_for_vars( vars_list=list(self.var_name), expression=convert_signed_number(first_var.split("^")[0], accept_var=True), ) second_var = add_implicit_cross_operator_for_vars( vars_list=list(self.var_name), expression=convert_signed_number(second_var.split("^")[0], accept_var=True), ) removed_var1_name = first_var.replace(self.var_name, "1") removed_var2_name = second_var.replace(self.var_name, "1") tokens = convert_to_tokens(removed_var1_name + operator + removed_var2_name) result = self.solve(tokens, internal=True) if float(result) == 0: return "0.0" elif float(result) == 1: return self._write_power_to_var(var=self.var_name, power=first_var_power) else: return str(result) + self._write_power_to_var(var=self.var_name, power=first_var_power)