j-js commited on
Commit
508bc51
·
verified ·
1 Parent(s): e61901b

Update explainers/explainer_ratio.py

Browse files
Files changed (1) hide show
  1. explainers/explainer_ratio.py +99 -120
explainers/explainer_ratio.py CHANGED
@@ -2,190 +2,169 @@ import re
2
  from .explainer_types import ExplainerResult, ExplainerScaffold
3
 
4
 
5
- _ALGEBRA_PATTERNS = [
6
- r"=",
7
- r"\bsolve\b",
8
- r"\bequation\b",
9
- r"\bexpression\b",
10
- r"\bvalue of\b",
11
- r"\bwhat is x\b",
12
- r"\bwhat is y\b",
13
- r"\bvariable\b",
14
- ]
15
-
16
-
17
- def _looks_like_algebra_question(text: str) -> bool:
18
  low = (text or "").lower()
19
 
20
- if re.search(r"\b[xyzab]\b", low) and "=" in low:
21
  return True
22
- if any(re.search(p, low) for p in _ALGEBRA_PATTERNS):
23
  return True
 
 
 
24
  return False
25
 
26
 
27
- def _infer_algebra_subtype(text: str) -> str:
28
  low = (text or "").lower()
29
 
30
- if any(k in low for k in ["system", "simultaneous", "x and y", "two equations"]):
31
- return "system"
32
- if any(k in low for k in ["inequality", "<", ">", "at least", "at most", "no more than"]):
33
- return "inequality"
34
- if any(k in low for k in ["quadratic", "squared", "^2", "x2", "root", "factor"]):
35
- return "quadratic"
36
- if any(k in low for k in ["expression", "value of 2x", "value of x +", "in terms of"]):
37
- return "expression_evaluation"
38
- if "=" in low:
39
- return "linear_equation"
40
- return "generic_algebra"
41
-
42
-
43
- def explain_algebra_question(text: str):
44
- if not _looks_like_algebra_question(text):
45
  return None
46
 
47
- subtype = _infer_algebra_subtype(text)
48
 
49
  result = ExplainerResult(
50
  understood=True,
51
- topic="algebra",
52
- summary="This is an algebra problem. The main goal is to translate the wording into a clean symbolic relationship and isolate the requested quantity step by step."
53
  )
54
 
55
  scaffold = ExplainerScaffold(
56
- concept="Algebra represents unknown quantities symbolically, then uses valid transformations to isolate or compare them.",
57
- ask="Identify the unknown, identify the governing relationship, and check whether the question wants the variable itself or an expression built from it.",
58
- target="Set up the simplest correct equation or relation before manipulating it.",
59
  answer_hidden=True,
60
  )
61
 
62
  teaching_points = [
63
- "Most algebra errors happen before the solving starts: either the variable is misdefined, or the equation is set up incorrectly.",
64
- "A clean equation makes the solving steps much easier.",
65
- "You should always check whether the question asks for x itself or for something derived from x."
66
  ]
67
 
68
- if subtype == "linear_equation":
69
  scaffold.setup_actions = [
70
- "Identify the unknown and write the equation cleanly.",
71
- "Simplify each side if needed.",
72
- "Undo operations in a logical order to isolate the variable."
73
  ]
74
  scaffold.intermediate_steps = [
75
- "Combine like terms first when possible.",
76
- "Move variable terms and constant terms carefully.",
77
- "Check whether the final result should be the variable or a substituted expression."
78
  ]
79
- scaffold.first_move = "Rewrite the relationship as one clean equation if it is not already in that form."
80
- scaffold.next_hint = "Simplify both sides before isolating the variable."
81
  scaffold.variables_to_define = [
82
- "Let the unknown quantity be x if the question has not already named it."
83
  ]
84
  scaffold.equations_to_form = [
85
- "Build one equation from the stated relationship."
86
  ]
87
  scaffold.common_traps = [
88
- "Moving terms across the equals sign incorrectly.",
89
- "Trying to isolate the variable before simplifying.",
90
- "Finding x and forgetting the question asks for something like 2x or x + 3."
91
  ]
92
 
93
- elif subtype == "system":
94
  scaffold.setup_actions = [
95
- "Identify the separate equations and unknowns.",
96
- "Decide whether substitution or elimination is the cleaner method.",
97
- "Reduce the system to one variable before solving completely."
98
  ]
99
  scaffold.intermediate_steps = [
100
- "Make one variable easy to substitute, or align coefficients for elimination.",
101
- "After finding one variable, substitute back carefully.",
102
- "Check whether the question asks for one variable, both variables, or a combination of them."
 
 
 
 
 
103
  ]
104
- scaffold.first_move = "Choose one variable to eliminate or substitute."
105
- scaffold.next_hint = "Turn the system into a single-variable equation before solving."
106
  scaffold.equations_to_form = [
107
- "Use the two given equations together to reduce to one unknown."
108
  ]
109
  scaffold.common_traps = [
110
- "Mixing substitution and elimination without a clear plan.",
111
- "Arithmetic mistakes when substituting back.",
112
- "Stopping after finding one variable when the question asks for something else."
113
  ]
114
 
115
- elif subtype == "inequality":
116
  scaffold.setup_actions = [
117
- "Translate the condition into an inequality.",
118
- "Manipulate it like an equation, but track the inequality direction carefully.",
119
- "Reverse the sign only if multiplying or dividing by a negative number."
120
  ]
121
  scaffold.intermediate_steps = [
122
- "Simplify both sides first if possible.",
123
- "Isolate the variable systematically.",
124
- "Interpret the final solution set in the form the question wants."
125
- ]
126
- scaffold.first_move = "Set up the inequality carefully from the wording."
127
- scaffold.next_hint = "Solve it step by step, watching for any operation that would reverse the sign."
128
- scaffold.common_traps = [
129
- "Forgetting to reverse the inequality when dividing or multiplying by a negative.",
130
- "Treating phrase-based conditions like at least or no more than incorrectly.",
131
- "Reporting a single number when the solution is actually a range."
132
  ]
133
-
134
- elif subtype == "quadratic":
135
- scaffold.setup_actions = [
136
- "Rewrite the equation so one side is zero if needed.",
137
- "Look for factoring, structure, or another simplifying method.",
138
- "Treat each factor or case carefully once the equation is structured properly."
139
- ]
140
- scaffold.intermediate_steps = [
141
- "Factor if the form allows it.",
142
- "Otherwise identify another clean solving route.",
143
- "Check whether all resulting values are allowed in the original context."
144
  ]
145
- scaffold.first_move = "Put the expression into a standard structured form before solving."
146
- scaffold.next_hint = "Then look for a factorable pattern or another clean route."
147
  scaffold.common_traps = [
148
- "Trying to factor before the expression is fully simplified.",
149
- "Dropping one valid case.",
150
- "Giving roots when the question asks for a derived expression instead."
151
  ]
152
 
153
- elif subtype == "expression_evaluation":
154
  scaffold.setup_actions = [
155
- "Find the variable or relationship first.",
156
- "Only then substitute into the requested expression.",
157
- "Simplify the final expression carefully."
158
  ]
159
  scaffold.intermediate_steps = [
160
- "Do not stop when you find the variable unless that is exactly what the question asks.",
161
- "Preserve parentheses during substitution.",
162
- "Check whether there is a shortcut using the given relationship directly."
 
 
 
 
 
163
  ]
164
- scaffold.first_move = "Work out whether you need to solve for the variable first or can rewrite the target expression directly."
165
- scaffold.next_hint = "Once the relationship is clear, substitute only into the exact expression the question asks for."
166
  scaffold.common_traps = [
167
- "Stopping at x when the question asks for something built from x.",
168
- "Substituting incorrectly into expressions with multiple terms.",
169
- "Ignoring an easier algebraic simplification path."
170
  ]
171
 
172
  else:
173
  scaffold.setup_actions = [
174
- "Define the unknown clearly.",
175
- "Translate the wording into a symbolic relationship.",
176
- "Manipulate the relationship only after the setup is clean."
177
  ]
178
  scaffold.intermediate_steps = [
179
- "Simplify before isolating.",
180
- "Keep track of what the question actually asks for.",
181
- "Check the final quantity against the prompt."
182
  ]
183
- scaffold.first_move = "Start by translating the words into one clean symbolic statement."
184
- scaffold.next_hint = "Then simplify the structure before solving."
185
  scaffold.common_traps = [
186
- "Poor variable definition.",
187
- "Messy setup before solving.",
188
- "Answering the wrong final quantity."
189
  ]
190
 
191
  result.teaching_points = teaching_points
 
2
  from .explainer_types import ExplainerResult, ExplainerScaffold
3
 
4
 
5
+ def _looks_like_ratio_question(text: str) -> bool:
 
 
 
 
 
 
 
 
 
 
 
 
6
  low = (text or "").lower()
7
 
8
+ if re.search(r"\b\d+\s*:\s*\d+\b", low):
9
  return True
10
+ if "for every" in low:
11
  return True
12
+ if "ratio" in low or "proportion" in low:
13
+ return True
14
+
15
  return False
16
 
17
 
18
+ def _infer_ratio_subtype(text: str) -> str:
19
  low = (text or "").lower()
20
 
21
+ if any(k in low for k in ["for every", "ratio of", "respectively"]):
22
+ return "ratio_parts"
23
+ if any(k in low for k in ["total", "sum", "combined"]):
24
+ return "part_to_total"
25
+ if any(k in low for k in ["proportion", "directly proportional", "inversely proportional"]):
26
+ return "proportion"
27
+ if any(k in low for k in ["mixture", "men and women", "boys and girls", "red and blue", "apples and oranges"]):
28
+ return "group_ratio"
29
+ return "generic_ratio"
30
+
31
+
32
+ def explain_ratio_question(text: str):
33
+ if not _looks_like_ratio_question(text):
 
 
34
  return None
35
 
36
+ subtype = _infer_ratio_subtype(text)
37
 
38
  result = ExplainerResult(
39
  understood=True,
40
+ topic="ratio",
41
+ summary="This is a ratio problem. The main job is to preserve the order of the ratio and convert ratio parts into actual quantities using one shared multiplier."
42
  )
43
 
44
  scaffold = ExplainerScaffold(
45
+ concept="A ratio compares quantities by relative size, not by actual amount.",
46
+ ask="Decide what each side of the ratio refers to, keep the order exact, and determine whether the question wants one part, a total, a difference, or a scaled version.",
47
+ target="Translate the ratio into variable-based quantities that can be linked to the condition in the question.",
48
  answer_hidden=True,
49
  )
50
 
51
  teaching_points = [
52
+ "A ratio does not give actual quantities until a common scale factor is applied.",
53
+ "Most ratio questions become simple algebra once each part is written in terms of the same multiplier.",
54
+ "The order matters. Reversing the ratio changes the meaning of the whole setup."
55
  ]
56
 
57
+ if subtype == "ratio_parts":
58
  scaffold.setup_actions = [
59
+ "Write each ratio part using a common multiplier such as ak and bk.",
60
+ "Keep the terms in the same order as the original ratio statement.",
61
+ "Use the condition in the question to connect those expressions to actual values."
62
  ]
63
  scaffold.intermediate_steps = [
64
+ "If one part is known, solve for the multiplier first.",
65
+ "If a total is given, add the ratio expressions.",
66
+ "If a difference is given, subtract the relevant ratio expressions."
67
  ]
68
+ scaffold.first_move = "Rewrite each ratio term as a multiple of the same variable."
69
+ scaffold.next_hint = "Then connect those expressions to the value or condition given in the question."
70
  scaffold.variables_to_define = [
71
+ "Let the common multiplier be k."
72
  ]
73
  scaffold.equations_to_form = [
74
+ "amounts = ratio parts × common multiplier"
75
  ]
76
  scaffold.common_traps = [
77
+ "Reversing the order of the ratio.",
78
+ "Treating the ratio numbers as final quantities instead of scaled parts.",
79
+ "Forgetting that different parts must all use the same multiplier."
80
  ]
81
 
82
+ elif subtype == "part_to_total":
83
  scaffold.setup_actions = [
84
+ "Represent each part with a shared multiplier.",
85
+ "Add the ratio parts to represent the total.",
86
+ "Match the part or total expression to the given condition."
87
  ]
88
  scaffold.intermediate_steps = [
89
+ "Translate the whole ratio into algebraic amounts first.",
90
+ "Use the sum of all parts for the total.",
91
+ "Check whether the question asks for one component or the overall total."
92
+ ]
93
+ scaffold.first_move = "Turn the ratio into variable-based amounts and add them to get the total structure."
94
+ scaffold.next_hint = "Use the given total to solve for the shared multiplier."
95
+ scaffold.variables_to_define = [
96
+ "Let the common multiplier be k."
97
  ]
 
 
98
  scaffold.equations_to_form = [
99
+ "total = sum of all ratio parts × k"
100
  ]
101
  scaffold.common_traps = [
102
+ "Using only one part instead of the full sum when a total is given.",
103
+ "Dropping one category from the total.",
104
+ "Solving for the multiplier and forgetting to return to the quantity actually asked for."
105
  ]
106
 
107
+ elif subtype == "proportion":
108
  scaffold.setup_actions = [
109
+ "Identify which two ratios or rates are being set equal.",
110
+ "Preserve matching positions carefully.",
111
+ "Use cross-multiplication only after the correspondence is correct."
112
  ]
113
  scaffold.intermediate_steps = [
114
+ "Line up like-with-like before building the proportion.",
115
+ "Check units or roles so the comparison makes sense.",
116
+ "Then simplify the resulting equation."
 
 
 
 
 
 
 
117
  ]
118
+ scaffold.first_move = "Match the corresponding quantities in the two ratios."
119
+ scaffold.next_hint = "Once the matching is correct, form the equation between the two ratios."
120
+ scaffold.equations_to_form = [
121
+ "first ratio = second ratio"
 
 
 
 
 
 
 
122
  ]
 
 
123
  scaffold.common_traps = [
124
+ "Matching the wrong terms across the two ratios.",
125
+ "Cross-multiplying before the setup is correct.",
126
+ "Ignoring whether the problem is direct or inverse proportion."
127
  ]
128
 
129
+ elif subtype == "group_ratio":
130
  scaffold.setup_actions = [
131
+ "Assign each group its ratio-based expression.",
132
+ "Use the stated total, difference, or known subgroup size to create an equation.",
133
+ "Solve for the common multiplier before finding the requested quantity."
134
  ]
135
  scaffold.intermediate_steps = [
136
+ "Make sure each category is represented exactly once.",
137
+ "Check whether the condition is about the whole group or one subgroup.",
138
+ "Return to the requested category at the end."
139
+ ]
140
+ scaffold.first_move = "Represent each group using the same scaling variable."
141
+ scaffold.next_hint = "Then use the condition involving the total or one group to solve for that variable."
142
+ scaffold.variables_to_define = [
143
+ "Let the common multiplier be k."
144
  ]
 
 
145
  scaffold.common_traps = [
146
+ "Using separate multipliers for parts of the same ratio.",
147
+ "Answering with the multiplier instead of the requested group amount.",
148
+ "Losing the original ratio order when translating categories."
149
  ]
150
 
151
  else:
152
  scaffold.setup_actions = [
153
+ "Identify what each term in the ratio represents.",
154
+ "Translate the ratio into algebraic quantities with a common scale factor.",
155
+ "Use the stated condition to solve for the scale factor."
156
  ]
157
  scaffold.intermediate_steps = [
158
+ "Use the sum if a total is involved.",
159
+ "Use subtraction if a difference is involved.",
160
+ "Check which final quantity the question wants."
161
  ]
162
+ scaffold.first_move = "Start by assigning a shared multiplier to the ratio parts."
163
+ scaffold.next_hint = "Then use the given condition to turn the ratio setup into an equation."
164
  scaffold.common_traps = [
165
+ "Reversing the order of the ratio.",
166
+ "Not using one shared multiplier.",
167
+ "Stopping at the multiplier instead of the requested quantity."
168
  ]
169
 
170
  result.teaching_points = teaching_points