QuizGenerator 0.6.3__py3-none-any.whl → 0.7.1__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.
- QuizGenerator/contentast.py +2191 -2193
- QuizGenerator/misc.py +1 -1
- QuizGenerator/mixins.py +64 -64
- QuizGenerator/premade_questions/basic.py +16 -16
- QuizGenerator/premade_questions/cst334/languages.py +26 -26
- QuizGenerator/premade_questions/cst334/math_questions.py +42 -42
- QuizGenerator/premade_questions/cst334/memory_questions.py +124 -124
- QuizGenerator/premade_questions/cst334/persistence_questions.py +48 -48
- QuizGenerator/premade_questions/cst334/process.py +38 -38
- QuizGenerator/premade_questions/cst463/gradient_descent/gradient_calculation.py +45 -45
- QuizGenerator/premade_questions/cst463/gradient_descent/gradient_descent_questions.py +34 -34
- QuizGenerator/premade_questions/cst463/gradient_descent/loss_calculations.py +53 -53
- QuizGenerator/premade_questions/cst463/gradient_descent/misc.py +2 -2
- QuizGenerator/premade_questions/cst463/math_and_data/matrix_questions.py +65 -65
- QuizGenerator/premade_questions/cst463/math_and_data/vector_questions.py +39 -39
- QuizGenerator/premade_questions/cst463/models/attention.py +36 -36
- QuizGenerator/premade_questions/cst463/models/cnns.py +26 -26
- QuizGenerator/premade_questions/cst463/models/rnns.py +36 -36
- QuizGenerator/premade_questions/cst463/models/text.py +32 -32
- QuizGenerator/premade_questions/cst463/models/weight_counting.py +15 -15
- QuizGenerator/premade_questions/cst463/neural-network-basics/neural_network_questions.py +124 -124
- QuizGenerator/premade_questions/cst463/tensorflow-intro/tensorflow_questions.py +161 -161
- QuizGenerator/question.py +41 -41
- QuizGenerator/quiz.py +7 -7
- QuizGenerator/regenerate.py +114 -13
- QuizGenerator/typst_utils.py +2 -2
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.1.dist-info}/METADATA +1 -1
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.1.dist-info}/RECORD +31 -31
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.1.dist-info}/WHEEL +0 -0
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.1.dist-info}/entry_points.txt +0 -0
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,7 +5,7 @@ import logging
|
|
|
5
5
|
from typing import List, Tuple
|
|
6
6
|
import sympy as sp
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
import QuizGenerator.contentast as ca
|
|
9
9
|
from QuizGenerator.question import Question, QuestionRegistry
|
|
10
10
|
from .misc import generate_function, format_vector
|
|
11
11
|
|
|
@@ -57,7 +57,7 @@ class DerivativeQuestion(Question, abc.ABC):
|
|
|
57
57
|
# Use auto_float for Canvas compatibility with integers and decimals
|
|
58
58
|
# Label includes the partial derivative notation
|
|
59
59
|
label = f"∂f/∂x_{i} at ({eval_point_str})"
|
|
60
|
-
self.answers[answer_key] = AnswerTypes.Float(gradient_value, label=label)
|
|
60
|
+
self.answers[answer_key] = ca.AnswerTypes.Float(gradient_value, label=label)
|
|
61
61
|
|
|
62
62
|
def _create_gradient_vector_answer(self) -> None:
|
|
63
63
|
"""Create a single gradient vector answer for PDF format."""
|
|
@@ -75,20 +75,20 @@ class DerivativeQuestion(Question, abc.ABC):
|
|
|
75
75
|
|
|
76
76
|
# Format as vector for display using consistent formatting
|
|
77
77
|
vector_str = format_vector(gradient_values)
|
|
78
|
-
self.answers["gradient_vector"] = AnswerTypes.String(vector_str, pdf_only=True)
|
|
78
|
+
self.answers["gradient_vector"] = ca.AnswerTypes.String(vector_str, pdf_only=True)
|
|
79
79
|
|
|
80
|
-
def _get_body(self, **kwargs) -> Tuple[
|
|
80
|
+
def _get_body(self, **kwargs) -> Tuple[ca.Section, List[ca.Answer]]:
|
|
81
81
|
"""Build question body and collect answers."""
|
|
82
|
-
body =
|
|
82
|
+
body = ca.Section()
|
|
83
83
|
answers = []
|
|
84
84
|
|
|
85
85
|
# Display the function
|
|
86
86
|
body.add_element(
|
|
87
|
-
|
|
87
|
+
ca.Paragraph([
|
|
88
88
|
"Given the function ",
|
|
89
|
-
|
|
89
|
+
ca.Equation(sp.latex(self.equation), inline=True),
|
|
90
90
|
", calculate the gradient at the point ",
|
|
91
|
-
|
|
91
|
+
ca.Equation(format_vector(self.evaluation_point), inline=True),
|
|
92
92
|
"."
|
|
93
93
|
])
|
|
94
94
|
)
|
|
@@ -98,9 +98,9 @@ class DerivativeQuestion(Question, abc.ABC):
|
|
|
98
98
|
|
|
99
99
|
# For PDF: Use OnlyLatex to show gradient vector format (no answer blank)
|
|
100
100
|
body.add_element(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
ca.OnlyLatex([
|
|
102
|
+
ca.Paragraph([
|
|
103
|
+
ca.Equation(
|
|
104
104
|
f"\\left. \\nabla f \\right|_{{{eval_point_str}}} = ",
|
|
105
105
|
inline=True
|
|
106
106
|
)
|
|
@@ -113,9 +113,9 @@ class DerivativeQuestion(Question, abc.ABC):
|
|
|
113
113
|
answer = self.answers[f"partial_derivative_{i}"]
|
|
114
114
|
answers.append(answer)
|
|
115
115
|
body.add_element(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
ca.OnlyHtml([
|
|
117
|
+
ca.Paragraph([
|
|
118
|
+
ca.Equation(
|
|
119
119
|
f"\\left. {self._format_partial_derivative(i)} \\right|_{{{eval_point_str}}} = ",
|
|
120
120
|
inline=True
|
|
121
121
|
),
|
|
@@ -126,32 +126,32 @@ class DerivativeQuestion(Question, abc.ABC):
|
|
|
126
126
|
|
|
127
127
|
return body, answers
|
|
128
128
|
|
|
129
|
-
def get_body(self, **kwargs) ->
|
|
129
|
+
def get_body(self, **kwargs) -> ca.Section:
|
|
130
130
|
"""Build question body (backward compatible interface)."""
|
|
131
131
|
body, _ = self._get_body(**kwargs)
|
|
132
132
|
return body
|
|
133
133
|
|
|
134
|
-
def _get_explanation(self, **kwargs) -> Tuple[
|
|
134
|
+
def _get_explanation(self, **kwargs) -> Tuple[ca.Section, List[ca.Answer]]:
|
|
135
135
|
"""Build question explanation."""
|
|
136
|
-
explanation =
|
|
136
|
+
explanation = ca.Section()
|
|
137
137
|
|
|
138
138
|
# Show the function and its gradient
|
|
139
139
|
explanation.add_element(
|
|
140
|
-
|
|
140
|
+
ca.Paragraph([
|
|
141
141
|
"To find the gradient, we calculate the partial derivatives of ",
|
|
142
|
-
|
|
142
|
+
ca.Equation(sp.latex(self.equation), inline=True),
|
|
143
143
|
":"
|
|
144
144
|
])
|
|
145
145
|
)
|
|
146
146
|
|
|
147
147
|
# Show analytical gradient
|
|
148
148
|
explanation.add_element(
|
|
149
|
-
|
|
149
|
+
ca.Equation(f"\\nabla f = {sp.latex(self.gradient_function)}", inline=False)
|
|
150
150
|
)
|
|
151
151
|
|
|
152
152
|
# Show evaluation at the specific point
|
|
153
153
|
explanation.add_element(
|
|
154
|
-
|
|
154
|
+
ca.Paragraph([
|
|
155
155
|
f"Evaluating at the point {format_vector(self.evaluation_point)}:"
|
|
156
156
|
])
|
|
157
157
|
)
|
|
@@ -162,18 +162,18 @@ class DerivativeQuestion(Question, abc.ABC):
|
|
|
162
162
|
partial_expr = self.gradient_function[i]
|
|
163
163
|
partial_value = partial_expr.subs(subs_map)
|
|
164
164
|
|
|
165
|
-
# Use
|
|
165
|
+
# Use ca.Answer.accepted_strings for clean numerical formatting
|
|
166
166
|
try:
|
|
167
167
|
numerical_value = float(partial_value)
|
|
168
168
|
except (TypeError, ValueError):
|
|
169
169
|
numerical_value = float(partial_value.evalf())
|
|
170
170
|
|
|
171
171
|
# Get clean string representation
|
|
172
|
-
clean_value = sorted(
|
|
172
|
+
clean_value = sorted(ca.Answer.accepted_strings(numerical_value), key=lambda s: len(s))[0]
|
|
173
173
|
|
|
174
174
|
explanation.add_element(
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
ca.Paragraph([
|
|
176
|
+
ca.Equation(
|
|
177
177
|
f"{self._format_partial_derivative(i)} = {sp.latex(partial_expr)} = {clean_value}",
|
|
178
178
|
inline=False
|
|
179
179
|
)
|
|
@@ -182,7 +182,7 @@ class DerivativeQuestion(Question, abc.ABC):
|
|
|
182
182
|
|
|
183
183
|
return explanation, []
|
|
184
184
|
|
|
185
|
-
def get_explanation(self, **kwargs) ->
|
|
185
|
+
def get_explanation(self, **kwargs) -> ca.Section:
|
|
186
186
|
"""Build question explanation (backward compatible interface)."""
|
|
187
187
|
explanation, _ = self._get_explanation(**kwargs)
|
|
188
188
|
return explanation
|
|
@@ -284,26 +284,26 @@ class DerivativeChain(DerivativeQuestion):
|
|
|
284
284
|
f = sp.Function('f')
|
|
285
285
|
self.equation = sp.Eq(f(*self.variables), self.function)
|
|
286
286
|
|
|
287
|
-
def _get_explanation(self, **kwargs) -> Tuple[
|
|
287
|
+
def _get_explanation(self, **kwargs) -> Tuple[ca.Section, List[ca.Answer]]:
|
|
288
288
|
"""Build question explanation."""
|
|
289
|
-
explanation =
|
|
289
|
+
explanation = ca.Section()
|
|
290
290
|
|
|
291
291
|
# Show the composed function structure
|
|
292
292
|
explanation.add_element(
|
|
293
|
-
|
|
293
|
+
ca.Paragraph([
|
|
294
294
|
"This is a composition of functions requiring the chain rule. The function ",
|
|
295
|
-
|
|
295
|
+
ca.Equation(sp.latex(self.equation), inline=True),
|
|
296
296
|
" can be written as ",
|
|
297
|
-
|
|
297
|
+
ca.Equation(f"f(g(x)) \\text{{ where }} g(x) = {sp.latex(self.inner_function)}", inline=True),
|
|
298
298
|
"."
|
|
299
299
|
])
|
|
300
300
|
)
|
|
301
301
|
|
|
302
302
|
# Explain chain rule with Leibniz notation
|
|
303
303
|
explanation.add_element(
|
|
304
|
-
|
|
304
|
+
ca.Paragraph([
|
|
305
305
|
"The chain rule states that for a composite function ",
|
|
306
|
-
|
|
306
|
+
ca.Equation("f(g(x))", inline=True),
|
|
307
307
|
", the derivative with respect to each variable is found by multiplying the derivative of the outer function with respect to the inner function by the derivative of the inner function with respect to the variable:"
|
|
308
308
|
])
|
|
309
309
|
)
|
|
@@ -312,14 +312,14 @@ class DerivativeChain(DerivativeQuestion):
|
|
|
312
312
|
for i in range(self.num_variables):
|
|
313
313
|
var_name = f"x_{i}"
|
|
314
314
|
explanation.add_element(
|
|
315
|
-
|
|
315
|
+
ca.Equation(
|
|
316
316
|
f"\\frac{{\\partial f}}{{\\partial {var_name}}} = \\frac{{\\partial f}}{{\\partial g}} \\cdot \\frac{{\\partial g}}{{\\partial {var_name}}}",
|
|
317
317
|
inline=False
|
|
318
318
|
)
|
|
319
319
|
)
|
|
320
320
|
|
|
321
321
|
explanation.add_element(
|
|
322
|
-
|
|
322
|
+
ca.Paragraph([
|
|
323
323
|
"Applying this to our specific function:"
|
|
324
324
|
])
|
|
325
325
|
)
|
|
@@ -333,13 +333,13 @@ class DerivativeChain(DerivativeQuestion):
|
|
|
333
333
|
inner_deriv = self.inner_function.diff(self.variables[i])
|
|
334
334
|
|
|
335
335
|
explanation.add_element(
|
|
336
|
-
|
|
336
|
+
ca.Paragraph([
|
|
337
337
|
f"For {var_name}:"
|
|
338
338
|
])
|
|
339
339
|
)
|
|
340
340
|
|
|
341
341
|
explanation.add_element(
|
|
342
|
-
|
|
342
|
+
ca.Equation(
|
|
343
343
|
f"\\frac{{\\partial f}}{{\\partial {var_name}}} = \\left({sp.latex(outer_deriv)}\\right) \\cdot \\left({sp.latex(inner_deriv)}\\right)",
|
|
344
344
|
inline=False
|
|
345
345
|
)
|
|
@@ -347,18 +347,18 @@ class DerivativeChain(DerivativeQuestion):
|
|
|
347
347
|
|
|
348
348
|
# Show analytical gradient
|
|
349
349
|
explanation.add_element(
|
|
350
|
-
|
|
350
|
+
ca.Paragraph([
|
|
351
351
|
"This gives us the complete gradient:"
|
|
352
352
|
])
|
|
353
353
|
)
|
|
354
354
|
|
|
355
355
|
explanation.add_element(
|
|
356
|
-
|
|
356
|
+
ca.Equation(f"\\nabla f = {sp.latex(self.gradient_function)}", inline=False)
|
|
357
357
|
)
|
|
358
358
|
|
|
359
359
|
# Show evaluation at the specific point
|
|
360
360
|
explanation.add_element(
|
|
361
|
-
|
|
361
|
+
ca.Paragraph([
|
|
362
362
|
f"Evaluating at the point {format_vector(self.evaluation_point)}:"
|
|
363
363
|
])
|
|
364
364
|
)
|
|
@@ -369,18 +369,18 @@ class DerivativeChain(DerivativeQuestion):
|
|
|
369
369
|
partial_expr = self.gradient_function[i]
|
|
370
370
|
partial_value = partial_expr.subs(subs_map)
|
|
371
371
|
|
|
372
|
-
# Use
|
|
372
|
+
# Use ca.Answer.accepted_strings for clean numerical formatting
|
|
373
373
|
try:
|
|
374
374
|
numerical_value = float(partial_value)
|
|
375
375
|
except (TypeError, ValueError):
|
|
376
376
|
numerical_value = float(partial_value.evalf())
|
|
377
377
|
|
|
378
378
|
# Get clean string representation
|
|
379
|
-
clean_value = sorted(
|
|
379
|
+
clean_value = sorted(ca.Answer.accepted_strings(numerical_value), key=lambda s: len(s))[0]
|
|
380
380
|
|
|
381
381
|
explanation.add_element(
|
|
382
|
-
|
|
383
|
-
|
|
382
|
+
ca.Paragraph([
|
|
383
|
+
ca.Equation(
|
|
384
384
|
f"{self._format_partial_derivative(i)} = {sp.latex(partial_expr)} = {clean_value}",
|
|
385
385
|
inline=False
|
|
386
386
|
)
|
|
@@ -389,7 +389,7 @@ class DerivativeChain(DerivativeQuestion):
|
|
|
389
389
|
|
|
390
390
|
return explanation, []
|
|
391
391
|
|
|
392
|
-
def get_explanation(self, **kwargs) ->
|
|
392
|
+
def get_explanation(self, **kwargs) -> ca.Section:
|
|
393
393
|
"""Build question explanation (backward compatible interface)."""
|
|
394
394
|
explanation, _ = self._get_explanation(**kwargs)
|
|
395
395
|
return explanation
|
|
@@ -6,7 +6,7 @@ import math
|
|
|
6
6
|
from typing import List, Tuple, Callable, Union, Any
|
|
7
7
|
import sympy as sp
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
import QuizGenerator.contentast as ca
|
|
10
10
|
from QuizGenerator.question import Question, QuestionRegistry
|
|
11
11
|
from QuizGenerator.mixins import TableQuestionMixin, BodyTemplatesMixin
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ from .misc import generate_function, format_vector
|
|
|
15
15
|
log = logging.getLogger(__name__)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
# Note: This file does not use
|
|
18
|
+
# Note: This file does not use ca.Answer wrappers - it uses TableQuestionMixin
|
|
19
19
|
# which handles answer display through create_answer_table(). The answers are created
|
|
20
20
|
# with labels embedded at creation time in refresh().
|
|
21
21
|
|
|
@@ -98,19 +98,19 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
98
98
|
|
|
99
99
|
# Location answer
|
|
100
100
|
location_key = f"answer__location_{step}"
|
|
101
|
-
self.answers[location_key] = AnswerTypes.Vector(list(result['location']), label=f"Location at step {step}")
|
|
101
|
+
self.answers[location_key] = ca.AnswerTypes.Vector(list(result['location']), label=f"Location at step {step}")
|
|
102
102
|
|
|
103
103
|
# Gradient answer
|
|
104
104
|
gradient_key = f"answer__gradient_{step}"
|
|
105
|
-
self.answers[gradient_key] = AnswerTypes.Vector(list(result['gradient']), label=f"Gradient at step {step}")
|
|
105
|
+
self.answers[gradient_key] = ca.AnswerTypes.Vector(list(result['gradient']), label=f"Gradient at step {step}")
|
|
106
106
|
|
|
107
107
|
# Update answer
|
|
108
108
|
update_key = f"answer__update_{step}"
|
|
109
|
-
self.answers[update_key] = AnswerTypes.Vector(list(result['update']), label=f"Update at step {step}")
|
|
109
|
+
self.answers[update_key] = ca.AnswerTypes.Vector(list(result['update']), label=f"Update at step {step}")
|
|
110
110
|
|
|
111
|
-
def _get_body(self, **kwargs) -> Tuple[
|
|
111
|
+
def _get_body(self, **kwargs) -> Tuple[ca.Section, List[ca.Answer]]:
|
|
112
112
|
"""Build question body and collect answers."""
|
|
113
|
-
body =
|
|
113
|
+
body = ca.Section()
|
|
114
114
|
answers = []
|
|
115
115
|
|
|
116
116
|
# Introduction
|
|
@@ -118,24 +118,24 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
118
118
|
sign = "-" if self.minimize else "+"
|
|
119
119
|
|
|
120
120
|
body.add_element(
|
|
121
|
-
|
|
121
|
+
ca.Paragraph(
|
|
122
122
|
[
|
|
123
123
|
f"Use gradient descent to {objective} the function ",
|
|
124
|
-
|
|
124
|
+
ca.Equation(sp.latex(self.function), inline=True),
|
|
125
125
|
" with learning rate ",
|
|
126
|
-
|
|
126
|
+
ca.Equation(f"\\alpha = {self.learning_rate}", inline=True),
|
|
127
127
|
f" and starting point {self.starting_point[0] if self.num_variables == 1 else tuple(self.starting_point)}. "
|
|
128
128
|
"Fill in the table below with your calculations."
|
|
129
129
|
]
|
|
130
130
|
)
|
|
131
131
|
)
|
|
132
132
|
|
|
133
|
-
# Create table data - use
|
|
133
|
+
# Create table data - use ca.Equation for proper LaTeX rendering in headers
|
|
134
134
|
headers = [
|
|
135
135
|
"n",
|
|
136
136
|
"location",
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
ca.Equation("\\nabla f", inline=True),
|
|
138
|
+
ca.Equation("\\alpha \\cdot \\nabla f", inline=True)
|
|
139
139
|
]
|
|
140
140
|
table_rows = []
|
|
141
141
|
|
|
@@ -174,17 +174,17 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
174
174
|
|
|
175
175
|
return body, answers
|
|
176
176
|
|
|
177
|
-
def get_body(self, **kwargs) ->
|
|
177
|
+
def get_body(self, **kwargs) -> ca.Section:
|
|
178
178
|
"""Build question body (backward compatible interface)."""
|
|
179
179
|
body, _ = self._get_body(**kwargs)
|
|
180
180
|
return body
|
|
181
181
|
|
|
182
|
-
def _get_explanation(self, **kwargs) -> Tuple[
|
|
182
|
+
def _get_explanation(self, **kwargs) -> Tuple[ca.Section, List[ca.Answer]]:
|
|
183
183
|
"""Build question explanation."""
|
|
184
|
-
explanation =
|
|
184
|
+
explanation = ca.Section()
|
|
185
185
|
|
|
186
186
|
explanation.add_element(
|
|
187
|
-
|
|
187
|
+
ca.Paragraph(
|
|
188
188
|
[
|
|
189
189
|
"Gradient descent is an optimization algorithm that iteratively moves towards "
|
|
190
190
|
"the minimum of a function by taking steps proportional to the negative of the gradient."
|
|
@@ -196,10 +196,10 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
196
196
|
sign = "-" if self.minimize else "+"
|
|
197
197
|
|
|
198
198
|
explanation.add_element(
|
|
199
|
-
|
|
199
|
+
ca.Paragraph(
|
|
200
200
|
[
|
|
201
201
|
f"We want to {objective} the function ",
|
|
202
|
-
|
|
202
|
+
ca.Equation(sp.latex(self.function), inline=True),
|
|
203
203
|
". First, we calculate the analytical gradient:"
|
|
204
204
|
]
|
|
205
205
|
)
|
|
@@ -207,16 +207,16 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
207
207
|
|
|
208
208
|
# Add analytical gradient calculation as a display equation (vertical vector)
|
|
209
209
|
explanation.add_element(
|
|
210
|
-
|
|
210
|
+
ca.Equation(f"\\nabla f = {sp.latex(self.gradient_function)}", inline=False)
|
|
211
211
|
)
|
|
212
212
|
|
|
213
213
|
explanation.add_element(
|
|
214
|
-
|
|
214
|
+
ca.Paragraph(
|
|
215
215
|
[
|
|
216
216
|
f"Since we want to {objective}, we use the update rule: ",
|
|
217
|
-
|
|
217
|
+
ca.Equation(f"x_{{new}} = x_{{old}} {sign} \\alpha \\nabla f", inline=True),
|
|
218
218
|
f". We start at {tuple(self.starting_point)} with learning rate ",
|
|
219
|
-
|
|
219
|
+
ca.Equation(f"\\alpha = {self.learning_rate}", inline=True),
|
|
220
220
|
"."
|
|
221
221
|
]
|
|
222
222
|
)
|
|
@@ -224,7 +224,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
224
224
|
|
|
225
225
|
# Add completed table showing all solutions
|
|
226
226
|
explanation.add_element(
|
|
227
|
-
|
|
227
|
+
ca.Paragraph(
|
|
228
228
|
[
|
|
229
229
|
"**Solution Table:**"
|
|
230
230
|
]
|
|
@@ -235,8 +235,8 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
235
235
|
solution_headers = [
|
|
236
236
|
"n",
|
|
237
237
|
"location",
|
|
238
|
-
|
|
239
|
-
|
|
238
|
+
ca.Equation("\\nabla f", inline=True),
|
|
239
|
+
ca.Equation("\\alpha \\cdot \\nabla f", inline=True)
|
|
240
240
|
]
|
|
241
241
|
|
|
242
242
|
solution_rows = []
|
|
@@ -264,7 +264,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
264
264
|
step = result['step']
|
|
265
265
|
|
|
266
266
|
explanation.add_element(
|
|
267
|
-
|
|
267
|
+
ca.Paragraph(
|
|
268
268
|
[
|
|
269
269
|
f"**Step {step}:**"
|
|
270
270
|
]
|
|
@@ -272,7 +272,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
272
272
|
)
|
|
273
273
|
|
|
274
274
|
explanation.add_element(
|
|
275
|
-
|
|
275
|
+
ca.Paragraph(
|
|
276
276
|
[
|
|
277
277
|
f"Location: {format_vector(result['location'])}"
|
|
278
278
|
]
|
|
@@ -280,7 +280,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
280
280
|
)
|
|
281
281
|
|
|
282
282
|
explanation.add_element(
|
|
283
|
-
|
|
283
|
+
ca.Paragraph(
|
|
284
284
|
[
|
|
285
285
|
f"Gradient: {format_vector(result['gradient'])}"
|
|
286
286
|
]
|
|
@@ -288,10 +288,10 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
288
288
|
)
|
|
289
289
|
|
|
290
290
|
explanation.add_element(
|
|
291
|
-
|
|
291
|
+
ca.Paragraph(
|
|
292
292
|
[
|
|
293
293
|
"Update: ",
|
|
294
|
-
|
|
294
|
+
ca.Equation(
|
|
295
295
|
f"\\alpha \\cdot \\nabla f = {self.learning_rate} \\cdot {format_vector(result['gradient'])} = {format_vector(result['update'])}",
|
|
296
296
|
inline=True
|
|
297
297
|
)
|
|
@@ -306,7 +306,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
306
306
|
next_loc = [current_loc[j] - update[j] for j in range(len(current_loc))]
|
|
307
307
|
|
|
308
308
|
explanation.add_element(
|
|
309
|
-
|
|
309
|
+
ca.Paragraph(
|
|
310
310
|
[
|
|
311
311
|
f"Next location: {format_vector(current_loc)} - {format_vector(result['update'])} = {format_vector(next_loc)}"
|
|
312
312
|
]
|
|
@@ -315,7 +315,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
315
315
|
|
|
316
316
|
function_values = [r['function_value'] for r in self.gradient_descent_results]
|
|
317
317
|
explanation.add_element(
|
|
318
|
-
|
|
318
|
+
ca.Paragraph(
|
|
319
319
|
[
|
|
320
320
|
f"Function values: {[f'{v:.4f}' for v in function_values]}"
|
|
321
321
|
]
|
|
@@ -324,7 +324,7 @@ class GradientDescentWalkthrough(GradientDescentQuestion, TableQuestionMixin, Bo
|
|
|
324
324
|
|
|
325
325
|
return explanation, []
|
|
326
326
|
|
|
327
|
-
def get_explanation(self, **kwargs) ->
|
|
327
|
+
def get_explanation(self, **kwargs) -> ca.Section:
|
|
328
328
|
"""Build question explanation (backward compatible interface)."""
|
|
329
329
|
explanation, _ = self._get_explanation(**kwargs)
|
|
330
330
|
return explanation
|