QuizGenerator 0.7.1__py3-none-any.whl → 0.8.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 +48 -15
- QuizGenerator/generate.py +2 -1
- QuizGenerator/mixins.py +14 -100
- QuizGenerator/premade_questions/basic.py +24 -29
- QuizGenerator/premade_questions/cst334/languages.py +100 -99
- QuizGenerator/premade_questions/cst334/math_questions.py +112 -122
- QuizGenerator/premade_questions/cst334/memory_questions.py +621 -621
- QuizGenerator/premade_questions/cst334/persistence_questions.py +137 -163
- QuizGenerator/premade_questions/cst334/process.py +312 -328
- QuizGenerator/premade_questions/cst463/gradient_descent/gradient_calculation.py +34 -35
- QuizGenerator/premade_questions/cst463/gradient_descent/gradient_descent_questions.py +41 -36
- QuizGenerator/premade_questions/cst463/gradient_descent/loss_calculations.py +48 -41
- QuizGenerator/premade_questions/cst463/math_and_data/matrix_questions.py +285 -521
- QuizGenerator/premade_questions/cst463/math_and_data/vector_questions.py +149 -126
- QuizGenerator/premade_questions/cst463/models/attention.py +44 -50
- QuizGenerator/premade_questions/cst463/models/cnns.py +43 -47
- QuizGenerator/premade_questions/cst463/models/matrices.py +61 -11
- QuizGenerator/premade_questions/cst463/models/rnns.py +48 -50
- QuizGenerator/premade_questions/cst463/models/text.py +65 -67
- QuizGenerator/premade_questions/cst463/models/weight_counting.py +47 -46
- QuizGenerator/premade_questions/cst463/neural-network-basics/neural_network_questions.py +100 -156
- QuizGenerator/premade_questions/cst463/tensorflow-intro/tensorflow_questions.py +93 -141
- QuizGenerator/question.py +310 -202
- QuizGenerator/quiz.py +8 -5
- QuizGenerator/regenerate.py +14 -6
- {quizgenerator-0.7.1.dist-info → quizgenerator-0.8.1.dist-info}/METADATA +30 -2
- {quizgenerator-0.7.1.dist-info → quizgenerator-0.8.1.dist-info}/RECORD +30 -30
- {quizgenerator-0.7.1.dist-info → quizgenerator-0.8.1.dist-info}/WHEEL +0 -0
- {quizgenerator-0.7.1.dist-info → quizgenerator-0.8.1.dist-info}/entry_points.txt +0 -0
- {quizgenerator-0.7.1.dist-info → quizgenerator-0.8.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
|
|
4
4
|
import abc
|
|
5
5
|
import enum
|
|
6
|
-
import
|
|
7
|
-
from typing import List, Dict, Optional
|
|
6
|
+
import random
|
|
7
|
+
from typing import List, Dict, Optional
|
|
8
8
|
|
|
9
9
|
from QuizGenerator.question import QuestionRegistry, Question
|
|
10
10
|
|
|
@@ -154,27 +154,16 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
|
|
|
154
154
|
kwargs['grammar_str_bad'] = grammar_str_bad
|
|
155
155
|
|
|
156
156
|
super().__init__(*args, **kwargs)
|
|
157
|
+
self.answer_kind = ca.Answer.CanvasAnswerKind.MULTIPLE_ANSWER
|
|
157
158
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
self.grammar_str_bad = grammar_str_bad
|
|
163
|
-
self.include_spaces = kwargs.get("include_spaces", False)
|
|
164
|
-
self.MAX_LENGTH = kwargs.get("max_length", 30)
|
|
165
|
-
self.grammar_good = BNF.parse_bnf(self.grammar_str_good, self.rng)
|
|
166
|
-
self.grammar_bad = BNF.parse_bnf(self.grammar_str_bad, self.rng)
|
|
167
|
-
|
|
168
|
-
self.num_answer_options = kwargs.get("num_answer_options", 4)
|
|
169
|
-
self.num_answer_blanks = kwargs.get("num_answer_blanks", 4)
|
|
170
|
-
|
|
171
|
-
def _select_random_grammar(self):
|
|
172
|
-
"""Select and set a random grammar. Called from refresh() to ensure each PDF gets different grammar."""
|
|
173
|
-
which_grammar = self.rng.choice(range(4))
|
|
159
|
+
@classmethod
|
|
160
|
+
def _select_random_grammar(cls, rng):
|
|
161
|
+
"""Select and return a random grammar configuration."""
|
|
162
|
+
which_grammar = rng.choice(range(4))
|
|
174
163
|
|
|
175
164
|
if which_grammar == 0:
|
|
176
165
|
# todo: make a few different kinds of grammars that could be picked
|
|
177
|
-
|
|
166
|
+
grammar_str_good = """
|
|
178
167
|
<expression> ::= <term> | <expression> + <term> | <expression> - <term>
|
|
179
168
|
<term> ::= <factor> | <term> * <factor> | <term> / <factor>
|
|
180
169
|
<factor> ::= <number>
|
|
@@ -182,17 +171,17 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
|
|
|
182
171
|
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
|
183
172
|
"""
|
|
184
173
|
# Adding in a plus to number
|
|
185
|
-
|
|
174
|
+
grammar_str_bad = """
|
|
186
175
|
<expression> ::= <term> | <expression> + <term> | <expression> - <term>
|
|
187
176
|
<term> ::= <factor> | <term> * <factor> | <term> / <factor>
|
|
188
177
|
<factor> ::= <number>
|
|
189
178
|
<number> ::= <digit> + | <digit> <number>
|
|
190
179
|
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
|
191
180
|
"""
|
|
192
|
-
|
|
193
|
-
|
|
181
|
+
include_spaces = False
|
|
182
|
+
max_length = 30
|
|
194
183
|
elif which_grammar == 1:
|
|
195
|
-
|
|
184
|
+
grammar_str_good = """
|
|
196
185
|
<sentence> ::= <subject> <verb> <object>
|
|
197
186
|
<subject> ::= The cat | A dog | The bird | A child | <adjective> <animal>
|
|
198
187
|
<animal> ::= cat | dog | bird | child
|
|
@@ -200,7 +189,7 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
|
|
|
200
189
|
<verb> ::= chases | sees | hates | loves
|
|
201
190
|
<object> ::= the ball | the toy | the tree | <adjective> <object>
|
|
202
191
|
"""
|
|
203
|
-
|
|
192
|
+
grammar_str_bad = """
|
|
204
193
|
<sentence> ::= <subject> <verb> <object>
|
|
205
194
|
<subject> ::= The human | The dog | A bird | Some child | A <adjective> <animal>
|
|
206
195
|
<animal> ::= cat | dog | bird | child
|
|
@@ -208,10 +197,10 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
|
|
|
208
197
|
<verb> ::= chases | sees | hates | loves
|
|
209
198
|
<object> ::= the ball | the toy | the tree | <adjective> <object>
|
|
210
199
|
"""
|
|
211
|
-
|
|
212
|
-
|
|
200
|
+
include_spaces = True
|
|
201
|
+
max_length = 100
|
|
213
202
|
elif which_grammar == 2:
|
|
214
|
-
|
|
203
|
+
grammar_str_good = """
|
|
215
204
|
<poem> ::= <line> | <line> <poem>
|
|
216
205
|
<line> ::= <subject> <verb> <object> <modifier>
|
|
217
206
|
<subject> ::= whispers | shadows | dreams | echoes | <compound-subject>
|
|
@@ -223,7 +212,7 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
|
|
|
223
212
|
<modifier> ::= silently | violently | mysteriously | endlessly | <recursive-modifier>
|
|
224
213
|
<recursive-modifier> ::= <modifier> and <modifier>
|
|
225
214
|
"""
|
|
226
|
-
|
|
215
|
+
grammar_str_bad = """
|
|
227
216
|
<bad-poem> ::= <almost-valid-line> | <bad-poem> <bad-poem>
|
|
228
217
|
<almost-valid-line> ::= <tricky-subject> <tricky-verb> <tricky-object> <tricky-modifier>
|
|
229
218
|
<tricky-subject> ::= whispers | shadows and and | <duplicate-subject>
|
|
@@ -238,103 +227,126 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
|
|
|
238
227
|
<modifier-subject-swap> ::= whispers silently
|
|
239
228
|
<duplicate-modifier> ::= silently silently
|
|
240
229
|
"""
|
|
241
|
-
|
|
242
|
-
|
|
230
|
+
include_spaces = True
|
|
231
|
+
max_length = 100
|
|
243
232
|
elif which_grammar == 3:
|
|
244
|
-
|
|
233
|
+
grammar_str_good = """
|
|
245
234
|
<A> ::= a <B> a |
|
|
246
235
|
<B> ::= b <C> b |
|
|
247
236
|
<C> ::= c <A> c |
|
|
248
237
|
"""
|
|
249
|
-
|
|
238
|
+
grammar_str_bad = """
|
|
250
239
|
<A> ::= a <B> c
|
|
251
240
|
<B> ::= b <C> a |
|
|
252
241
|
<C> ::= c <A> b |
|
|
253
242
|
"""
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
243
|
+
include_spaces = False
|
|
244
|
+
max_length = 100
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
"grammar_str_good": grammar_str_good,
|
|
248
|
+
"grammar_str_bad": grammar_str_bad,
|
|
249
|
+
"include_spaces": include_spaces,
|
|
250
|
+
"max_length": max_length,
|
|
251
|
+
}
|
|
259
252
|
|
|
260
|
-
|
|
261
|
-
|
|
253
|
+
@classmethod
|
|
254
|
+
def _build_context(cls, *, rng_seed=None, **kwargs):
|
|
255
|
+
rng = random.Random(rng_seed)
|
|
256
|
+
|
|
257
|
+
grammar_str_good = kwargs.get("grammar_str_good")
|
|
258
|
+
grammar_str_bad = kwargs.get("grammar_str_bad")
|
|
259
|
+
|
|
260
|
+
if grammar_str_good is not None and grammar_str_bad is not None:
|
|
261
|
+
include_spaces = kwargs.get("include_spaces", False)
|
|
262
|
+
max_length = kwargs.get("max_length", 30)
|
|
263
|
+
else:
|
|
264
|
+
selection = cls._select_random_grammar(rng)
|
|
265
|
+
grammar_str_good = selection["grammar_str_good"]
|
|
266
|
+
grammar_str_bad = selection["grammar_str_bad"]
|
|
267
|
+
include_spaces = selection["include_spaces"]
|
|
268
|
+
max_length = selection["max_length"]
|
|
262
269
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
self._select_random_grammar()
|
|
270
|
+
grammar_good = BNF.parse_bnf(grammar_str_good, rng)
|
|
271
|
+
grammar_bad = BNF.parse_bnf(grammar_str_bad, rng)
|
|
266
272
|
|
|
267
|
-
|
|
273
|
+
num_answer_options = kwargs.get("num_answer_options", 4)
|
|
274
|
+
num_answer_blanks = kwargs.get("num_answer_blanks", 4)
|
|
268
275
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
good_string =
|
|
272
|
-
|
|
276
|
+
answer_options = []
|
|
277
|
+
|
|
278
|
+
good_string = grammar_good.generate(include_spaces)
|
|
279
|
+
answer_options.append(ca.Answer(
|
|
273
280
|
value=good_string,
|
|
274
281
|
kind=ca.Answer.CanvasAnswerKind.MULTIPLE_ANSWER,
|
|
275
282
|
correct=True
|
|
276
|
-
)
|
|
283
|
+
))
|
|
277
284
|
|
|
278
|
-
bad_string =
|
|
279
|
-
|
|
285
|
+
bad_string = grammar_bad.generate(include_spaces)
|
|
286
|
+
answer_options.append(ca.Answer(
|
|
280
287
|
value=bad_string,
|
|
281
288
|
kind=ca.Answer.CanvasAnswerKind.MULTIPLE_ANSWER,
|
|
282
289
|
correct=False
|
|
283
|
-
)
|
|
290
|
+
))
|
|
284
291
|
|
|
285
|
-
bad_early_string =
|
|
286
|
-
|
|
292
|
+
bad_early_string = grammar_bad.generate(include_spaces, early_exit=True)
|
|
293
|
+
answer_options.append(ca.Answer(
|
|
287
294
|
value=bad_early_string,
|
|
288
295
|
kind=ca.Answer.CanvasAnswerKind.MULTIPLE_ANSWER,
|
|
289
296
|
correct=False
|
|
290
|
-
)
|
|
297
|
+
))
|
|
291
298
|
|
|
292
|
-
answer_text_set = {a.value for a in
|
|
299
|
+
answer_text_set = {a.value for a in answer_options}
|
|
293
300
|
num_tries = 0
|
|
294
|
-
while len(
|
|
295
|
-
|
|
296
|
-
correct = self.rng.choice([True, False])
|
|
301
|
+
while len(answer_options) < 10 and num_tries < cls.MAX_TRIES:
|
|
302
|
+
correct = rng.choice([True, False])
|
|
297
303
|
if not correct:
|
|
298
|
-
early_exit =
|
|
304
|
+
early_exit = rng.choice([True, False])
|
|
299
305
|
else:
|
|
300
306
|
early_exit = False
|
|
301
307
|
|
|
302
308
|
generated_string = (
|
|
303
|
-
|
|
309
|
+
grammar_good
|
|
304
310
|
if correct or early_exit
|
|
305
|
-
else
|
|
306
|
-
).generate(
|
|
311
|
+
else grammar_bad
|
|
312
|
+
).generate(include_spaces, early_exit=early_exit)
|
|
307
313
|
|
|
308
314
|
is_correct = correct and not early_exit
|
|
309
315
|
|
|
310
|
-
if len(generated_string) <
|
|
311
|
-
|
|
316
|
+
if len(generated_string) < max_length and generated_string not in answer_text_set:
|
|
317
|
+
answer_options.append(ca.Answer(
|
|
312
318
|
value=generated_string,
|
|
313
319
|
kind=ca.Answer.CanvasAnswerKind.MULTIPLE_ANSWER,
|
|
314
320
|
correct=is_correct
|
|
315
|
-
)
|
|
321
|
+
))
|
|
316
322
|
answer_text_set.add(generated_string)
|
|
317
323
|
num_tries += 1
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
self.grammar_good.generate(early_exit=True)
|
|
324
|
+
|
|
325
|
+
featured_answers = {
|
|
326
|
+
grammar_good.generate(),
|
|
327
|
+
grammar_bad.generate(),
|
|
328
|
+
grammar_good.generate(early_exit=True)
|
|
324
329
|
}
|
|
325
|
-
while len(
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
lambda:
|
|
329
|
-
lambda:
|
|
330
|
-
lambda:
|
|
330
|
+
while len(featured_answers) < num_answer_options:
|
|
331
|
+
featured_answers.add(
|
|
332
|
+
rng.choice([
|
|
333
|
+
lambda: grammar_good.generate(),
|
|
334
|
+
lambda: grammar_bad.generate(),
|
|
335
|
+
lambda: grammar_good.generate(early_exit=True),
|
|
331
336
|
])()
|
|
332
337
|
)
|
|
333
|
-
|
|
334
|
-
def _get_body(self, *args, **kwargs):
|
|
335
|
-
"""Build question body and collect answers."""
|
|
336
|
-
answers = list(self.answers.values())
|
|
337
338
|
|
|
339
|
+
return {
|
|
340
|
+
"grammar_good": grammar_good,
|
|
341
|
+
"answer_options": answer_options,
|
|
342
|
+
"featured_answers": featured_answers,
|
|
343
|
+
"include_spaces": include_spaces,
|
|
344
|
+
"num_answer_blanks": num_answer_blanks,
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
@classmethod
|
|
348
|
+
def _build_body(cls, context):
|
|
349
|
+
"""Build question body and collect answers."""
|
|
338
350
|
body = ca.Section()
|
|
339
351
|
|
|
340
352
|
body.add_element(
|
|
@@ -355,30 +367,26 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
|
|
|
355
367
|
)
|
|
356
368
|
|
|
357
369
|
body.add_element(
|
|
358
|
-
ca.Code(
|
|
370
|
+
ca.Code(context["grammar_good"].get_grammar_string())
|
|
359
371
|
)
|
|
360
372
|
|
|
361
373
|
# Add in some answers as latex-only options to be circled
|
|
362
374
|
latex_list = ca.OnlyLatex([])
|
|
363
|
-
for answer in
|
|
375
|
+
for answer in context["featured_answers"]:
|
|
364
376
|
latex_list.add_element(ca.Paragraph([f"- `{str(answer)}`"]))
|
|
365
377
|
body.add_element(latex_list)
|
|
366
378
|
|
|
367
379
|
# For Latex-only, ask students to generate some more.
|
|
368
380
|
body.add_element(
|
|
369
381
|
ca.OnlyLatex([
|
|
370
|
-
ca.AnswerBlock([ca.AnswerTypes.String("", label="") for i in range(
|
|
382
|
+
ca.AnswerBlock([ca.AnswerTypes.String("", label="") for i in range(context["num_answer_blanks"])])
|
|
371
383
|
])
|
|
372
384
|
)
|
|
373
385
|
|
|
374
|
-
return body,
|
|
386
|
+
return body, list(context["answer_options"])
|
|
375
387
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
body, _ = self._get_body(*args, **kwargs)
|
|
379
|
-
return body
|
|
380
|
-
|
|
381
|
-
def _get_explanation(self, *args, **kwargs):
|
|
388
|
+
@classmethod
|
|
389
|
+
def _build_explanation(cls, context):
|
|
382
390
|
"""Build question explanation."""
|
|
383
391
|
explanation = ca.Section()
|
|
384
392
|
explanation.add_element(
|
|
@@ -387,13 +395,6 @@ class ValidStringsInLanguageQuestion(LanguageQuestion):
|
|
|
387
395
|
"Unfortunately, there isn't space here to demonstrate the derivation so please work through them on your own!"
|
|
388
396
|
])
|
|
389
397
|
)
|
|
390
|
-
return explanation, []
|
|
391
|
-
|
|
392
|
-
def get_explanation(self, *args, **kwargs) -> ca.Section:
|
|
393
|
-
"""Build question explanation (backward compatible interface)."""
|
|
394
|
-
explanation, _ = self._get_explanation(*args, **kwargs)
|
|
395
398
|
return explanation
|
|
396
399
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
return ca.Answer.CanvasAnswerKind.MULTIPLE_ANSWER, list(itertools.chain(*[a.get_for_canvas() for a in self.answers.values()]))
|
|
400
|
+
|