From d8632115b1fa5aac553013367f457ca4ccbf8df7 Mon Sep 17 00:00:00 2001 From: Accusedbold Date: Fri, 1 May 2026 13:50:06 -0400 Subject: [PATCH] Step Generator Polish, untested --- __pycache__/algebraic_steps.cpython-313.pyc | Bin 25796 -> 26591 bytes __pycache__/problem_generator.cpython-313.pyc | Bin 13421 -> 13469 bytes __pycache__/steps_generator.cpython-313.pyc | Bin 19285 -> 19414 bytes algebraic_steps.py | 102 +++++++++++------- problem_generator.py | 4 +- steps_generator.py | 28 ++--- 6 files changed, 81 insertions(+), 53 deletions(-) diff --git a/__pycache__/algebraic_steps.cpython-313.pyc b/__pycache__/algebraic_steps.cpython-313.pyc index 061f4cd27d4847d3198a114612e16205a049f442..7cd16c3df699b90601cab38f9430a78ed72a990e 100644 GIT binary patch delta 6160 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 diff --git a/__pycache__/problem_generator.cpython-313.pyc b/__pycache__/problem_generator.cpython-313.pyc index cf098ceb8295819b53f30ea2ccceb5084be169bb..03e379b61517a159a80282b8a7497aa076a52f63 100644 GIT binary patch delta 613 zcmaExF*lR@;HOJqWLHBiiU9; zGlg;n^XM_FFcdQ>0C65u8WKyB*RO~PXi||Nka)=pVrhd29S|W3B&zr-w6u&AbQLVM zDipL8EN(Fx-eRS1?dI4~UD6Ci_eO<$J&_-QaRVKzKrMM^%HzWFHwN6-5Sd ztDm>TEQ=+8$`0Ccx^i+H;$j1lrkt*P9EX|MT=_Onk}+gt3jr!9@|t{7HkvgY$n4py zDJRFo76B3crzAf)N5Pvl8pvHRIbT_9@?16c%{LW9nYhD1DnRZmikbXVsgN}R$XvfU zUwIo7TOvqQY;psy=wt^qC$3Z=cRvsppO}15L1J=;knHAzYM+=HQzl;&m6?1&i-$37 z@?9+z#;D0m+BIBRK$RCjs^cf~bNNp`BP}@jrh?$+pW2?xjM+e&lx2&&fzm|^KthwF z$PdK!2N8-OB4Bc}z5^>LY~F4@q5qUoz7Ql@3?d3ZL=l_-ixp2kV`#?@3QkRyTdXCO z1*yeFC6gtMj9IIIV(gOxjhxtJFLTRZV3D6Z%gEdbq_PMUOhup&DM|nlAnz4{TwMgR zwg{xL2ppX}AQmT(xW!?Uo1apelWJE~Gg;Vp4Zk!a+h=A5Ce05_K-NdA$>)q`vMCgS G)B^zA` z0C65u8WKyBYjVGo{Ny82i@5@UhU5WpvC8B^>A#a}WRz5-8N{uA-V(DcmH>($wB>YV z<~YQ~1|m&4T{$=oGqJgHY(6Ao$jBB1R8ZtG`KN3&YbcP}xj9l!j)^S{BC4k>KY5OV zH)|x2J9qMYWwFU;)z~+4DvC03hk#Uwf{3Wen#zT&aX{vp&GVJFF|oyiM8zgI@QO|@ zP;=r+26FcRaq)@C9~C4fcL>RD{;2kenK5bdMNyea+B}RYlXD!8`O5;S6h z26@CNk|Wq)BJjsxf(fRW5KRRA!w)2Br7D4HkeH~!Xqy@njZx2?-P!J9w^na5H|O4S z&*R?nopa{%6Xc6Gh%lRz!!tNyU;i?2VAV09h`fEwKjnAJc_qw~Bt%&_RAIBFjFBB7 zl32@bIiK>OjD*Z?*{RWwk%vp&@_iX{qU@?2D znOIUe!^lKoWY&l*foWoOqh6+-iL)^(p$*xfbK(a5e4JCb9wP(`3!6Z;GSK!tlY~m+gfnP20lp?Wb4Xa+^EA1wnu_v zo&w^8qehRvTQ{M*0DT&pm&X>RC}XfQ+P(r(32i=sL|yXH*i zdeFJ#gD?LN58k`4)`o88pcAFZi+z;m@vmEi`8kQBjh;}-<^m3r>SP#p1hl8rEpCpu z;oU}S2{)hB3MOD*569aAW>rFQRfM;ysx6M2#zA!;J_2VP5=>R?%ojB7O@4USz~I*H zJNviqf@@w64EWtf0mZ!VvcI;v52*?KhA$w(_cPye)^U5&`HqWS6U*Ain>xn%&PlH8 zwq1ah{2Hi#zz9MaKW47JpOpVkJ8G1cDf2@k^Y}f`fZUphG%p-rTg`#|O=wZw zjMF=O0u)=|@`|M}(k?-;w%pc_oImj!ju7ZG*Tbu|-!CeFC+gm`X{voxe+;ue*zV>g!FGLWa>hgLUCd5huhie}>ws_GsKG@oOMnN~yixrK)pmKVUKXceaz zFdEp;;QdIR$Dv0Gqn5AJvNahs3C_4AI20D(n~DNB8_ofB4Jy$R*+jImr>VY@=Y&tW z5~z%nrS0}d!X#zMwSc9V1MWmlrAeM@38z-0WD^{2^}xB-a^i)nt-$X?KX=oIx{D9x z89TK4E3(LX^*^cwZQ4Ojg!Q==%O2YIPbw^S@zCzh6|j zCkM1kUdfYaH_Va+;T0wDd>ii=L2K$BI^n+x^GF~UJD~`ZZC=webaNB@-WDoQ`zTHG zC19H?lw~&jwPDn!=`;v6tBaw<%omQR1KW2!yLEV^e{fiR5qT#mR5l<~BD4*{O#270 zq0SnebOg>epWi#ar1i3R-O)bDb=(jNUVHG!z^Hjb@b2$eOs8Z!zcU_06CcA*ot-Rc zhfvq!6@AnnTDnzQb5)ww>JXhMZZ(h8gYaROi$8*E^o<$b4R^XO)y}d@h-22ku>NUE y&GZt6Eg3JVyH4t7S$BffFiokM)da4s^*Lr)Z(_T0no=`s;IFk|G7I5{ivI@l_8Is9 delta 1920 zcma)6Uu;ul6u;kXZ`*rs|I*&xt>yN1OJ#Jd>$0t|mTjd9+kiR4E;mjJDi9}QvCLbM z#1|okApVJ&CnC`hFm(q72V|`+u&0IRc-=NB!g)niguJWjo?)g=>OzXz!Br4-$D|vw17R6Cy4XoM zqGrz=VVJ$c$PwTuA8=}p%oH-ZkwL(_MIr%6a4P)f4f=Qv&1eGM3zo;ms|rw#x#T8? zDV91j-8Jcxjc`&5d+xJP)fZ|GCm9BQvGhXJT=&H%pZsvz%xYH>> zxhq1<1P~tX4TPXAF)d=<86%I|r#vPh1|Ot(uE^sVzDx9q`;oYdUolgEwg_u8Ubq=r z4du2s!80a+H5qzf7IMk=s~+0Wh_MT9C9~W#lB;1|&xo0yJ2XFWXi;7dK zfZ+BZxFwgpfiJsmr+}sSp$NW+Vdf$#EGscHqwz=>+Bf*kY(E`|!C7t{oQvedCd2S2 z%CG}|xZUf40kz9QCKZI50xePLewg&Z$9>cOMt+Qa7+N(mN`HrN5Kn8cdy69r6aBFV z;$Y#O)K3;N3(u$LghQw@MpbsfM1OQa%$#6hrxbwCvjTC$`N56E2RYgQ_K;Wcn`yvJ z=kkF%t?`%@nt>ic7KKJm9B^nT=+s2Bg}+4=2M}AJhPV*54%fUvxM2;!&7pQgpXm|W zhX?x`q}$;&ryJhebc}lmSqB!P zIl`KCzD?_Vur}0G;V@2&xs%w%BJFc{YO?_M9tlEsRDz`J4&;4}N82?=nnbIENyRFg z0EZsg6>JjX>q1TT)^ie_3n=QwBLCwjxuszuk`Fih2)f11^s)7(t9g`sN<)IxEj=Vf zU|wn?bj+#$#ta=TGIWm!ZUfbfBHa$-2G`ca;T%qzJtI-uiUBGkevyX~~*{zedCVIjLSAyTu(x;}>9d>ll2wb#IIgJA<~q zL3`DpP&X)e4O&x!24WnCjoTFARU|ParZ@}xwtd}IVb>DhiiKf2mMK-)Nfg#RT+kf?QOmat5&%WEmNxUFdW@JNGfn)d+XnXjJ2r% 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