j-js commited on
Commit
10fdac3
·
verified ·
1 Parent(s): 1457c41

Update explainers/explainer_ratio.py

Browse files
Files changed (1) hide show
  1. explainers/explainer_ratio.py +120 -112
explainers/explainer_ratio.py CHANGED
@@ -1,183 +1,191 @@
1
  import re
2
- from explainer_types import ExplainerResult, ExplainerScaffold
3
-
4
-
5
- _RATIO_PATTERNS = [
6
- r"\bratio\b",
7
- r"\bproportion\b",
8
- r"\bfor every\b",
9
- r"\bto\b",
10
- r":",
11
- r"\bout of\b",
12
- r"\brespectively\b",
13
- r"\bpart to part\b",
14
- r"\bpart to whole\b",
15
  ]
16
 
17
 
18
- def _looks_like_ratio_question(text: str) -> bool:
19
  low = (text or "").lower()
20
 
21
- if re.search(r"\b\d+\s*:\s*\d+\b", low):
22
  return True
23
- if "for every" in low:
24
  return True
25
- if "ratio" in low or "proportion" in low:
26
- return True
27
-
28
  return False
29
 
30
 
31
- def _infer_ratio_subtype(text: str) -> str:
32
  low = (text or "").lower()
33
 
34
- if any(k in low for k in ["for every", "ratio of", "respectively"]):
35
- return "ratio_parts"
36
- if any(k in low for k in ["total", "sum", "combined"]):
37
- return "part_to_total"
38
- if any(k in low for k in ["proportion", "directly proportional", "inversely proportional"]):
39
- return "proportion"
40
- if any(k in low for k in ["mixture", "men and women", "boys and girls", "red and blue", "apples and oranges"]):
41
- return "group_ratio"
42
- return "generic_ratio"
43
-
44
-
45
- def explain_ratio(text: str):
46
- if not _looks_like_ratio_question(text):
 
 
47
  return None
48
 
49
- subtype = _infer_ratio_subtype(text)
50
 
51
  result = ExplainerResult(
52
  understood=True,
53
- topic="ratio",
54
- 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."
55
  )
56
 
57
  scaffold = ExplainerScaffold(
58
- concept="A ratio compares quantities by relative size, not by actual amount.",
59
- 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.",
60
- target="Translate the ratio into variable-based quantities that can be linked to the condition in the question.",
61
  answer_hidden=True,
62
  )
63
 
64
  teaching_points = [
65
- "A ratio does not give actual quantities until a common scale factor is applied.",
66
- "Most ratio questions become simple algebra once each part is written in terms of the same multiplier.",
67
- "The order matters. Reversing the ratio changes the meaning of the whole setup."
68
  ]
69
 
70
- if subtype == "ratio_parts":
71
  scaffold.setup_actions = [
72
- "Write each ratio part using a common multiplier such as ak and bk.",
73
- "Keep the terms in the same order as the original ratio statement.",
74
- "Use the condition in the question to connect those expressions to actual values."
75
  ]
76
  scaffold.intermediate_steps = [
77
- "If one part is known, solve for the multiplier first.",
78
- "If a total is given, add the ratio expressions.",
79
- "If a difference is given, subtract the relevant ratio expressions."
80
  ]
81
- scaffold.first_move = "Rewrite each ratio term as a multiple of the same variable."
82
- scaffold.next_hint = "Then connect those expressions to the value or condition given in the question."
83
  scaffold.variables_to_define = [
84
- "Let the common multiplier be k."
85
  ]
86
  scaffold.equations_to_form = [
87
- "amounts = ratio parts × common multiplier"
88
  ]
89
  scaffold.common_traps = [
90
- "Reversing the order of the ratio.",
91
- "Treating the ratio numbers as final quantities instead of scaled parts.",
92
- "Forgetting that different parts must all use the same multiplier."
93
  ]
94
 
95
- elif subtype == "part_to_total":
96
  scaffold.setup_actions = [
97
- "Represent each part with a shared multiplier.",
98
- "Add the ratio parts to represent the total.",
99
- "Match the part or total expression to the given condition."
100
  ]
101
  scaffold.intermediate_steps = [
102
- "Translate the whole ratio into algebraic amounts first.",
103
- "Use the sum of all parts for the total.",
104
- "Check whether the question asks for one component or the overall total."
105
- ]
106
- scaffold.first_move = "Turn the ratio into variable-based amounts and add them to get the total structure."
107
- scaffold.next_hint = "Use the given total to solve for the shared multiplier."
108
- scaffold.variables_to_define = [
109
- "Let the common multiplier be k."
110
  ]
 
 
111
  scaffold.equations_to_form = [
112
- "total = sum of all ratio parts × k"
113
  ]
114
  scaffold.common_traps = [
115
- "Using only one part instead of the full sum when a total is given.",
116
- "Dropping one category from the total.",
117
- "Solving for the multiplier and forgetting to return to the quantity actually asked for."
118
  ]
119
 
120
- elif subtype == "proportion":
121
  scaffold.setup_actions = [
122
- "Identify which two ratios or rates are being set equal.",
123
- "Preserve matching positions carefully.",
124
- "Use cross-multiplication only after the correspondence is correct."
125
  ]
126
  scaffold.intermediate_steps = [
127
- "Line up like-with-like before building the proportion.",
128
- "Check units or roles so the comparison makes sense.",
129
- "Then simplify the resulting equation."
130
- ]
131
- scaffold.first_move = "Match the corresponding quantities in the two ratios."
132
- scaffold.next_hint = "Once the matching is correct, form the equation between the two ratios."
133
- scaffold.equations_to_form = [
134
- "first ratio = second ratio"
135
  ]
 
 
136
  scaffold.common_traps = [
137
- "Matching the wrong terms across the two ratios.",
138
- "Cross-multiplying before the setup is correct.",
139
- "Ignoring whether the problem is direct or inverse proportion."
140
  ]
141
 
142
- elif subtype == "group_ratio":
143
  scaffold.setup_actions = [
144
- "Assign each group its ratio-based expression.",
145
- "Use the stated total, difference, or known subgroup size to create an equation.",
146
- "Solve for the common multiplier before finding the requested quantity."
147
  ]
148
  scaffold.intermediate_steps = [
149
- "Make sure each category is represented exactly once.",
150
- "Check whether the condition is about the whole group or one subgroup.",
151
- "Return to the requested category at the end."
152
  ]
153
- scaffold.first_move = "Represent each group using the same scaling variable."
154
- scaffold.next_hint = "Then use the condition involving the total or one group to solve for that variable."
155
- scaffold.variables_to_define = [
156
- "Let the common multiplier be k."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  ]
 
 
158
  scaffold.common_traps = [
159
- "Using separate multipliers for parts of the same ratio.",
160
- "Answering with the multiplier instead of the requested group amount.",
161
- "Losing the original ratio order when translating categories."
162
  ]
163
 
164
  else:
165
  scaffold.setup_actions = [
166
- "Identify what each term in the ratio represents.",
167
- "Translate the ratio into algebraic quantities with a common scale factor.",
168
- "Use the stated condition to solve for the scale factor."
169
  ]
170
  scaffold.intermediate_steps = [
171
- "Use the sum if a total is involved.",
172
- "Use subtraction if a difference is involved.",
173
- "Check which final quantity the question wants."
174
  ]
175
- scaffold.first_move = "Start by assigning a shared multiplier to the ratio parts."
176
- scaffold.next_hint = "Then use the given condition to turn the ratio setup into an equation."
177
  scaffold.common_traps = [
178
- "Reversing the order of the ratio.",
179
- "Not using one shared multiplier.",
180
- "Stopping at the multiplier instead of the requested quantity."
181
  ]
182
 
183
  result.teaching_points = teaching_points
 
1
  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