Step Generator Polish, untested

This commit is contained in:
2026-05-01 13:50:06 -04:00
parent a98042ca5b
commit d8632115b1
6 changed files with 81 additions and 53 deletions

View File

@@ -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])

View File

@@ -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()

View File

@@ -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