diff --git a/__pycache__/algebraic_steps.cpython-313.pyc b/__pycache__/algebraic_steps.cpython-313.pyc index 061f4cd..7cd16c3 100644 Binary files a/__pycache__/algebraic_steps.cpython-313.pyc and b/__pycache__/algebraic_steps.cpython-313.pyc differ diff --git a/__pycache__/problem_generator.cpython-313.pyc b/__pycache__/problem_generator.cpython-313.pyc index cf098ce..03e379b 100644 Binary files a/__pycache__/problem_generator.cpython-313.pyc and b/__pycache__/problem_generator.cpython-313.pyc differ diff --git a/__pycache__/steps_generator.cpython-313.pyc b/__pycache__/steps_generator.cpython-313.pyc index 5755285..00a0039 100644 Binary files a/__pycache__/steps_generator.cpython-313.pyc and b/__pycache__/steps_generator.cpython-313.pyc differ diff --git a/algebraic_steps.py b/algebraic_steps.py index c17dc4d..854b3a5 100644 --- a/algebraic_steps.py +++ b/algebraic_steps.py @@ -18,12 +18,12 @@ def move_all_to_one_side(equation): left, right = current.split("=") x = symbols('x') - left_expr = parse_expr(left, transformations=transformations, evaluate=False) - right_expr = parse_expr(right, transformations=transformations, evaluate=False) - new_expr = left_expr - right_expr - step["after"] = f"{sstr(new_expr)} = 0" + left_expr = clean(parse_expr(left, transformations=transformations, evaluate=False)) + right_expr = clean(parse_expr(right, transformations=transformations, evaluate=False)) + new_expr = f"({sstr(left_expr)}) - ({sstr(right_expr)}) = 0" + step["after"] = new_expr - step["step"] = f"Subtract both sides by {sstr(right_expr)}" + step["step"] = f"Subtract {sstr(clean(right_expr))} from both sides" step["rule"] = "Subtraction Property of Equality" return step @@ -42,7 +42,7 @@ def add_both_sides(equation, value): new_right_expr = clean(right_expr + value) step["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}" - step["step"] = f"Add both sides by {sstr(value)}" + step["step"] = f"Add {sstr(value)} to both sides" step["rule"] = "Addition Property of Equality" return step @@ -61,7 +61,7 @@ def subtract_both_sides(equation, value): new_right_expr = clean(right_expr - value) step["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}" - step["step"] = f"Subtract both sides by {sstr(value)}" + step["step"] = f"Subtract {sstr(value)} from both sides" step["rule"] = "Subtraction Property of Equality" return step @@ -95,10 +95,21 @@ def multiply_both_sides(equation, value): left_expr = parse_expr(left, transformations=transformations, evaluate=False) right_expr = parse_expr(right, transformations=transformations, evaluate=False) - new_left_expr = cancel(left_expr * value) - new_right_expr = Mul(right_expr, value, evaluate=False) + if left_expr != 1 and left_expr != -1: + new_left_expr = cancel(left_expr * value) + elif left_expr == 1: + new_left_expr = value + else: + new_left_expr = -value + + if right_expr != 1 and right_expr != -1: + new_right_expr = Mul(right_expr, value, evaluate=False) + elif right_expr == 1: + new_right_expr = value + else: + new_right_expr = -value + step["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}" - step["step"] = f"Multiply both sides by {sstr(value)}" step["rule"] = "Multiplication Property of Equality" return step @@ -255,11 +266,10 @@ def trinomial_by_grouping(equation, inner): steps[-1]["after"] = f"{sstr(new_left_expr)} = {sstr(right_expr)}" steps[-1]["step"] = ( - f"Seperate the x coefficient to equal the factors of the first times last coefficients" - f"({sstr(Abs(a))} x {sstr(Abs(c))} = {sstr(ac)}) that {action} {sstr(Abs(b))}" - f"({sstr(factor1)},{sstr(factor2)})" + f"Split the x coefficient to two terms that multiply to the first coefficient({sstr(Abs(a))}) " + f"times last coefficient({sstr(Abs(c))}) = ({sstr(ac)}) and {action} {sstr(Abs(b))}" ) - steps[-1]["rule"] = "Split Coefficients" + steps[-1]["rule"] = "Factoring by grouping" ## Factor Out X on left term steps.append({}) @@ -267,15 +277,20 @@ def trinomial_by_grouping(equation, inner): terms = left_expr.as_ordered_terms() t1, t2, t3, t4 = terms[0], terms[1], terms[2], terms[3] - div = gcd(t3, t4) factored_part1 = factor(t1 + t2) - factored_part2 = factor(t3 + t4) + if t3 != -x: + div = gcd(t3, t4) + factored_part2 = factor(t3 + t4) + else: + div = -1 + factored_part2 = Mul(-1,(-t3 - t4), evaluate=False) rest = sum(terms[2:]) new_left_expr = Add(factored_part1, rest, evaluate=False) - new_left_expr = Mul(n, new_left_expr, evaluate=False) + if n != 1: + new_left_expr = Mul(n, new_left_expr, evaluate=False) steps[-1]["after"] = f"{sstr(new_left_expr)} = {sstr(right_expr)}" - steps[-1]["step"] = f"Factor out the x from the left two terms of the inner polynomial" + steps[-1]["step"] = f"Factor out the x from the left two terms of the polynomial" steps[-1]["rule"] = "Reverse Distributive Property" ## Factor Out GCD on right term @@ -283,27 +298,32 @@ def trinomial_by_grouping(equation, inner): steps[-1]["before"] = steps[-2]["after"] left_expr = Add(factored_part1, factored_part2, evaluate=False) - new_left_expr = Mul(n, left_expr, evaluate=False) + new_left_expr = left_expr + if n != 1: + new_left_expr = Mul(n, new_left_expr, evaluate=False) steps[-1]["after"] = f"{sstr(new_left_expr)} = {sstr(right_expr)}" - steps[-1]["step"] = f"Factor out the GCD({sstr(div)}) from the right two terms of the inner polynomial" + steps[-1]["step"] = f"Factor out {sstr(div)} to match the common binomial" steps[-1]["rule"] = "Reverse Distributive Property" - ## Add Like Terms + ## Factor out base if steps[-1]["before"] != steps[-1]["after"]: steps.append({}) steps[-1]["before"] = steps[-2]["after"] terms = left_expr.as_ordered_terms() factors = [set(t.as_ordered_factors()) for t in terms] common = set.intersection(*factors) + print(f"common:{common}, factors:{factors}, terms:{terms}, left_expr:{sstr(left_expr)}") base = list(common)[0] coeffs = [t.coeff(base) for t in terms] new_expr = sum(coeffs) * base - new_left_expr = flatten_mul(Mul(n, new_expr, evaluate=False)) + new_left_expr = new_expr + if n != 1: + new_left_expr = flatten_mul(Mul(n, new_left_expr, evaluate=False)) steps[-1]["after"] = f"{sstr(new_left_expr)} = {sstr(right_expr)}" - steps[-1]["step"] = f"Collect the like terms" - steps[-1]["rule"] = "Combine the like terms" + steps[-1]["step"] = f"Factor out the common factor ({sstr(base)})" + steps[-1]["rule"] = "Reverse Distributive Property" return steps @@ -350,7 +370,7 @@ def solve_roots(equation): steps[-1]["before"] = equation steps[-1]["after"] = f"{sstr(clean_factor)} = 0" steps[-1]["step"] = f"Focus on a root" - steps[-1]["rule"] = "Root of a polynomial" + steps[-1]["rule"] = "Zero Product Property" current = steps[-1]["after"] a = clean_factor.coeff(x) @@ -375,16 +395,17 @@ def solve_roots(equation): steps.append({}) steps[-1]["before"] = equation steps[-1]["after"] = solutions - steps[-1]["step"] = f"Solved The Roots" - steps[-1]["rule"] = "Root of a polynomial" + steps[-1]["step"] = f"List the potential solutions" + steps[-1]["rule"] = "Zero product property" return steps def combine_like_terms(equation): - step = {} + steps = [] + steps.append({}) current = equation - step["before"] = current + steps[-1]["before"] = current left, right = current.split("=") x = symbols('x') @@ -421,10 +442,14 @@ def combine_like_terms(equation): new_right_terms.append(coeff * base) new_right_expr = sum(new_right_terms) - step["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}" - step["step"] = "Collect Like Terms" - step["rule"] = "Combine the like terms" - return step + steps[-1]["after"] = f"{sstr(new_left_expr)} = {sstr(new_right_expr)}" + steps[-1]["step"] = "Collect Like Terms" + steps[-1]["rule"] = "Combine the like terms" + + if steps[-1]["before"] == steps[-1]["after"]: + steps = [] + + return steps def distribute_left_step(equation): steps = [] @@ -520,17 +545,17 @@ def check_roots(equation, roots): steps[-1]["before"] = steps[-2]["after"] steps[-1]["after"] = f"{sstr(l_result)} = {sstr(r_result)}" steps[-1]["step"] = f"{value} is correct" - steps[-1]["rule"] = "Found Root" + steps[-1]["rule"] = "Found a Valid Solution" if len(valid_roots) > 0: - valid_roots += "," + valid_roots += ", " valid_roots += f"x = {value}" steps.append({}) steps[-1]["before"] = equation steps[-1]["after"] = valid_roots - steps[-1]["step"] = f"Found Valid Roots" - steps[-1]["rule"] = "Found Solution" + steps[-1]["step"] = f"List Valid Solutions" + steps[-1]["rule"] = "Problem Solved" return steps @@ -624,9 +649,8 @@ def distribute_once(expr): # ------------------------------------------------------------ return expr, None -def clean(expr): - # remove explicit 1 multipliers +def clean(expr): expr = expr.replace( lambda e: isinstance(e, Mul), lambda e: Mul(*[arg for arg in e.args if arg != 1]) diff --git a/problem_generator.py b/problem_generator.py index c6a23f7..7511930 100644 --- a/problem_generator.py +++ b/problem_generator.py @@ -127,7 +127,7 @@ def generate_quadratic (): solution = sstr(root1) else: solution = [sstr(root1), sstr(root2)] - + return { "type": "quadratic", "problem": f"{sstr(expr)} = 0", @@ -265,6 +265,6 @@ def generate_problem(): problem_type = random.choices(types, weights=weights)[0] template = TEMPLATES[problem_type] - return generate_tricky() + return generate_quadratic() #return template() \ No newline at end of file diff --git a/steps_generator.py b/steps_generator.py index c152267..782a45e 100644 --- a/steps_generator.py +++ b/steps_generator.py @@ -207,7 +207,8 @@ def generate_like_terms_steps (problem): return steps @register_steps_generator("quadratic") -def generate_quadratic_steps (problem): +def generate_quadratic_steps (problem, skip_check=False): + print(f"calling generate_quadratic_steps with: {problem["problem"]}") #ax² + bx + c = 0 steps = [] @@ -245,12 +246,13 @@ def generate_quadratic_steps (problem): current = steps[-1]["after"] # Check for incorrect answers - steps.extend(algebraic_steps.check_roots(problem["problem"], current)) + if not skip_check: + steps.extend(algebraic_steps.check_roots(problem["problem"], current)) return steps @register_steps_generator("difference_squares") -def generate_difference_squares_steps (problem): +def generate_difference_squares_steps (problem, skip_check=False): #x² - a² = 0 steps = [] @@ -277,7 +279,8 @@ def generate_difference_squares_steps (problem): current = steps[-1]["after"] # Check for incorrect answers - steps.extend(algebraic_steps.check_roots(problem["problem"], current)) + if not skip_check: + steps.extend(algebraic_steps.check_roots(problem["problem"], current)) return steps @@ -292,7 +295,7 @@ def generate_zero_product_steps (problem): return steps @register_steps_generator("radical") -def generate_radical_steps (problem): +def generate_radical_steps (problem, skip_check=False): #√(x + a) = b steps = [] x = symbols('x') @@ -321,7 +324,8 @@ def generate_radical_steps (problem): current = steps[-1]["after"] # Check for incorrect answers - steps.extend(algebraic_steps.check_roots(problem["problem"], current)) + if not skip_check: + steps.extend(algebraic_steps.check_roots(problem["problem"], current)) return steps @@ -375,7 +379,7 @@ def generate_binomial_steps (problem): init_printing(order='lex') ## Combine Like Terms - steps.append(algebraic_steps.combine_like_terms(current)) + steps.extend(algebraic_steps.combine_like_terms(current)) current = steps[-1]["after"] left, right = current.split("=") left_expr = parse_expr(left, transformations=transformations) @@ -404,7 +408,7 @@ def generate_binomial_steps (problem): return steps @register_steps_generator("tricky") -def generate_tricky_steps (problem): +def generate_tricky_steps (problem, skip_check=False): #(x² - x - a) / (x + b) = c steps = [] x = symbols('x') @@ -429,16 +433,16 @@ def generate_tricky_steps (problem): current = steps[-1]["after"] # Combine Like Terms - steps.append(algebraic_steps.combine_like_terms(current)) + steps.extend(algebraic_steps.combine_like_terms(current)) current = steps[-1]["after"] # Solve Quadratic - print(f"calling generate_quadratic_steps with: {current}") - steps.extend(generate_quadratic_steps({"problem" : current})) + steps.extend(generate_quadratic_steps({"problem" : current}, True)) current = steps[-1]["after"] # Check for incorrect answers - steps.extend(algebraic_steps.check_roots(problem["problem"], current)) + if not skip_check: + steps.extend(algebraic_steps.check_roots(problem["problem"], current)) return steps