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.
- 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/typst_utils.py +2 -2
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/METADATA +1 -1
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/RECORD +30 -30
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/WHEEL +0 -0
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/entry_points.txt +0 -0
- {quizgenerator-0.6.3.dist-info → quizgenerator-0.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,7 +6,7 @@ import difflib
|
|
|
6
6
|
import logging
|
|
7
7
|
|
|
8
8
|
from QuizGenerator.question import Question, QuestionRegistry
|
|
9
|
-
|
|
9
|
+
import QuizGenerator.contentast as ca
|
|
10
10
|
from QuizGenerator.mixins import TableQuestionMixin, BodyTemplatesMixin
|
|
11
11
|
|
|
12
12
|
log = logging.getLogger(__name__)
|
|
@@ -36,10 +36,10 @@ class HardDriveAccessTime(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
36
36
|
self.disk_access_delay = self.access_delay * self.number_of_reads + self.transfer_delay
|
|
37
37
|
|
|
38
38
|
self.answers.update({
|
|
39
|
-
"answer__rotational_delay" : AnswerTypes.Float(self.rotational_delay),
|
|
40
|
-
"answer__access_delay" : AnswerTypes.Float(self.access_delay),
|
|
41
|
-
"answer__transfer_delay" : AnswerTypes.Float(self.transfer_delay),
|
|
42
|
-
"answer__disk_access_delay" : AnswerTypes.Float(self.disk_access_delay),
|
|
39
|
+
"answer__rotational_delay" : ca.AnswerTypes.Float(self.rotational_delay),
|
|
40
|
+
"answer__access_delay" : ca.AnswerTypes.Float(self.access_delay),
|
|
41
|
+
"answer__transfer_delay" : ca.AnswerTypes.Float(self.transfer_delay),
|
|
42
|
+
"answer__disk_access_delay" : ca.AnswerTypes.Float(self.disk_access_delay),
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
def _get_body(self, *args, **kwargs):
|
|
@@ -94,16 +94,16 @@ class HardDriveAccessTime(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
94
94
|
|
|
95
95
|
return body, answers
|
|
96
96
|
|
|
97
|
-
def get_body(self, *args, **kwargs) ->
|
|
97
|
+
def get_body(self, *args, **kwargs) -> ca.Section:
|
|
98
98
|
"""Build question body (backward compatible interface)."""
|
|
99
99
|
body, _ = self._get_body(*args, **kwargs)
|
|
100
100
|
return body
|
|
101
101
|
|
|
102
102
|
def _get_explanation(self):
|
|
103
|
-
explanation =
|
|
103
|
+
explanation = ca.Section()
|
|
104
104
|
|
|
105
105
|
explanation.add_element(
|
|
106
|
-
|
|
106
|
+
ca.Paragraph([
|
|
107
107
|
"To calculate the total disk access time (or \"delay\"), "
|
|
108
108
|
"we should first calculate each of the individual parts.",
|
|
109
109
|
r"Since we know that $t_{total} = (\text{# of reads}) \cdot t_{access} + t_{transfer}$"
|
|
@@ -113,8 +113,8 @@ class HardDriveAccessTime(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
113
113
|
)
|
|
114
114
|
|
|
115
115
|
explanation.add_elements([
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
ca.Paragraph(["Starting with the rotation delay, we calculate:"]),
|
|
117
|
+
ca.Equation(
|
|
118
118
|
"t_{rotation} = "
|
|
119
119
|
+ f"\\frac{{1 minute}}{{{self.hard_drive_rotation_speed}revolutions}}"
|
|
120
120
|
+ r"\cdot \frac{60 seconds}{1 minute} \cdot \frac{1000 ms}{1 second} \cdot \frac{1 revolution}{2} = "
|
|
@@ -123,10 +123,10 @@ class HardDriveAccessTime(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
123
123
|
])
|
|
124
124
|
|
|
125
125
|
explanation.add_elements([
|
|
126
|
-
|
|
126
|
+
ca.Paragraph([
|
|
127
127
|
"Now we can calculate:",
|
|
128
128
|
]),
|
|
129
|
-
|
|
129
|
+
ca.Equation(
|
|
130
130
|
f"t_{{access}} "
|
|
131
131
|
f"= t_{{rotation}} + t_{{seek}} "
|
|
132
132
|
f"= {self.rotational_delay:0.2f}ms + {self.seek_delay:0.2f}ms = {self.access_delay:0.2f}ms"
|
|
@@ -134,8 +134,8 @@ class HardDriveAccessTime(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
134
134
|
])
|
|
135
135
|
|
|
136
136
|
explanation.add_elements([
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
ca.Paragraph([r"Next we need to calculate our transfer delay, $t_{transfer}$, which we do as:"]),
|
|
138
|
+
ca.Equation(
|
|
139
139
|
f"t_{{transfer}} "
|
|
140
140
|
f"= \\frac{{{self.number_of_reads} \\cdot {self.size_of_reads}KB}}{{1}} \\cdot \\frac{{1MB}}{{1024KB}} "
|
|
141
141
|
f"\\cdot \\frac{{1 second}}{{{self.transfer_rate}MB}} \\cdot \\frac{{1000ms}}{{1second}} "
|
|
@@ -144,8 +144,8 @@ class HardDriveAccessTime(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
144
144
|
])
|
|
145
145
|
|
|
146
146
|
explanation.add_elements([
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
ca.Paragraph(["Putting these together we get:"]),
|
|
148
|
+
ca.Equation(
|
|
149
149
|
f"t_{{total}} "
|
|
150
150
|
f"= \\text{{(# reads)}} \\cdot t_{{access}} + t_{{transfer}} "
|
|
151
151
|
f"= {self.number_of_reads} \\cdot {self.access_delay:0.2f} + {self.transfer_delay:0.2f} "
|
|
@@ -153,7 +153,7 @@ class HardDriveAccessTime(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
153
153
|
])
|
|
154
154
|
return explanation, []
|
|
155
155
|
|
|
156
|
-
def get_explanation(self) ->
|
|
156
|
+
def get_explanation(self) -> ca.Section:
|
|
157
157
|
"""Build question explanation (backward compatible interface)."""
|
|
158
158
|
explanation, _ = self._get_explanation()
|
|
159
159
|
return explanation
|
|
@@ -178,10 +178,10 @@ class INodeAccesses(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
178
178
|
self.inode_index_in_block = int(self.inode_address_in_block / self.inode_size)
|
|
179
179
|
|
|
180
180
|
self.answers.update({
|
|
181
|
-
"answer__inode_address": AnswerTypes.Int(self.inode_address),
|
|
182
|
-
"answer__inode_block": AnswerTypes.Int(self.inode_block),
|
|
183
|
-
"answer__inode_address_in_block": AnswerTypes.Int(self.inode_address_in_block),
|
|
184
|
-
"answer__inode_index_in_block": AnswerTypes.Int(self.inode_index_in_block),
|
|
181
|
+
"answer__inode_address": ca.AnswerTypes.Int(self.inode_address),
|
|
182
|
+
"answer__inode_block": ca.AnswerTypes.Int(self.inode_block),
|
|
183
|
+
"answer__inode_address_in_block": ca.AnswerTypes.Int(self.inode_address_in_block),
|
|
184
|
+
"answer__inode_index_in_block": ca.AnswerTypes.Int(self.inode_index_in_block),
|
|
185
185
|
})
|
|
186
186
|
|
|
187
187
|
def _get_body(self):
|
|
@@ -229,16 +229,16 @@ class INodeAccesses(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
229
229
|
|
|
230
230
|
return body, answers
|
|
231
231
|
|
|
232
|
-
def get_body(self) ->
|
|
232
|
+
def get_body(self) -> ca.Section:
|
|
233
233
|
"""Build question body (backward compatible interface)."""
|
|
234
234
|
body, _ = self._get_body()
|
|
235
235
|
return body
|
|
236
236
|
|
|
237
237
|
def _get_explanation(self):
|
|
238
|
-
explanation =
|
|
238
|
+
explanation = ca.Section()
|
|
239
239
|
|
|
240
240
|
explanation.add_element(
|
|
241
|
-
|
|
241
|
+
ca.Paragraph([
|
|
242
242
|
"If we are given an inode number, there are a few steps that we need to take to load the actual inode. "
|
|
243
243
|
"These consist of determining the address of the inode, which block would contain it, "
|
|
244
244
|
"and then its address within the block.",
|
|
@@ -247,7 +247,7 @@ class INodeAccesses(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
247
247
|
)
|
|
248
248
|
|
|
249
249
|
explanation.add_element(
|
|
250
|
-
|
|
250
|
+
ca.Equation.make_block_equation__multiline_equals(
|
|
251
251
|
r"(\text{Inode address})",
|
|
252
252
|
[
|
|
253
253
|
r"(\text{Inode Start Location}) + (\text{inode #}) \cdot (\text{inode size})",
|
|
@@ -257,13 +257,13 @@ class INodeAccesses(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
257
257
|
)
|
|
258
258
|
|
|
259
259
|
explanation.add_element(
|
|
260
|
-
|
|
260
|
+
ca.Paragraph([
|
|
261
261
|
"Next, we us this to figure out what block the inode is in. "
|
|
262
262
|
"We do this directly so we know what block to load, "
|
|
263
263
|
"thus minimizing the number of loads we have to make.",
|
|
264
264
|
])
|
|
265
265
|
)
|
|
266
|
-
explanation.add_element(
|
|
266
|
+
explanation.add_element(ca.Equation.make_block_equation__multiline_equals(
|
|
267
267
|
r"\text{Block containing inode}",
|
|
268
268
|
[
|
|
269
269
|
r"(\text{Inode address}) \mathbin{//} (\text{block size})",
|
|
@@ -273,7 +273,7 @@ class INodeAccesses(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
273
273
|
))
|
|
274
274
|
|
|
275
275
|
explanation.add_element(
|
|
276
|
-
|
|
276
|
+
ca.Paragraph([
|
|
277
277
|
"When we load this block, we now have in our system memory "
|
|
278
278
|
"(remember, blocks on the hard drive are effectively useless to us until they're in main memory!), "
|
|
279
279
|
"the inode, so next we need to figure out where it is within that block."
|
|
@@ -283,7 +283,7 @@ class INodeAccesses(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
283
283
|
])
|
|
284
284
|
)
|
|
285
285
|
|
|
286
|
-
explanation.add_element(
|
|
286
|
+
explanation.add_element(ca.Equation.make_block_equation__multiline_equals(
|
|
287
287
|
r"\text{offset within block}",
|
|
288
288
|
[
|
|
289
289
|
r"(\text{Inode address}) \bmod (\text{block size})",
|
|
@@ -293,12 +293,12 @@ class INodeAccesses(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
293
293
|
))
|
|
294
294
|
|
|
295
295
|
explanation.add_element(
|
|
296
|
-
|
|
296
|
+
ca.Text("Remember that `mod` is the same as `%`, the modulo operation.")
|
|
297
297
|
)
|
|
298
298
|
|
|
299
|
-
explanation.add_element(
|
|
299
|
+
explanation.add_element(ca.Paragraph(["and"]))
|
|
300
300
|
|
|
301
|
-
explanation.add_element(
|
|
301
|
+
explanation.add_element(ca.Equation.make_block_equation__multiline_equals(
|
|
302
302
|
r"\text{index within block}",
|
|
303
303
|
[
|
|
304
304
|
r"\dfrac{\text{offset within block}}{\text{inode size}}",
|
|
@@ -309,7 +309,7 @@ class INodeAccesses(IOQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
309
309
|
|
|
310
310
|
return explanation, []
|
|
311
311
|
|
|
312
|
-
def get_explanation(self) ->
|
|
312
|
+
def get_explanation(self) -> ca.Section:
|
|
313
313
|
"""Build question explanation (backward compatible interface)."""
|
|
314
314
|
explanation, _ = self._get_explanation()
|
|
315
315
|
return explanation
|
|
@@ -322,7 +322,7 @@ class VSFS_states(IOQuestion):
|
|
|
322
322
|
|
|
323
323
|
def __init__(self, *args, **kwargs):
|
|
324
324
|
super().__init__(*args, **kwargs)
|
|
325
|
-
self.answer_kind =
|
|
325
|
+
self.answer_kind = ca.Answer.CanvasAnswerKind.MULTIPLE_DROPDOWN
|
|
326
326
|
|
|
327
327
|
self.num_steps = kwargs.get("num_steps", 10)
|
|
328
328
|
|
|
@@ -344,7 +344,7 @@ class VSFS_states(IOQuestion):
|
|
|
344
344
|
))
|
|
345
345
|
self.rng.shuffle(wrong_answers)
|
|
346
346
|
|
|
347
|
-
self.answers["answer__cmd"] =
|
|
347
|
+
self.answers["answer__cmd"] = ca.Answer.dropdown(
|
|
348
348
|
f"{operations[-1]['cmd']}",
|
|
349
349
|
baffles=list(set([op['cmd'] for op in operations[:-1] if op != operations[-1]['cmd']])),
|
|
350
350
|
label="Command"
|
|
@@ -354,21 +354,21 @@ class VSFS_states(IOQuestion):
|
|
|
354
354
|
"""Build question body and collect answers."""
|
|
355
355
|
answers = [self.answers["answer__cmd"]]
|
|
356
356
|
|
|
357
|
-
body =
|
|
357
|
+
body = ca.Section()
|
|
358
358
|
|
|
359
|
-
body.add_element(
|
|
359
|
+
body.add_element(ca.Paragraph(["What operation happens between these two states?"]))
|
|
360
360
|
|
|
361
361
|
body.add_element(
|
|
362
|
-
|
|
362
|
+
ca.Code(
|
|
363
363
|
self.start_state,
|
|
364
364
|
make_small=True
|
|
365
365
|
)
|
|
366
366
|
)
|
|
367
367
|
|
|
368
|
-
body.add_element(
|
|
368
|
+
body.add_element(ca.AnswerBlock(self.answers["answer__cmd"]))
|
|
369
369
|
|
|
370
370
|
body.add_element(
|
|
371
|
-
|
|
371
|
+
ca.Code(
|
|
372
372
|
self.end_state,
|
|
373
373
|
make_small=True
|
|
374
374
|
)
|
|
@@ -376,19 +376,19 @@ class VSFS_states(IOQuestion):
|
|
|
376
376
|
|
|
377
377
|
return body, answers
|
|
378
378
|
|
|
379
|
-
def get_body(self) ->
|
|
379
|
+
def get_body(self) -> ca.Section:
|
|
380
380
|
"""Build question body (backward compatible interface)."""
|
|
381
381
|
body, _ = self._get_body()
|
|
382
382
|
return body
|
|
383
383
|
|
|
384
384
|
def _get_explanation(self):
|
|
385
|
-
explanation =
|
|
385
|
+
explanation = ca.Section()
|
|
386
386
|
|
|
387
387
|
log.debug(f"self.start_state: {self.start_state}")
|
|
388
388
|
log.debug(f"self.end_state: {self.end_state}")
|
|
389
389
|
|
|
390
390
|
explanation.add_elements([
|
|
391
|
-
|
|
391
|
+
ca.Paragraph([
|
|
392
392
|
"The key thing to pay attention to when solving these problems is where there are differences between the start state and the end state.",
|
|
393
393
|
"In this particular problem, we can see that these lines are different:"
|
|
394
394
|
])
|
|
@@ -405,7 +405,7 @@ class VSFS_states(IOQuestion):
|
|
|
405
405
|
)
|
|
406
406
|
|
|
407
407
|
explanation.add_element(
|
|
408
|
-
|
|
408
|
+
ca.Paragraph(chunk_to_add)
|
|
409
409
|
)
|
|
410
410
|
|
|
411
411
|
chunk_to_add = [
|
|
@@ -452,22 +452,22 @@ class VSFS_states(IOQuestion):
|
|
|
452
452
|
chunk_to_add.append("If they have not changed, then we know we must have eithered called `link` or `unlink` and must check the references.")
|
|
453
453
|
|
|
454
454
|
explanation.add_element(
|
|
455
|
-
|
|
455
|
+
ca.Paragraph(chunk_to_add)
|
|
456
456
|
)
|
|
457
457
|
|
|
458
458
|
explanation.add_elements([
|
|
459
|
-
|
|
459
|
+
ca.Paragraph(["The overall changes are highlighted with `*` symbols below"])
|
|
460
460
|
])
|
|
461
461
|
|
|
462
462
|
explanation.add_element(
|
|
463
|
-
|
|
463
|
+
ca.Code(
|
|
464
464
|
highlight_changes(self.start_state, self.end_state)
|
|
465
465
|
)
|
|
466
466
|
)
|
|
467
467
|
|
|
468
468
|
return explanation, []
|
|
469
469
|
|
|
470
|
-
def get_explanation(self) ->
|
|
470
|
+
def get_explanation(self) -> ca.Section:
|
|
471
471
|
"""Build question explanation (backward compatible interface)."""
|
|
472
472
|
explanation, _ = self._get_explanation()
|
|
473
473
|
return explanation
|
|
@@ -13,7 +13,7 @@ from typing import List
|
|
|
13
13
|
|
|
14
14
|
import matplotlib.pyplot as plt
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
import QuizGenerator.contentast as ca
|
|
17
17
|
from QuizGenerator.question import Question, QuestionRegistry, RegenerableChoiceMixin
|
|
18
18
|
from QuizGenerator.mixins import TableQuestionMixin, BodyTemplatesMixin
|
|
19
19
|
|
|
@@ -356,15 +356,15 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
356
356
|
|
|
357
357
|
for job_id in sorted(self.job_stats.keys()):
|
|
358
358
|
self.answers.update({
|
|
359
|
-
f"answer__response_time_job{job_id}": AnswerTypes.Float(self.job_stats[job_id]["Response"]),
|
|
360
|
-
f"answer__turnaround_time_job{job_id}": AnswerTypes.Float(self.job_stats[job_id]["TAT"]),
|
|
359
|
+
f"answer__response_time_job{job_id}": ca.AnswerTypes.Float(self.job_stats[job_id]["Response"]),
|
|
360
|
+
f"answer__turnaround_time_job{job_id}": ca.AnswerTypes.Float(self.job_stats[job_id]["TAT"]),
|
|
361
361
|
})
|
|
362
362
|
self.answers.update({
|
|
363
|
-
"answer__average_response_time": AnswerTypes.Float(
|
|
363
|
+
"answer__average_response_time": ca.AnswerTypes.Float(
|
|
364
364
|
sum([job.response_time for job in jobs]) / len(jobs),
|
|
365
365
|
label="Overall average response time"
|
|
366
366
|
),
|
|
367
|
-
"answer__average_turnaround_time": AnswerTypes.Float(
|
|
367
|
+
"answer__average_turnaround_time": ca.AnswerTypes.Float(
|
|
368
368
|
sum([job.turnaround_time for job in jobs]) / len(jobs),
|
|
369
369
|
label="Overall average TAT"
|
|
370
370
|
)
|
|
@@ -380,7 +380,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
380
380
|
Tuple of (body_ast, answers_list)
|
|
381
381
|
"""
|
|
382
382
|
from typing import List
|
|
383
|
-
answers: List[
|
|
383
|
+
answers: List[ca.Answer] = []
|
|
384
384
|
|
|
385
385
|
# Create table data for scheduling results
|
|
386
386
|
table_rows = []
|
|
@@ -410,7 +410,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
410
410
|
answers.append(avg_tat_answer)
|
|
411
411
|
|
|
412
412
|
# Create average answer block
|
|
413
|
-
average_block =
|
|
413
|
+
average_block = ca.AnswerBlock([avg_response_answer, avg_tat_answer])
|
|
414
414
|
|
|
415
415
|
# Use mixin to create complete body
|
|
416
416
|
intro_text = (
|
|
@@ -418,8 +418,8 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
418
418
|
f"Break any ties using the job number."
|
|
419
419
|
)
|
|
420
420
|
|
|
421
|
-
instructions =
|
|
422
|
-
f"Please format answer as fractions, mixed numbers, or numbers rounded to a maximum of {
|
|
421
|
+
instructions = ca.OnlyHtml([ca.Paragraph([
|
|
422
|
+
f"Please format answer as fractions, mixed numbers, or numbers rounded to a maximum of {ca.Answer.DEFAULT_ROUNDING_DIGITS} digits after the decimal. "
|
|
423
423
|
"Examples of appropriately formatted answers would be `0`, `3/2`, `1 1/3`, `1.6667`, and `1.25`. "
|
|
424
424
|
"Note that answers that can be rounded to whole numbers should be, rather than being left in fractional form."
|
|
425
425
|
])])
|
|
@@ -428,7 +428,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
428
428
|
body.add_element(average_block)
|
|
429
429
|
return body, answers
|
|
430
430
|
|
|
431
|
-
def get_body(self, *args, **kwargs) ->
|
|
431
|
+
def get_body(self, *args, **kwargs) -> ca.Section:
|
|
432
432
|
"""Build question body (backward compatible interface)."""
|
|
433
433
|
body, _ = self._get_body(*args, **kwargs)
|
|
434
434
|
return body
|
|
@@ -439,32 +439,32 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
439
439
|
Returns:
|
|
440
440
|
Tuple of (explanation_ast, answers_list)
|
|
441
441
|
"""
|
|
442
|
-
explanation =
|
|
442
|
+
explanation = ca.Section()
|
|
443
443
|
|
|
444
444
|
explanation.add_element(
|
|
445
|
-
|
|
445
|
+
ca.Paragraph([
|
|
446
446
|
f"To calculate the overall Turnaround and Response times using {self.scheduler_algorithm} "
|
|
447
447
|
f"we want to first start by calculating the respective target and response times of all of our individual jobs."
|
|
448
448
|
])
|
|
449
449
|
)
|
|
450
450
|
|
|
451
451
|
explanation.add_elements([
|
|
452
|
-
|
|
452
|
+
ca.Paragraph([
|
|
453
453
|
"We do this by subtracting arrival time from either the completion time or the start time. That is:"
|
|
454
454
|
]),
|
|
455
|
-
|
|
456
|
-
|
|
455
|
+
ca.Equation("Job_{TAT} = Job_{completion} - Job_{arrival\_time}"),
|
|
456
|
+
ca.Equation("Job_{response} = Job_{start} - Job_{arrival\_time}"),
|
|
457
457
|
])
|
|
458
458
|
|
|
459
459
|
explanation.add_element(
|
|
460
|
-
|
|
460
|
+
ca.Paragraph([
|
|
461
461
|
f"For each of our {len(self.job_stats.keys())} jobs, we can make these calculations.",
|
|
462
462
|
])
|
|
463
463
|
)
|
|
464
464
|
|
|
465
465
|
## Add in TAT
|
|
466
466
|
explanation.add_element(
|
|
467
|
-
|
|
467
|
+
ca.Paragraph([
|
|
468
468
|
"For turnaround time (TAT) this would be:"
|
|
469
469
|
] + [
|
|
470
470
|
f"Job{job_id}_TAT "
|
|
@@ -479,7 +479,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
479
479
|
f"{self.job_stats[job_id]['TAT']:0.{self.ROUNDING_DIGITS}f}" for job_id in sorted(self.job_stats.keys())
|
|
480
480
|
])
|
|
481
481
|
explanation.add_element(
|
|
482
|
-
|
|
482
|
+
ca.Paragraph([
|
|
483
483
|
f"We then calculate the average of these to find the average TAT time",
|
|
484
484
|
f"Avg(TAT) = ({summation_line}) / ({len(self.job_stats.keys())}) "
|
|
485
485
|
f"= {self.overall_stats['TAT']:0.{self.ROUNDING_DIGITS}f}",
|
|
@@ -489,7 +489,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
489
489
|
|
|
490
490
|
## Add in Response
|
|
491
491
|
explanation.add_element(
|
|
492
|
-
|
|
492
|
+
ca.Paragraph([
|
|
493
493
|
"For response time this would be:"
|
|
494
494
|
] + [
|
|
495
495
|
f"Job{job_id}_response "
|
|
@@ -504,7 +504,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
504
504
|
f"{self.job_stats[job_id]['Response']:0.{self.ROUNDING_DIGITS}f}" for job_id in sorted(self.job_stats.keys())
|
|
505
505
|
])
|
|
506
506
|
explanation.add_element(
|
|
507
|
-
|
|
507
|
+
ca.Paragraph([
|
|
508
508
|
f"We then calculate the average of these to find the average Response time",
|
|
509
509
|
f"Avg(Response) "
|
|
510
510
|
f"= ({summation_line}) / ({len(self.job_stats.keys())}) "
|
|
@@ -514,7 +514,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
514
514
|
)
|
|
515
515
|
|
|
516
516
|
explanation.add_element(
|
|
517
|
-
|
|
517
|
+
ca.Table(
|
|
518
518
|
headers=["Time", "Events"],
|
|
519
519
|
data=[
|
|
520
520
|
[f"{t:02.{self.ROUNDING_DIGITS}f}s"] + ['\n'.join(self.timeline[t])]
|
|
@@ -524,7 +524,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
524
524
|
)
|
|
525
525
|
|
|
526
526
|
explanation.add_element(
|
|
527
|
-
|
|
527
|
+
ca.Picture(
|
|
528
528
|
img_data=self.make_image(),
|
|
529
529
|
caption="Process Scheduling Overview"
|
|
530
530
|
)
|
|
@@ -532,7 +532,7 @@ class SchedulingQuestion(ProcessQuestion, RegenerableChoiceMixin, TableQuestionM
|
|
|
532
532
|
|
|
533
533
|
return explanation, []
|
|
534
534
|
|
|
535
|
-
def get_explanation(self, **kwargs) ->
|
|
535
|
+
def get_explanation(self, **kwargs) -> ca.Section:
|
|
536
536
|
"""Build question explanation (backward compatible interface)."""
|
|
537
537
|
explanation, _ = self._get_explanation(**kwargs)
|
|
538
538
|
return explanation
|
|
@@ -907,13 +907,13 @@ class MLFQQuestion(ProcessQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
907
907
|
|
|
908
908
|
for job_id in sorted(self.job_stats.keys()):
|
|
909
909
|
self.answers.update({
|
|
910
|
-
f"answer__turnaround_time_job{job_id}": AnswerTypes.Float(self.job_stats[job_id]["TAT"])
|
|
910
|
+
f"answer__turnaround_time_job{job_id}": ca.AnswerTypes.Float(self.job_stats[job_id]["TAT"])
|
|
911
911
|
})
|
|
912
912
|
|
|
913
913
|
return self.is_interesting()
|
|
914
914
|
|
|
915
915
|
def _get_body(self, *args, **kwargs):
|
|
916
|
-
answers: List[
|
|
916
|
+
answers: List[ca.Answer] = []
|
|
917
917
|
|
|
918
918
|
queue_rows = []
|
|
919
919
|
for i in reversed(range(self.num_queues)):
|
|
@@ -923,7 +923,7 @@ class MLFQQuestion(ProcessQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
923
923
|
self.queue_quantums[i],
|
|
924
924
|
"infinite" if allotment is None else allotment
|
|
925
925
|
])
|
|
926
|
-
queue_table =
|
|
926
|
+
queue_table = ca.Table(
|
|
927
927
|
headers=["Queue", "Quantum", "Allotment"],
|
|
928
928
|
data=queue_rows
|
|
929
929
|
)
|
|
@@ -953,38 +953,38 @@ class MLFQQuestion(ProcessQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
953
953
|
|
|
954
954
|
instructions = (
|
|
955
955
|
f"Compute the turnaround time (TAT) for each job. "
|
|
956
|
-
f"Round to at most {
|
|
956
|
+
f"Round to at most {ca.Answer.DEFAULT_ROUNDING_DIGITS} digits after the decimal."
|
|
957
957
|
)
|
|
958
958
|
|
|
959
|
-
body =
|
|
960
|
-
body.add_element(
|
|
959
|
+
body = ca.Section()
|
|
960
|
+
body.add_element(ca.Paragraph([intro_text]))
|
|
961
961
|
body.add_element(queue_table)
|
|
962
962
|
if self.boost_interval is not None:
|
|
963
|
-
body.add_element(
|
|
963
|
+
body.add_element(ca.Paragraph([
|
|
964
964
|
f"Every {self.boost_interval} time units, all jobs are boosted to "
|
|
965
965
|
f"Q{self.num_queues - 1}. After a boost, scheduling restarts with the "
|
|
966
966
|
"lowest job number in that queue."
|
|
967
967
|
]))
|
|
968
|
-
body.add_element(
|
|
968
|
+
body.add_element(ca.Paragraph([instructions]))
|
|
969
969
|
body.add_element(scheduling_table)
|
|
970
970
|
return body, answers
|
|
971
971
|
|
|
972
|
-
def get_body(self, *args, **kwargs) ->
|
|
972
|
+
def get_body(self, *args, **kwargs) -> ca.Section:
|
|
973
973
|
body, _ = self._get_body(*args, **kwargs)
|
|
974
974
|
return body
|
|
975
975
|
|
|
976
976
|
def _get_explanation(self, **kwargs):
|
|
977
|
-
explanation =
|
|
977
|
+
explanation = ca.Section()
|
|
978
978
|
|
|
979
979
|
explanation.add_element(
|
|
980
|
-
|
|
980
|
+
ca.Paragraph([
|
|
981
981
|
"Turnaround time (TAT) is the completion time minus the arrival time.",
|
|
982
982
|
"We calculate it for each job after simulating the schedule."
|
|
983
983
|
])
|
|
984
984
|
)
|
|
985
985
|
|
|
986
986
|
explanation.add_element(
|
|
987
|
-
|
|
987
|
+
ca.Paragraph([
|
|
988
988
|
"For each job:"
|
|
989
989
|
] + [
|
|
990
990
|
f"Job{job_id}_TAT = "
|
|
@@ -996,7 +996,7 @@ class MLFQQuestion(ProcessQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
996
996
|
)
|
|
997
997
|
|
|
998
998
|
explanation.add_element(
|
|
999
|
-
|
|
999
|
+
ca.Table(
|
|
1000
1000
|
headers=["Time", "Events"],
|
|
1001
1001
|
data=[
|
|
1002
1002
|
[f"{t:0.{self.ROUNDING_DIGITS}f}s"] + ['\n'.join(events)]
|
|
@@ -1017,7 +1017,7 @@ class MLFQQuestion(ProcessQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
1017
1017
|
)
|
|
1018
1018
|
|
|
1019
1019
|
explanation.add_element(
|
|
1020
|
-
|
|
1020
|
+
ca.Picture(
|
|
1021
1021
|
img_data=self.make_image(),
|
|
1022
1022
|
caption="MLFQ Scheduling Overview"
|
|
1023
1023
|
)
|
|
@@ -1025,7 +1025,7 @@ class MLFQQuestion(ProcessQuestion, TableQuestionMixin, BodyTemplatesMixin):
|
|
|
1025
1025
|
|
|
1026
1026
|
return explanation, []
|
|
1027
1027
|
|
|
1028
|
-
def get_explanation(self, **kwargs) ->
|
|
1028
|
+
def get_explanation(self, **kwargs) -> ca.Section:
|
|
1029
1029
|
explanation, _ = self._get_explanation(**kwargs)
|
|
1030
1030
|
return explanation
|
|
1031
1031
|
|