QuizGenerator 0.4.2__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. QuizGenerator/contentast.py +809 -117
  2. QuizGenerator/generate.py +219 -11
  3. QuizGenerator/misc.py +0 -556
  4. QuizGenerator/mixins.py +50 -29
  5. QuizGenerator/premade_questions/basic.py +3 -3
  6. QuizGenerator/premade_questions/cst334/languages.py +183 -175
  7. QuizGenerator/premade_questions/cst334/math_questions.py +81 -70
  8. QuizGenerator/premade_questions/cst334/memory_questions.py +262 -165
  9. QuizGenerator/premade_questions/cst334/persistence_questions.py +83 -60
  10. QuizGenerator/premade_questions/cst334/process.py +558 -79
  11. QuizGenerator/premade_questions/cst463/gradient_descent/gradient_calculation.py +39 -13
  12. QuizGenerator/premade_questions/cst463/gradient_descent/gradient_descent_questions.py +61 -36
  13. QuizGenerator/premade_questions/cst463/gradient_descent/loss_calculations.py +29 -10
  14. QuizGenerator/premade_questions/cst463/gradient_descent/misc.py +2 -2
  15. QuizGenerator/premade_questions/cst463/math_and_data/matrix_questions.py +60 -43
  16. QuizGenerator/premade_questions/cst463/math_and_data/vector_questions.py +173 -326
  17. QuizGenerator/premade_questions/cst463/models/attention.py +29 -14
  18. QuizGenerator/premade_questions/cst463/models/cnns.py +32 -20
  19. QuizGenerator/premade_questions/cst463/models/rnns.py +28 -15
  20. QuizGenerator/premade_questions/cst463/models/text.py +29 -15
  21. QuizGenerator/premade_questions/cst463/models/weight_counting.py +38 -30
  22. QuizGenerator/premade_questions/cst463/neural-network-basics/neural_network_questions.py +91 -111
  23. QuizGenerator/premade_questions/cst463/tensorflow-intro/tensorflow_questions.py +128 -55
  24. QuizGenerator/question.py +114 -20
  25. QuizGenerator/quiz.py +81 -24
  26. QuizGenerator/regenerate.py +98 -29
  27. {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/METADATA +1 -1
  28. {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/RECORD +31 -33
  29. QuizGenerator/README.md +0 -5
  30. QuizGenerator/logging.yaml +0 -55
  31. {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/WHEEL +0 -0
  32. {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/entry_points.txt +0 -0
  33. {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -2,11 +2,11 @@ from __future__ import annotations
2
2
 
3
3
  import abc
4
4
  import logging
5
- from typing import List
5
+ from typing import List, Tuple
6
6
  import sympy as sp
7
7
 
8
- from QuizGenerator.contentast import ContentAST
9
- from QuizGenerator.question import Question, Answer, QuestionRegistry
8
+ from QuizGenerator.contentast import ContentAST, AnswerTypes
9
+ from QuizGenerator.question import Question, QuestionRegistry
10
10
  from .misc import generate_function, format_vector
11
11
 
12
12
  log = logging.getLogger(__name__)
@@ -39,6 +39,9 @@ class DerivativeQuestion(Question, abc.ABC):
39
39
  # Evaluate gradient at the specified point
40
40
  subs_map = dict(zip(self.variables, evaluation_point))
41
41
 
42
+ # Format evaluation point for label
43
+ eval_point_str = ", ".join([f"x_{i} = {evaluation_point[i]}" for i in range(self.num_variables)])
44
+
42
45
  # Create answer for each partial derivative
43
46
  for i in range(self.num_variables):
44
47
  answer_key = f"partial_derivative_{i}"
@@ -52,7 +55,9 @@ class DerivativeQuestion(Question, abc.ABC):
52
55
  raise ValueError("Complex number encountered - need to regenerate")
53
56
 
54
57
  # Use auto_float for Canvas compatibility with integers and decimals
55
- self.answers[answer_key] = Answer.auto_float(answer_key, gradient_value)
58
+ # Label includes the partial derivative notation
59
+ label = f"∂f/∂x_{i} at ({eval_point_str})"
60
+ self.answers[answer_key] = AnswerTypes.Float(gradient_value, label=label)
56
61
 
57
62
  def _create_gradient_vector_answer(self) -> None:
58
63
  """Create a single gradient vector answer for PDF format."""
@@ -70,10 +75,12 @@ class DerivativeQuestion(Question, abc.ABC):
70
75
 
71
76
  # Format as vector for display using consistent formatting
72
77
  vector_str = format_vector(gradient_values)
73
- self.answers["gradient_vector"] = Answer.string("gradient_vector", vector_str, pdf_only=True)
78
+ self.answers["gradient_vector"] = AnswerTypes.String(vector_str, pdf_only=True)
74
79
 
75
- def get_body(self, **kwargs) -> ContentAST.Section:
80
+ def _get_body(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
81
+ """Build question body and collect answers."""
76
82
  body = ContentAST.Section()
83
+ answers = []
77
84
 
78
85
  # Display the function
79
86
  body.add_element(
@@ -103,6 +110,8 @@ class DerivativeQuestion(Question, abc.ABC):
103
110
 
104
111
  # For Canvas: Use OnlyHtml to show individual partial derivatives
105
112
  for i in range(self.num_variables):
113
+ answer = self.answers[f"partial_derivative_{i}"]
114
+ answers.append(answer)
106
115
  body.add_element(
107
116
  ContentAST.OnlyHtml([
108
117
  ContentAST.Paragraph([
@@ -110,14 +119,20 @@ class DerivativeQuestion(Question, abc.ABC):
110
119
  f"\\left. {self._format_partial_derivative(i)} \\right|_{{{eval_point_str}}} = ",
111
120
  inline=True
112
121
  ),
113
- ContentAST.Answer(self.answers[f"partial_derivative_{i}"])
122
+ answer
114
123
  ])
115
124
  ])
116
125
  )
117
126
 
127
+ return body, answers
128
+
129
+ def get_body(self, **kwargs) -> ContentAST.Section:
130
+ """Build question body (backward compatible interface)."""
131
+ body, _ = self._get_body(**kwargs)
118
132
  return body
119
133
 
120
- def get_explanation(self, **kwargs) -> ContentAST.Section:
134
+ def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
135
+ """Build question explanation."""
121
136
  explanation = ContentAST.Section()
122
137
 
123
138
  # Show the function and its gradient
@@ -147,14 +162,14 @@ class DerivativeQuestion(Question, abc.ABC):
147
162
  partial_expr = self.gradient_function[i]
148
163
  partial_value = partial_expr.subs(subs_map)
149
164
 
150
- # Use Answer.accepted_strings for clean numerical formatting
165
+ # Use ContentAST.Answer.accepted_strings for clean numerical formatting
151
166
  try:
152
167
  numerical_value = float(partial_value)
153
168
  except (TypeError, ValueError):
154
169
  numerical_value = float(partial_value.evalf())
155
170
 
156
171
  # Get clean string representation
157
- clean_value = sorted(Answer.accepted_strings(numerical_value), key=lambda s: len(s))[0]
172
+ clean_value = sorted(ContentAST.Answer.accepted_strings(numerical_value), key=lambda s: len(s))[0]
158
173
 
159
174
  explanation.add_element(
160
175
  ContentAST.Paragraph([
@@ -165,6 +180,11 @@ class DerivativeQuestion(Question, abc.ABC):
165
180
  ])
166
181
  )
167
182
 
183
+ return explanation, []
184
+
185
+ def get_explanation(self, **kwargs) -> ContentAST.Section:
186
+ """Build question explanation (backward compatible interface)."""
187
+ explanation, _ = self._get_explanation(**kwargs)
168
188
  return explanation
169
189
 
170
190
 
@@ -264,7 +284,8 @@ class DerivativeChain(DerivativeQuestion):
264
284
  f = sp.Function('f')
265
285
  self.equation = sp.Eq(f(*self.variables), self.function)
266
286
 
267
- def get_explanation(self, **kwargs) -> ContentAST.Section:
287
+ def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
288
+ """Build question explanation."""
268
289
  explanation = ContentAST.Section()
269
290
 
270
291
  # Show the composed function structure
@@ -348,14 +369,14 @@ class DerivativeChain(DerivativeQuestion):
348
369
  partial_expr = self.gradient_function[i]
349
370
  partial_value = partial_expr.subs(subs_map)
350
371
 
351
- # Use Answer.accepted_strings for clean numerical formatting
372
+ # Use ContentAST.Answer.accepted_strings for clean numerical formatting
352
373
  try:
353
374
  numerical_value = float(partial_value)
354
375
  except (TypeError, ValueError):
355
376
  numerical_value = float(partial_value.evalf())
356
377
 
357
378
  # Get clean string representation
358
- clean_value = sorted(Answer.accepted_strings(numerical_value), key=lambda s: len(s))[0]
379
+ clean_value = sorted(ContentAST.Answer.accepted_strings(numerical_value), key=lambda s: len(s))[0]
359
380
 
360
381
  explanation.add_element(
361
382
  ContentAST.Paragraph([
@@ -366,4 +387,9 @@ class DerivativeChain(DerivativeQuestion):
366
387
  ])
367
388
  )
368
389
 
390
+ return explanation, []
391
+
392
+ def get_explanation(self, **kwargs) -> ContentAST.Section:
393
+ """Build question explanation (backward compatible interface)."""
394
+ explanation, _ = self._get_explanation(**kwargs)
369
395
  return explanation
@@ -6,8 +6,8 @@ import math
6
6
  from typing import List, Tuple, Callable, Union, Any
7
7
  import sympy as sp
8
8
 
9
- from QuizGenerator.contentast import ContentAST
10
- from QuizGenerator.question import Question, Answer, QuestionRegistry
9
+ from QuizGenerator.contentast import ContentAST, AnswerTypes
10
+ from QuizGenerator.question import Question, QuestionRegistry
11
11
  from QuizGenerator.mixins import TableQuestionMixin, BodyTemplatesMixin
12
12
 
13
13
  from .misc import generate_function, format_vector
@@ -15,6 +15,11 @@ from .misc import generate_function, format_vector
15
15
  log = logging.getLogger(__name__)
16
16
 
17
17
 
18
+ # Note: This file does not use ContentAST.Answer wrappers - it uses TableQuestionMixin
19
+ # which handles answer display through create_answer_table(). The answers are created
20
+ # with labels embedded at creation time in refresh().
21
+
22
+
18
23
  class GradientDescentQuestion(Question, abc.ABC):
19
24
  def __init__(self, *args, **kwargs):
20
25
  kwargs["topic"] = kwargs.get("topic", Question.Topic.ML_OPTIMIZATION)
@@ -86,30 +91,32 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
86
91
 
87
92
  # Set up answers
88
93
  self.answers = {}
89
-
94
+
90
95
  # Answers for each step
91
96
  for i, result in enumerate(self.gradient_descent_results):
92
97
  step = result['step']
93
-
98
+
94
99
  # Location answer
95
100
  location_key = f"answer__location_{step}"
96
- self.answers[location_key] = Answer.vector_value(location_key, list(result['location']))
97
-
101
+ self.answers[location_key] = AnswerTypes.Vector(list(result['location']), label=f"Location at step {step}")
102
+
98
103
  # Gradient answer
99
104
  gradient_key = f"answer__gradient_{step}"
100
- self.answers[gradient_key] = Answer.vector_value(gradient_key, list(result['gradient']))
101
-
105
+ self.answers[gradient_key] = AnswerTypes.Vector(list(result['gradient']), label=f"Gradient at step {step}")
106
+
102
107
  # Update answer
103
108
  update_key = f"answer__update_{step}"
104
- self.answers[update_key] = Answer.vector_value(update_key, list(result['update']))
109
+ self.answers[update_key] = AnswerTypes.Vector(list(result['update']), label=f"Update at step {step}")
105
110
 
106
- def get_body(self, **kwargs) -> ContentAST.Section:
111
+ def _get_body(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
112
+ """Build question body and collect answers."""
107
113
  body = ContentAST.Section()
108
-
114
+ answers = []
115
+
109
116
  # Introduction
110
117
  objective = "minimize" if self.minimize else "maximize"
111
118
  sign = "-" if self.minimize else "+"
112
-
119
+
113
120
  body.add_element(
114
121
  ContentAST.Paragraph(
115
122
  [
@@ -122,7 +129,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
122
129
  ]
123
130
  )
124
131
  )
125
-
132
+
126
133
  # Create table data - use ContentAST.Equation for proper LaTeX rendering in headers
127
134
  headers = [
128
135
  "n",
@@ -131,36 +138,49 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
131
138
  ContentAST.Equation("\\alpha \\cdot \\nabla f", inline=True)
132
139
  ]
133
140
  table_rows = []
134
-
141
+
135
142
  for i in range(self.num_steps):
136
143
  step = i + 1
137
144
  row = {"n": str(step)}
138
-
145
+
139
146
  if step == 1:
140
-
147
+
141
148
  # Fill in starting location for first row with default formatting
142
149
  row["location"] = f"{format_vector(self.starting_point)}"
143
150
  row[headers[2]] = f"answer__gradient_{step}" # gradient column
144
151
  row[headers[3]] = f"answer__update_{step}" # update column
152
+ # Collect answers for this step (no location answer for step 1)
153
+ answers.append(self.answers[f"answer__gradient_{step}"])
154
+ answers.append(self.answers[f"answer__update_{step}"])
145
155
  else:
146
156
  # Subsequent rows - all answer fields
147
157
  row["location"] = f"answer__location_{step}"
148
158
  row[headers[2]] = f"answer__gradient_{step}" # gradient column
149
159
  row[headers[3]] = f"answer__update_{step}" # update column
160
+ # Collect all answers for this step
161
+ answers.append(self.answers[f"answer__location_{step}"])
162
+ answers.append(self.answers[f"answer__gradient_{step}"])
163
+ answers.append(self.answers[f"answer__update_{step}"])
150
164
  table_rows.append(row)
151
-
165
+
152
166
  # Create the table using mixin
153
167
  gradient_table = self.create_answer_table(
154
168
  headers=headers,
155
169
  data_rows=table_rows,
156
170
  answer_columns=["location", headers[2], headers[3]] # Use actual header objects
157
171
  )
158
-
172
+
159
173
  body.add_element(gradient_table)
160
-
174
+
175
+ return body, answers
176
+
177
+ def get_body(self, **kwargs) -> ContentAST.Section:
178
+ """Build question body (backward compatible interface)."""
179
+ body, _ = self._get_body(**kwargs)
161
180
  return body
162
181
 
163
- def get_explanation(self, **kwargs) -> ContentAST.Section:
182
+ def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
183
+ """Build question explanation."""
164
184
  explanation = ContentAST.Section()
165
185
 
166
186
  explanation.add_element(
@@ -201,7 +221,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
201
221
  ]
202
222
  )
203
223
  )
204
-
224
+
205
225
  # Add completed table showing all solutions
206
226
  explanation.add_element(
207
227
  ContentAST.Paragraph(
@@ -210,7 +230,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
210
230
  ]
211
231
  )
212
232
  )
213
-
233
+
214
234
  # Create filled solution table
215
235
  solution_headers = [
216
236
  "n",
@@ -218,31 +238,31 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
218
238
  ContentAST.Equation("\\nabla f", inline=True),
219
239
  ContentAST.Equation("\\alpha \\cdot \\nabla f", inline=True)
220
240
  ]
221
-
241
+
222
242
  solution_rows = []
223
243
  for i, result in enumerate(self.gradient_descent_results):
224
244
  step = result['step']
225
245
  row = {"n": str(step)}
226
-
246
+
227
247
  row["location"] = f"{format_vector(result['location'])}"
228
248
  row[solution_headers[2]] = f"{format_vector(result['gradient'])}"
229
249
  row[solution_headers[3]] = f"{format_vector(result['update'])}"
230
-
250
+
231
251
  solution_rows.append(row)
232
-
252
+
233
253
  # Create solution table (non-answer table, just display)
234
254
  solution_table = self.create_answer_table(
235
255
  headers=solution_headers,
236
256
  data_rows=solution_rows,
237
257
  answer_columns=[] # No answer columns since this is just for display
238
258
  )
239
-
259
+
240
260
  explanation.add_element(solution_table)
241
-
261
+
242
262
  # Step-by-step explanation
243
263
  for i, result in enumerate(self.gradient_descent_results):
244
264
  step = result['step']
245
-
265
+
246
266
  explanation.add_element(
247
267
  ContentAST.Paragraph(
248
268
  [
@@ -250,7 +270,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
250
270
  ]
251
271
  )
252
272
  )
253
-
273
+
254
274
  explanation.add_element(
255
275
  ContentAST.Paragraph(
256
276
  [
@@ -258,7 +278,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
258
278
  ]
259
279
  )
260
280
  )
261
-
281
+
262
282
  explanation.add_element(
263
283
  ContentAST.Paragraph(
264
284
  [
@@ -266,7 +286,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
266
286
  ]
267
287
  )
268
288
  )
269
-
289
+
270
290
  explanation.add_element(
271
291
  ContentAST.Paragraph(
272
292
  [
@@ -278,13 +298,13 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
278
298
  ]
279
299
  )
280
300
  )
281
-
301
+
282
302
  if step < len(self.gradient_descent_results):
283
303
  # Calculate next location for display
284
304
  current_loc = result['location']
285
305
  update = result['update']
286
306
  next_loc = [current_loc[j] - update[j] for j in range(len(current_loc))]
287
-
307
+
288
308
  explanation.add_element(
289
309
  ContentAST.Paragraph(
290
310
  [
@@ -292,7 +312,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
292
312
  ]
293
313
  )
294
314
  )
295
-
315
+
296
316
  function_values = [r['function_value'] for r in self.gradient_descent_results]
297
317
  explanation.add_element(
298
318
  ContentAST.Paragraph(
@@ -301,5 +321,10 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
301
321
  ]
302
322
  )
303
323
  )
304
-
324
+
325
+ return explanation, []
326
+
327
+ def get_explanation(self, **kwargs) -> ContentAST.Section:
328
+ """Build question explanation (backward compatible interface)."""
329
+ explanation, _ = self._get_explanation(**kwargs)
305
330
  return explanation
@@ -6,13 +6,16 @@ import math
6
6
  import numpy as np
7
7
  from typing import List, Tuple, Dict, Any
8
8
 
9
- from QuizGenerator.contentast import ContentAST
10
- from QuizGenerator.question import Question, Answer, QuestionRegistry
9
+ from QuizGenerator.contentast import ContentAST, AnswerTypes
10
+ from QuizGenerator.question import Question, QuestionRegistry
11
11
  from QuizGenerator.mixins import TableQuestionMixin, BodyTemplatesMixin
12
12
 
13
13
  log = logging.getLogger(__name__)
14
14
 
15
15
 
16
+ # Note: This file migrates to the _get_body()/_get_explanation() pattern
17
+
18
+
16
19
  class LossQuestion(Question, TableQuestionMixin, BodyTemplatesMixin, abc.ABC):
17
20
  """Base class for loss function calculation questions."""
18
21
 
@@ -70,14 +73,15 @@ class LossQuestion(Question, TableQuestionMixin, BodyTemplatesMixin, abc.ABC):
70
73
 
71
74
  # Individual loss answers
72
75
  for i in range(self.num_samples):
73
- self.answers[f"loss_{i}"] = Answer.float_value(f"loss_{i}", self.individual_losses[i])
76
+ self.answers[f"loss_{i}"] = AnswerTypes.Float(self.individual_losses[i], label=f"Sample {i + 1} loss")
74
77
 
75
78
  # Overall loss answer
76
- self.answers["overall_loss"] = Answer.float_value("overall_loss", self.overall_loss)
79
+ self.answers["overall_loss"] = AnswerTypes.Float(self.overall_loss, label="Overall loss")
77
80
 
78
- def get_body(self) -> ContentAST.Element:
79
- """Generate the question body with data table."""
81
+ def _get_body(self, **kwargs) -> Tuple[ContentAST.Element, List[ContentAST.Answer]]:
82
+ """Build question body and collect answers."""
80
83
  body = ContentAST.Section()
84
+ answers = []
81
85
 
82
86
  # Question description
83
87
  body.add_element(ContentAST.Paragraph([
@@ -85,15 +89,25 @@ class LossQuestion(Question, TableQuestionMixin, BodyTemplatesMixin, abc.ABC):
85
89
  f"and the overall {self._get_loss_function_short_name()}."
86
90
  ]))
87
91
 
88
- # Data table
92
+ # Data table (contains individual loss answers)
89
93
  body.add_element(self._create_data_table())
90
94
 
95
+ # Collect individual loss answers
96
+ for i in range(self.num_samples):
97
+ answers.append(self.answers[f"loss_{i}"])
98
+
91
99
  # Overall loss question
92
100
  body.add_element(ContentAST.Paragraph([
93
101
  f"Overall {self._get_loss_function_short_name()}: "
94
102
  ]))
95
- body.add_element(ContentAST.Answer(self.answers["overall_loss"]))
103
+ answers.append(self.answers["overall_loss"])
104
+ body.add_element(self.answers["overall_loss"])
105
+
106
+ return body, answers
96
107
 
108
+ def get_body(self, **kwargs) -> ContentAST.Element:
109
+ """Build question body (backward compatible interface)."""
110
+ body, _ = self._get_body(**kwargs)
97
111
  return body
98
112
 
99
113
  @abc.abstractmethod
@@ -101,8 +115,8 @@ class LossQuestion(Question, TableQuestionMixin, BodyTemplatesMixin, abc.ABC):
101
115
  """Create the data table with answer fields."""
102
116
  pass
103
117
 
104
- def get_explanation(self) -> ContentAST.Element:
105
- """Generate detailed explanation of the loss calculations."""
118
+ def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Element, List[ContentAST.Answer]]:
119
+ """Build question explanation."""
106
120
  explanation = ContentAST.Section()
107
121
 
108
122
  explanation.add_element(ContentAST.Paragraph([
@@ -121,6 +135,11 @@ class LossQuestion(Question, TableQuestionMixin, BodyTemplatesMixin, abc.ABC):
121
135
  # Overall loss calculation
122
136
  explanation.add_element(self._create_overall_loss_explanation())
123
137
 
138
+ return explanation, []
139
+
140
+ def get_explanation(self, **kwargs) -> ContentAST.Element:
141
+ """Build question explanation (backward compatible interface)."""
142
+ explanation, _ = self._get_explanation(**kwargs)
124
143
  return explanation
125
144
 
126
145
  @abc.abstractmethod
@@ -2,7 +2,7 @@
2
2
  from typing import List, Tuple, Callable, Union, Any
3
3
  import sympy as sp
4
4
 
5
- from QuizGenerator.misc import Answer
5
+ from QuizGenerator.contentast import ContentAST
6
6
 
7
7
  def generate_function(rng, num_variables: int, max_degree: int, use_quadratic: bool = True) -> tuple[Any, sp.Expr, sp.MutableDenseMatrix, sp.Equality]:
8
8
  """
@@ -61,7 +61,7 @@ def format_vector(vec: List[float]) -> str:
61
61
 
62
62
  vector_string = ', '.join(
63
63
  [
64
- sorted(Answer.accepted_strings(v), key=lambda s: len(s))[0]
64
+ sorted(ContentAST.Answer.accepted_strings(v), key=lambda s: len(s))[0]
65
65
  for v in vec
66
66
  ]
67
67
  )