QuizGenerator 0.6.3__py3-none-any.whl → 0.7.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 (30) hide show
  1. QuizGenerator/contentast.py +2191 -2193
  2. QuizGenerator/misc.py +1 -1
  3. QuizGenerator/mixins.py +64 -64
  4. QuizGenerator/premade_questions/basic.py +16 -16
  5. QuizGenerator/premade_questions/cst334/languages.py +26 -26
  6. QuizGenerator/premade_questions/cst334/math_questions.py +42 -42
  7. QuizGenerator/premade_questions/cst334/memory_questions.py +124 -124
  8. QuizGenerator/premade_questions/cst334/persistence_questions.py +48 -48
  9. QuizGenerator/premade_questions/cst334/process.py +38 -38
  10. QuizGenerator/premade_questions/cst463/gradient_descent/gradient_calculation.py +45 -45
  11. QuizGenerator/premade_questions/cst463/gradient_descent/gradient_descent_questions.py +34 -34
  12. QuizGenerator/premade_questions/cst463/gradient_descent/loss_calculations.py +53 -53
  13. QuizGenerator/premade_questions/cst463/gradient_descent/misc.py +2 -2
  14. QuizGenerator/premade_questions/cst463/math_and_data/matrix_questions.py +65 -65
  15. QuizGenerator/premade_questions/cst463/math_and_data/vector_questions.py +39 -39
  16. QuizGenerator/premade_questions/cst463/models/attention.py +36 -36
  17. QuizGenerator/premade_questions/cst463/models/cnns.py +26 -26
  18. QuizGenerator/premade_questions/cst463/models/rnns.py +36 -36
  19. QuizGenerator/premade_questions/cst463/models/text.py +32 -32
  20. QuizGenerator/premade_questions/cst463/models/weight_counting.py +15 -15
  21. QuizGenerator/premade_questions/cst463/neural-network-basics/neural_network_questions.py +124 -124
  22. QuizGenerator/premade_questions/cst463/tensorflow-intro/tensorflow_questions.py +161 -161
  23. QuizGenerator/question.py +41 -41
  24. QuizGenerator/quiz.py +7 -7
  25. QuizGenerator/typst_utils.py +2 -2
  26. {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/METADATA +1 -1
  27. {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/RECORD +30 -30
  28. {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/WHEEL +0 -0
  29. {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/entry_points.txt +0 -0
  30. {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -3,7 +3,7 @@ import abc
3
3
  import logging
4
4
 
5
5
  from QuizGenerator.question import Question, QuestionRegistry
6
- from QuizGenerator.contentast import ContentAST, AnswerTypes
6
+ import QuizGenerator.contentast as ca
7
7
  from QuizGenerator.mixins import MathOperationQuestion
8
8
 
9
9
  log = logging.getLogger(__name__)
@@ -13,15 +13,15 @@ class MatrixMathQuestion(MathOperationQuestion, Question):
13
13
  """
14
14
  Base class for matrix mathematics questions with multipart support.
15
15
 
16
- NOTE: This class demonstrates proper ContentAST usage patterns.
16
+ NOTE: This class demonstrates proper content AST usage patterns.
17
17
  When implementing similar question types (vectors, equations, etc.),
18
18
  follow these patterns for consistent formatting across output formats.
19
19
 
20
20
  Key patterns demonstrated:
21
- - ContentAST.Matrix for mathematical matrices
22
- - ContentAST.Equation.make_block_equation__multiline_equals for step-by-step solutions
23
- - ContentAST.OnlyHtml for Canvas-specific content
24
- - ContentAST.Answer.integer for numerical answers
21
+ - ca.Matrix for mathematical matrices
22
+ - ca.Equation.make_block_equation__multiline_equals for step-by-step solutions
23
+ - ca.OnlyHtml for Canvas-specific content
24
+ - ca.Answer.integer for numerical answers
25
25
  """
26
26
  def __init__(self, *args, **kwargs):
27
27
  kwargs["topic"] = kwargs.get("topic", Question.Topic.MATH)
@@ -32,7 +32,7 @@ class MatrixMathQuestion(MathOperationQuestion, Question):
32
32
  return [[self.rng.randint(min_val, max_val) for _ in range(cols)] for _ in range(rows)]
33
33
 
34
34
  def _matrix_to_table(self, matrix, prefix=""):
35
- """Convert a matrix to ContentAST table format."""
35
+ """Convert a matrix to content AST table format."""
36
36
  return [[f"{prefix}{matrix[i][j]}" for j in range(len(matrix[0]))] for i in range(len(matrix))]
37
37
 
38
38
  def _create_answer_table(self, rows, cols, answers_dict, answer_prefix="answer"):
@@ -51,7 +51,7 @@ class MatrixMathQuestion(MathOperationQuestion, Question):
51
51
  row.append(ans)
52
52
  answers.append(ans)
53
53
  table_data.append(row)
54
- return ContentAST.Table(data=table_data, padding=True), answers
54
+ return ca.Table(data=table_data, padding=True), answers
55
55
 
56
56
  # Implement MathOperationQuestion abstract methods
57
57
 
@@ -62,7 +62,7 @@ class MatrixMathQuestion(MathOperationQuestion, Question):
62
62
 
63
63
  def format_operand_latex(self, operand):
64
64
  """Format a matrix for LaTeX display."""
65
- return ContentAST.Matrix.to_latex(operand, "b")
65
+ return ca.Matrix.to_latex(operand, "b")
66
66
 
67
67
  def format_single_equation(self, operand_a, operand_b):
68
68
  """Format the equation for single questions."""
@@ -86,8 +86,8 @@ class MatrixMathQuestion(MathOperationQuestion, Question):
86
86
  cols_ans = self.answers["result_cols"]
87
87
  answers.extend([rows_ans, cols_ans])
88
88
  body.add_element(
89
- ContentAST.OnlyHtml([
90
- ContentAST.AnswerBlock([rows_ans, cols_ans])
89
+ ca.OnlyHtml([
90
+ ca.AnswerBlock([rows_ans, cols_ans])
91
91
  ])
92
92
  )
93
93
 
@@ -98,8 +98,8 @@ class MatrixMathQuestion(MathOperationQuestion, Question):
98
98
  table, table_answers = self._create_answer_table(rows, cols, self.answers)
99
99
  answers.extend(table_answers)
100
100
  body.add_element(
101
- ContentAST.OnlyHtml([
102
- ContentAST.Paragraph(["Result matrix:"]),
101
+ ca.OnlyHtml([
102
+ ca.Paragraph(["Result matrix:"]),
103
103
  table
104
104
  ])
105
105
  )
@@ -108,8 +108,8 @@ class MatrixMathQuestion(MathOperationQuestion, Question):
108
108
  table, table_answers = self._create_answer_table(self.max_dim, self.max_dim, self.answers)
109
109
  answers.extend(table_answers)
110
110
  body.add_element(
111
- ContentAST.OnlyHtml([
112
- ContentAST.Paragraph(["Result matrix (use '-' if cell doesn't exist):"]),
111
+ ca.OnlyHtml([
112
+ ca.Paragraph(["Result matrix (use '-' if cell doesn't exist):"]),
113
113
  table
114
114
  ])
115
115
  )
@@ -169,7 +169,7 @@ class MatrixAddition(MatrixMathQuestion):
169
169
  for i in range(rows):
170
170
  for j in range(cols):
171
171
  answer_key = f"answer_{i}_{j}"
172
- self.answers[answer_key] = AnswerTypes.Int(result[i][j])
172
+ self.answers[answer_key] = ca.AnswerTypes.Int(result[i][j])
173
173
  else:
174
174
  # For multipart questions, use subpart letter format
175
175
  letter = chr(ord('a') + subpart_index)
@@ -178,7 +178,7 @@ class MatrixAddition(MatrixMathQuestion):
178
178
  for i in range(rows):
179
179
  for j in range(cols):
180
180
  answer_key = f"subpart_{letter}_{i}_{j}"
181
- self.answers[answer_key] = AnswerTypes.Int(result[i][j])
181
+ self.answers[answer_key] = ca.AnswerTypes.Int(result[i][j])
182
182
 
183
183
  def refresh(self, *args, **kwargs):
184
184
  """Override refresh to set rows/cols for compatibility."""
@@ -190,11 +190,11 @@ class MatrixAddition(MatrixMathQuestion):
190
190
  self.matrix_b = self.operand_b
191
191
  # rows and cols should already be set by generate_operands
192
192
 
193
- def get_explanation(self, **kwargs) -> ContentAST.Section:
194
- explanation = ContentAST.Section()
193
+ def get_explanation(self, **kwargs) -> ca.Section:
194
+ explanation = ca.Section()
195
195
 
196
196
  explanation.add_element(
197
- ContentAST.Paragraph([
197
+ ca.Paragraph([
198
198
  "Matrix addition is performed element-wise. Each element in the result matrix "
199
199
  "is the sum of the corresponding elements in the input matrices."
200
200
  ])
@@ -202,7 +202,7 @@ class MatrixAddition(MatrixMathQuestion):
202
202
 
203
203
  if self.is_multipart():
204
204
  # Handle multipart explanations
205
- explanation.add_element(ContentAST.Paragraph(["Step-by-step calculation for each part:"]))
205
+ explanation.add_element(ca.Paragraph(["Step-by-step calculation for each part:"]))
206
206
  for i, data in enumerate(self.subquestion_data):
207
207
  letter = chr(ord('a') + i)
208
208
  matrix_a = data.get('matrix_a', data['operand_a'])
@@ -218,9 +218,9 @@ class MatrixAddition(MatrixMathQuestion):
218
218
  result_str = r" \\ ".join([" & ".join([str(result[row][col]) for col in range(cols)]) for row in range(rows)])
219
219
 
220
220
  # Add explanation for this subpart
221
- explanation.add_element(ContentAST.Paragraph([f"Part ({letter}):"]))
221
+ explanation.add_element(ca.Paragraph([f"Part ({letter}):"]))
222
222
  explanation.add_element(
223
- ContentAST.Equation.make_block_equation__multiline_equals(
223
+ ca.Equation.make_block_equation__multiline_equals(
224
224
  lhs="A + B",
225
225
  rhs=[
226
226
  f"\\begin{{bmatrix}} {matrix_a_str} \\end{{bmatrix}} + \\begin{{bmatrix}} {matrix_b_str} \\end{{bmatrix}}",
@@ -231,7 +231,7 @@ class MatrixAddition(MatrixMathQuestion):
231
231
  )
232
232
  else:
233
233
  # Single part explanation (original behavior)
234
- explanation.add_element(ContentAST.Paragraph(["Step-by-step calculation:"]))
234
+ explanation.add_element(ca.Paragraph(["Step-by-step calculation:"]))
235
235
 
236
236
  # Create properly formatted matrix strings
237
237
  matrix_a_str = r" \\ ".join([" & ".join([str(self.matrix_a[i][j]) for j in range(self.cols)]) for i in range(self.rows)])
@@ -240,7 +240,7 @@ class MatrixAddition(MatrixMathQuestion):
240
240
  result_str = r" \\ ".join([" & ".join([str(self.result[i][j]) for j in range(self.cols)]) for i in range(self.rows)])
241
241
 
242
242
  explanation.add_element(
243
- ContentAST.Equation.make_block_equation__multiline_equals(
243
+ ca.Equation.make_block_equation__multiline_equals(
244
244
  lhs="A + B",
245
245
  rhs=[
246
246
  f"\\begin{{bmatrix}} {matrix_a_str} \\end{{bmatrix}} + \\begin{{bmatrix}} {matrix_b_str} \\end{{bmatrix}}",
@@ -299,7 +299,7 @@ class MatrixScalarMultiplication(MatrixMathQuestion):
299
299
  for i in range(rows):
300
300
  for j in range(cols):
301
301
  answer_key = f"answer_{i}_{j}"
302
- self.answers[answer_key] = AnswerTypes.Int(result[i][j])
302
+ self.answers[answer_key] = ca.AnswerTypes.Int(result[i][j])
303
303
  else:
304
304
  # For multipart questions, use subpart letter format
305
305
  letter = chr(ord('a') + subpart_index)
@@ -308,7 +308,7 @@ class MatrixScalarMultiplication(MatrixMathQuestion):
308
308
  for i in range(rows):
309
309
  for j in range(cols):
310
310
  answer_key = f"subpart_{letter}_{i}_{j}"
311
- self.answers[answer_key] = AnswerTypes.Int(result[i][j])
311
+ self.answers[answer_key] = ca.AnswerTypes.Int(result[i][j])
312
312
 
313
313
  def refresh(self, *args, **kwargs):
314
314
  """Override refresh to handle different scalars per subpart."""
@@ -355,7 +355,7 @@ class MatrixScalarMultiplication(MatrixMathQuestion):
355
355
  """Override to handle scalar multiplication format."""
356
356
  subparts = []
357
357
  for data in self.subquestion_data:
358
- matrix_latex = ContentAST.Matrix.to_latex(data['matrix'], "b")
358
+ matrix_latex = ca.Matrix.to_latex(data['matrix'], "b")
359
359
  scalar = data['scalar']
360
360
  # Return scalar * matrix as a single string
361
361
  subparts.append(f"{scalar} \\cdot {matrix_latex}")
@@ -363,21 +363,21 @@ class MatrixScalarMultiplication(MatrixMathQuestion):
363
363
 
364
364
  def format_single_equation(self, operand_a, operand_b):
365
365
  """Format the equation for single questions."""
366
- matrix_latex = ContentAST.Matrix.to_latex(operand_a, "b")
366
+ matrix_latex = ca.Matrix.to_latex(operand_a, "b")
367
367
  return f"{self.scalar} \\cdot {matrix_latex}"
368
368
 
369
- def get_explanation(self, **kwargs) -> ContentAST.Section:
370
- explanation = ContentAST.Section()
369
+ def get_explanation(self, **kwargs) -> ca.Section:
370
+ explanation = ca.Section()
371
371
 
372
372
  explanation.add_element(
373
- ContentAST.Paragraph([
373
+ ca.Paragraph([
374
374
  "Scalar multiplication involves multiplying every element in the matrix by the scalar value."
375
375
  ])
376
376
  )
377
377
 
378
378
  if self.is_multipart():
379
379
  # Handle multipart explanations
380
- explanation.add_element(ContentAST.Paragraph(["Step-by-step calculation for each part:"]))
380
+ explanation.add_element(ca.Paragraph(["Step-by-step calculation for each part:"]))
381
381
  for i, data in enumerate(self.subquestion_data):
382
382
  letter = chr(ord('a') + i)
383
383
  matrix = data.get('matrix', data['operand_a'])
@@ -392,9 +392,9 @@ class MatrixScalarMultiplication(MatrixMathQuestion):
392
392
  result_str = r" \\ ".join([" & ".join([str(result[row][col]) for col in range(cols)]) for row in range(rows)])
393
393
 
394
394
  # Add explanation for this subpart
395
- explanation.add_element(ContentAST.Paragraph([f"Part ({letter}):"]))
395
+ explanation.add_element(ca.Paragraph([f"Part ({letter}):"]))
396
396
  explanation.add_element(
397
- ContentAST.Equation.make_block_equation__multiline_equals(
397
+ ca.Equation.make_block_equation__multiline_equals(
398
398
  lhs=f"{scalar} \\cdot A",
399
399
  rhs=[
400
400
  f"{scalar} \\cdot \\begin{{bmatrix}} {matrix_str} \\end{{bmatrix}}",
@@ -405,7 +405,7 @@ class MatrixScalarMultiplication(MatrixMathQuestion):
405
405
  )
406
406
  else:
407
407
  # Single part explanation
408
- explanation.add_element(ContentAST.Paragraph(["Step-by-step calculation:"]))
408
+ explanation.add_element(ca.Paragraph(["Step-by-step calculation:"]))
409
409
 
410
410
  # Create properly formatted matrix strings
411
411
  matrix_str = r" \\ ".join([" & ".join([str(self.matrix[i][j]) for j in range(self.cols)]) for i in range(self.rows)])
@@ -413,7 +413,7 @@ class MatrixScalarMultiplication(MatrixMathQuestion):
413
413
  result_str = r" \\ ".join([" & ".join([str(self.result[i][j]) for j in range(self.cols)]) for i in range(self.rows)])
414
414
 
415
415
  explanation.add_element(
416
- ContentAST.Equation.make_block_equation__multiline_equals(
416
+ ca.Equation.make_block_equation__multiline_equals(
417
417
  lhs=f"{self.scalar} \\cdot A",
418
418
  rhs=[
419
419
  f"{self.scalar} \\cdot \\begin{{bmatrix}} {matrix_str} \\end{{bmatrix}}",
@@ -501,27 +501,27 @@ class MatrixMultiplication(MatrixMathQuestion):
501
501
  # For single questions, use the old answer format
502
502
  # Dimension answers
503
503
  if result is not None:
504
- self.answers["result_rows"] = AnswerTypes.Int(self.result_rows, label="Number of rows in result")
505
- self.answers["result_cols"] = AnswerTypes.Int(self.result_cols, label="Number of columns in result")
504
+ self.answers["result_rows"] = ca.AnswerTypes.Int(self.result_rows, label="Number of rows in result")
505
+ self.answers["result_cols"] = ca.AnswerTypes.Int(self.result_cols, label="Number of columns in result")
506
506
 
507
507
  # Matrix element answers
508
508
  for i in range(self.max_dim):
509
509
  for j in range(self.max_dim):
510
510
  answer_key = f"answer_{i}_{j}"
511
511
  if i < self.result_rows and j < self.result_cols:
512
- self.answers[answer_key] = AnswerTypes.Int(result[i][j])
512
+ self.answers[answer_key] = ca.AnswerTypes.Int(result[i][j])
513
513
  else:
514
- self.answers[answer_key] = AnswerTypes.String("-")
514
+ self.answers[answer_key] = ca.AnswerTypes.String("-")
515
515
  else:
516
516
  # Multiplication not possible
517
- self.answers["result_rows"] = AnswerTypes.String("-", label="Number of rows in result")
518
- self.answers["result_cols"] = AnswerTypes.String("-", label="Number of columns in result")
517
+ self.answers["result_rows"] = ca.AnswerTypes.String("-", label="Number of rows in result")
518
+ self.answers["result_cols"] = ca.AnswerTypes.String("-", label="Number of columns in result")
519
519
 
520
520
  # All matrix elements are "-"
521
521
  for i in range(self.max_dim):
522
522
  for j in range(self.max_dim):
523
523
  answer_key = f"answer_{i}_{j}"
524
- self.answers[answer_key] = AnswerTypes.String("-")
524
+ self.answers[answer_key] = ca.AnswerTypes.String("-")
525
525
  else:
526
526
  # For multipart questions, use subpart letter format
527
527
  letter = chr(ord('a') + subpart_index)
@@ -533,7 +533,7 @@ class MatrixMultiplication(MatrixMathQuestion):
533
533
  for i in range(rows):
534
534
  for j in range(cols):
535
535
  answer_key = f"subpart_{letter}_{i}_{j}"
536
- self.answers[answer_key] = AnswerTypes.Int(result[i][j])
536
+ self.answers[answer_key] = ca.AnswerTypes.Int(result[i][j])
537
537
 
538
538
  def _add_single_question_answers(self, body):
539
539
  """Add Canvas-only answer fields for MatrixMultiplication with dash instruction.
@@ -549,8 +549,8 @@ class MatrixMultiplication(MatrixMathQuestion):
549
549
  cols_ans = self.answers["result_cols"]
550
550
  answers.extend([rows_ans, cols_ans])
551
551
  body.add_element(
552
- ContentAST.OnlyHtml([
553
- ContentAST.AnswerBlock([rows_ans, cols_ans])
552
+ ca.OnlyHtml([
553
+ ca.AnswerBlock([rows_ans, cols_ans])
554
554
  ])
555
555
  )
556
556
 
@@ -558,8 +558,8 @@ class MatrixMultiplication(MatrixMathQuestion):
558
558
  table, table_answers = self._create_answer_table(self.max_dim, self.max_dim, self.answers)
559
559
  answers.extend(table_answers)
560
560
  body.add_element(
561
- ContentAST.OnlyHtml([
562
- ContentAST.Paragraph(["Result matrix (use '-' if cell doesn't exist):"]),
561
+ ca.OnlyHtml([
562
+ ca.Paragraph(["Result matrix (use '-' if cell doesn't exist):"]),
563
563
  table
564
564
  ])
565
565
  )
@@ -575,13 +575,13 @@ class MatrixMultiplication(MatrixMathQuestion):
575
575
  self.matrix_a = self.operand_a
576
576
  self.matrix_b = self.operand_b
577
577
 
578
- def get_explanation(self, **kwargs) -> ContentAST.Section:
579
- explanation = ContentAST.Section()
578
+ def get_explanation(self, **kwargs) -> ca.Section:
579
+ explanation = ca.Section()
580
580
 
581
581
  if self.is_multipart():
582
582
  # For multipart questions, provide simpler explanations
583
583
  explanation.add_element(
584
- ContentAST.Paragraph([
584
+ ca.Paragraph([
585
585
  "Matrix multiplication: Each element in the result is the dot product of "
586
586
  "the corresponding row from the first matrix and column from the second matrix."
587
587
  ])
@@ -593,17 +593,17 @@ class MatrixMultiplication(MatrixMathQuestion):
593
593
  matrix_b = data.get('matrix_b', data['operand_b'])
594
594
  result = data['result']
595
595
 
596
- explanation.add_element(ContentAST.Paragraph([f"Part ({letter}): Matrices multiplied successfully."]))
596
+ explanation.add_element(ca.Paragraph([f"Part ({letter}): Matrices multiplied successfully."]))
597
597
 
598
598
  elif hasattr(self, 'multiplication_possible') and self.multiplication_possible:
599
599
  # Single question with successful multiplication
600
- explanation.add_element(ContentAST.Paragraph(["Given matrices:"]))
601
- matrix_a_latex = ContentAST.Matrix.to_latex(self.matrix_a, "b")
602
- matrix_b_latex = ContentAST.Matrix.to_latex(self.matrix_b, "b")
603
- explanation.add_element(ContentAST.Equation(f"A = {matrix_a_latex}, \\quad B = {matrix_b_latex}"))
600
+ explanation.add_element(ca.Paragraph(["Given matrices:"]))
601
+ matrix_a_latex = ca.Matrix.to_latex(self.matrix_a, "b")
602
+ matrix_b_latex = ca.Matrix.to_latex(self.matrix_b, "b")
603
+ explanation.add_element(ca.Equation(f"A = {matrix_a_latex}, \\quad B = {matrix_b_latex}"))
604
604
 
605
605
  explanation.add_element(
606
- ContentAST.Paragraph([
606
+ ca.Paragraph([
607
607
  f"Matrix multiplication is possible because the number of columns in Matrix A ({self.cols_a}) "
608
608
  f"equals the number of rows in Matrix B ({self.rows_b}). "
609
609
  f"The result is a {self.result_rows}×{self.result_cols} matrix."
@@ -611,10 +611,10 @@ class MatrixMultiplication(MatrixMathQuestion):
611
611
  )
612
612
 
613
613
  # Comprehensive matrix multiplication walkthrough
614
- explanation.add_element(ContentAST.Paragraph(["Step-by-step calculation:"]))
614
+ explanation.add_element(ca.Paragraph(["Step-by-step calculation:"]))
615
615
 
616
616
  # Show detailed multiplication process using row×column visualization
617
- explanation.add_element(ContentAST.Paragraph(["Each element is calculated as the dot product of a row from Matrix A and a column from Matrix B:"]))
617
+ explanation.add_element(ca.Paragraph(["Each element is calculated as the dot product of a row from Matrix A and a column from Matrix B:"]))
618
618
 
619
619
  # Show calculation for first few elements with row×column visualization
620
620
  for i in range(min(2, self.result_rows)):
@@ -631,18 +631,18 @@ class MatrixMultiplication(MatrixMathQuestion):
631
631
  element_calc = " + ".join([f"{self.matrix_a[i][k]} \\cdot {self.matrix_b[k][j]}" for k in range(self.cols_a)])
632
632
 
633
633
  explanation.add_element(
634
- ContentAST.Equation(f"({i+1},{j+1}): {row_latex} \\cdot {col_latex} = {element_calc} = {self.result[i][j]}")
634
+ ca.Equation(f"({i+1},{j+1}): {row_latex} \\cdot {col_latex} = {element_calc} = {self.result[i][j]}")
635
635
  )
636
636
 
637
- explanation.add_element(ContentAST.Paragraph(["Final result:"]))
638
- explanation.add_element(ContentAST.Matrix(data=self.result, bracket_type="b"))
637
+ explanation.add_element(ca.Paragraph(["Final result:"]))
638
+ explanation.add_element(ca.Matrix(data=self.result, bracket_type="b"))
639
639
  else:
640
640
  # Single question with failed multiplication
641
641
  explanation.add_element(
642
- ContentAST.Paragraph([
642
+ ca.Paragraph([
643
643
  f"Matrix multiplication is not possible because the number of columns in Matrix A ({getattr(self, 'cols_a', 'unknown')}) "
644
644
  f"does not equal the number of rows in Matrix B ({getattr(self, 'rows_b', 'unknown')})."
645
645
  ])
646
646
  )
647
647
 
648
- return explanation
648
+ return explanation
@@ -5,7 +5,7 @@ import math
5
5
  from typing import List
6
6
 
7
7
  from QuizGenerator.question import Question, QuestionRegistry
8
- from QuizGenerator.contentast import ContentAST, AnswerTypes
8
+ import QuizGenerator.contentast as ca
9
9
  from QuizGenerator.mixins import MathOperationQuestion
10
10
 
11
11
  log = logging.getLogger(__name__)
@@ -22,7 +22,7 @@ class VectorMathQuestion(MathOperationQuestion, Question):
22
22
  return [self.rng.randint(min_val, max_val) for _ in range(dimension)]
23
23
 
24
24
  def _format_vector(self, vector):
25
- """Return a ContentAST.Matrix element for the vector (format-independent).
25
+ """Return a ca.Matrix element for the vector (format-independent).
26
26
 
27
27
  The Matrix element will render appropriately for each output format:
28
28
  - HTML: LaTeX bmatrix (for MathJax)
@@ -31,7 +31,7 @@ class VectorMathQuestion(MathOperationQuestion, Question):
31
31
  """
32
32
  # Convert to column matrix format: [[v1], [v2], [v3]]
33
33
  matrix_data = [[v] for v in vector]
34
- return ContentAST.Matrix(data=matrix_data, bracket_type="b")
34
+ return ca.Matrix(data=matrix_data, bracket_type="b")
35
35
 
36
36
  def _format_vector_inline(self, vector):
37
37
  """Format vector for inline display."""
@@ -118,18 +118,18 @@ class VectorAddition(VectorMathQuestion):
118
118
  raise NotImplementedError("Multipart not supported")
119
119
 
120
120
  def create_single_answers(self, result):
121
- self.answers["result"] = AnswerTypes.Vector(result)
121
+ self.answers["result"] = ca.AnswerTypes.Vector(result)
122
122
 
123
123
  def _get_body(self):
124
124
  """Build question body and collect answers."""
125
- body = ContentAST.Section()
125
+ body = ca.Section()
126
126
 
127
- body.add_element(ContentAST.Paragraph([self.get_intro_text()]))
127
+ body.add_element(ca.Paragraph([self.get_intro_text()]))
128
128
 
129
129
  # Equation display using MathExpression for format-independent rendering
130
130
  vector_a_elem = self._format_vector(self.vector_a)
131
131
  vector_b_elem = self._format_vector(self.vector_b)
132
- body.add_element(ContentAST.MathExpression([
132
+ body.add_element(ca.MathExpression([
133
133
  vector_a_elem,
134
134
  " + ",
135
135
  vector_b_elem,
@@ -138,16 +138,16 @@ class VectorAddition(VectorMathQuestion):
138
138
 
139
139
  # Canvas-only answer field - use stored answer for consistent UUID
140
140
  answer = self.answers["result"]
141
- body.add_element(ContentAST.OnlyHtml([ContentAST.Paragraph(["Enter your answer as a column vector:"])]))
142
- body.add_element(ContentAST.OnlyHtml([answer]))
141
+ body.add_element(ca.OnlyHtml([ca.Paragraph(["Enter your answer as a column vector:"])]))
142
+ body.add_element(ca.OnlyHtml([answer]))
143
143
 
144
144
  return body, list(self.answers.values())
145
145
 
146
146
  def _get_explanation(self):
147
147
  """Build question explanation."""
148
- explanation = ContentAST.Section()
148
+ explanation = ca.Section()
149
149
 
150
- explanation.add_element(ContentAST.Paragraph(["To add vectors, we add corresponding components:"]))
150
+ explanation.add_element(ca.Paragraph(["To add vectors, we add corresponding components:"]))
151
151
 
152
152
  # Use LaTeX syntax for make_block_equation__multiline_equals
153
153
  vector_a_str = r" \\ ".join([str(v) for v in self.vector_a])
@@ -156,7 +156,7 @@ class VectorAddition(VectorMathQuestion):
156
156
  addition_str = r" \\ ".join([f"{self.vector_a[i]}+{self.vector_b[i]}" for i in range(self.dimension)])
157
157
 
158
158
  explanation.add_element(
159
- ContentAST.Equation.make_block_equation__multiline_equals(
159
+ ca.Equation.make_block_equation__multiline_equals(
160
160
  lhs=r"\vec{a} + \vec{b}",
161
161
  rhs=[
162
162
  f"\\begin{{bmatrix}} {vector_a_str} \\end{{bmatrix}} + \\begin{{bmatrix}} {vector_b_str} \\end{{bmatrix}}",
@@ -197,17 +197,17 @@ class VectorScalarMultiplication(VectorMathQuestion):
197
197
  raise NotImplementedError("Multipart not supported")
198
198
 
199
199
  def create_single_answers(self, result):
200
- self.answers["result"] = AnswerTypes.Vector(result)
200
+ self.answers["result"] = ca.AnswerTypes.Vector(result)
201
201
 
202
202
  def _get_body(self):
203
203
  """Build question body and collect answers."""
204
- body = ContentAST.Section()
204
+ body = ca.Section()
205
205
 
206
- body.add_element(ContentAST.Paragraph([self.get_intro_text()]))
206
+ body.add_element(ca.Paragraph([self.get_intro_text()]))
207
207
 
208
208
  # Equation display using MathExpression
209
209
  vector_elem = self._format_vector(self.vector_a)
210
- body.add_element(ContentAST.MathExpression([
210
+ body.add_element(ca.MathExpression([
211
211
  f"{self.scalar} \\cdot ",
212
212
  vector_elem,
213
213
  " = "
@@ -215,23 +215,23 @@ class VectorScalarMultiplication(VectorMathQuestion):
215
215
 
216
216
  # Canvas-only answer field - use stored answer
217
217
  answer = self.answers["result"]
218
- body.add_element(ContentAST.OnlyHtml([ContentAST.Paragraph(["Enter your answer as a column vector:"])]))
219
- body.add_element(ContentAST.OnlyHtml([answer]))
218
+ body.add_element(ca.OnlyHtml([ca.Paragraph(["Enter your answer as a column vector:"])]))
219
+ body.add_element(ca.OnlyHtml([answer]))
220
220
 
221
221
  return body, list(self.answers.values())
222
222
 
223
223
  def _get_explanation(self):
224
224
  """Build question explanation."""
225
- explanation = ContentAST.Section()
225
+ explanation = ca.Section()
226
226
 
227
- explanation.add_element(ContentAST.Paragraph(["To multiply a vector by a scalar, we multiply each component by the scalar:"]))
227
+ explanation.add_element(ca.Paragraph(["To multiply a vector by a scalar, we multiply each component by the scalar:"]))
228
228
 
229
229
  vector_str = r" \\ ".join([str(v) for v in self.vector_a])
230
230
  multiplication_str = r" \\ ".join([f"{self.scalar} \\cdot {v}" for v in self.vector_a])
231
231
  result_str = r" \\ ".join([str(v) for v in self.result])
232
232
 
233
233
  explanation.add_element(
234
- ContentAST.Equation.make_block_equation__multiline_equals(
234
+ ca.Equation.make_block_equation__multiline_equals(
235
235
  lhs=f"{self.scalar} \\cdot \\vec{{v}}",
236
236
  rhs=[
237
237
  f"{self.scalar} \\cdot \\begin{{bmatrix}} {vector_str} \\end{{bmatrix}}",
@@ -260,18 +260,18 @@ class VectorDotProduct(VectorMathQuestion):
260
260
  raise NotImplementedError("Multipart not supported")
261
261
 
262
262
  def create_single_answers(self, result):
263
- self.answers["dot_product"] = AnswerTypes.Int(result)
263
+ self.answers["dot_product"] = ca.AnswerTypes.Int(result)
264
264
 
265
265
  def _get_body(self):
266
266
  """Build question body and collect answers."""
267
- body = ContentAST.Section()
267
+ body = ca.Section()
268
268
 
269
- body.add_element(ContentAST.Paragraph([self.get_intro_text()]))
269
+ body.add_element(ca.Paragraph([self.get_intro_text()]))
270
270
 
271
271
  # Equation display using MathExpression
272
272
  vector_a_elem = self._format_vector(self.vector_a)
273
273
  vector_b_elem = self._format_vector(self.vector_b)
274
- body.add_element(ContentAST.MathExpression([
274
+ body.add_element(ca.MathExpression([
275
275
  vector_a_elem,
276
276
  " \\cdot ",
277
277
  vector_b_elem,
@@ -280,15 +280,15 @@ class VectorDotProduct(VectorMathQuestion):
280
280
 
281
281
  # Canvas-only answer field - use stored answer
282
282
  answer = self.answers["dot_product"]
283
- body.add_element(ContentAST.OnlyHtml([answer]))
283
+ body.add_element(ca.OnlyHtml([answer]))
284
284
 
285
285
  return body, list(self.answers.values())
286
286
 
287
287
  def _get_explanation(self):
288
288
  """Build question explanation."""
289
- explanation = ContentAST.Section()
289
+ explanation = ca.Section()
290
290
 
291
- explanation.add_element(ContentAST.Paragraph(["The dot product is calculated by multiplying corresponding components and summing the results:"]))
291
+ explanation.add_element(ca.Paragraph(["The dot product is calculated by multiplying corresponding components and summing the results:"]))
292
292
 
293
293
  vector_a_str = r" \\ ".join([str(v) for v in self.vector_a])
294
294
  vector_b_str = r" \\ ".join([str(v) for v in self.vector_b])
@@ -296,7 +296,7 @@ class VectorDotProduct(VectorMathQuestion):
296
296
  calculation_str = " + ".join([str(self.vector_a[i] * self.vector_b[i]) for i in range(self.dimension)])
297
297
 
298
298
  explanation.add_element(
299
- ContentAST.Equation.make_block_equation__multiline_equals(
299
+ ca.Equation.make_block_equation__multiline_equals(
300
300
  lhs="\\vec{a} \\cdot \\vec{b}",
301
301
  rhs=[
302
302
  f"\\begin{{bmatrix}} {vector_a_str} \\end{{bmatrix}} \\cdot \\begin{{bmatrix}} {vector_b_str} \\end{{bmatrix}}",
@@ -327,17 +327,17 @@ class VectorMagnitude(VectorMathQuestion):
327
327
  raise NotImplementedError("Multipart not supported")
328
328
 
329
329
  def create_single_answers(self, result):
330
- self.answers["magnitude"] = AnswerTypes.Float(result)
330
+ self.answers["magnitude"] = ca.AnswerTypes.Float(result)
331
331
 
332
332
  def _get_body(self):
333
333
  """Build question body and collect answers."""
334
- body = ContentAST.Section()
334
+ body = ca.Section()
335
335
 
336
- body.add_element(ContentAST.Paragraph([self.get_intro_text()]))
336
+ body.add_element(ca.Paragraph([self.get_intro_text()]))
337
337
 
338
338
  # Equation display using MathExpression
339
339
  vector_elem = self._format_vector(self.vector_a)
340
- body.add_element(ContentAST.MathExpression([
340
+ body.add_element(ca.MathExpression([
341
341
  "||",
342
342
  vector_elem,
343
343
  "|| = "
@@ -345,16 +345,16 @@ class VectorMagnitude(VectorMathQuestion):
345
345
 
346
346
  # Canvas-only answer field - use stored answer
347
347
  answer = self.answers["magnitude"]
348
- body.add_element(ContentAST.OnlyHtml([answer]))
348
+ body.add_element(ca.OnlyHtml([answer]))
349
349
 
350
350
  return body, list(self.answers.values())
351
351
 
352
352
  def _get_explanation(self):
353
353
  """Build question explanation."""
354
- explanation = ContentAST.Section()
354
+ explanation = ca.Section()
355
355
 
356
- explanation.add_element(ContentAST.Paragraph(["The magnitude of a vector is calculated using the formula:"]))
357
- explanation.add_element(ContentAST.Equation(
356
+ explanation.add_element(ca.Paragraph(["The magnitude of a vector is calculated using the formula:"]))
357
+ explanation.add_element(ca.Equation(
358
358
  r"||\vec{v}|| = \sqrt{v_1^2 + v_2^2 + \cdots + v_n^2}", inline=False
359
359
  ))
360
360
 
@@ -363,10 +363,10 @@ class VectorMagnitude(VectorMathQuestion):
363
363
  squares_str = " + ".join([f"{v}^2" for v in self.vector_a])
364
364
  calculation_str = " + ".join([str(v**2) for v in self.vector_a])
365
365
  sum_of_squares = sum(component ** 2 for component in self.vector_a)
366
- result_formatted = sorted(ContentAST.Answer.accepted_strings(self.result), key=lambda s: len(s))[0]
366
+ result_formatted = sorted(ca.Answer.accepted_strings(self.result), key=lambda s: len(s))[0]
367
367
 
368
368
  explanation.add_element(
369
- ContentAST.Equation.make_block_equation__multiline_equals(
369
+ ca.Equation.make_block_equation__multiline_equals(
370
370
  lhs=r"||\vec{v}||",
371
371
  rhs=[
372
372
  f"\\left|\\left| \\begin{{bmatrix}} {vector_str} \\end{{bmatrix}} \\right|\\right|",