Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
cce63f6e
Commit
cce63f6e
authored
May 07, 2014
by
Jason Bau
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Fix randomization bug for multiple questions per problem"
This reverts commit
0c583d9e
.
parent
f4837d91
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
25 additions
and
103 deletions
+25
-103
common/lib/capa/capa/capa_problem.py
+2
-5
common/lib/capa/capa/responsetypes.py
+19
-26
common/lib/capa/capa/tests/test_answer_pool.py
+4
-72
No files found.
common/lib/capa/capa/capa_problem.py
View file @
cce63f6e
...
@@ -179,12 +179,9 @@ class LoncapaProblem(object):
...
@@ -179,12 +179,9 @@ class LoncapaProblem(object):
self
.
inputs
=
{}
self
.
inputs
=
{}
# Run response late_transforms last (see MultipleChoiceResponse)
# Run response late_transforms last (see MultipleChoiceResponse)
# Sort the responses to be in *_1 *_2 ... order.
for
response
in
self
.
responders
.
values
():
responses
=
self
.
responders
.
values
()
responses
=
sorted
(
responses
,
key
=
lambda
resp
:
int
(
resp
.
id
[
resp
.
id
.
rindex
(
'_'
)
+
1
:])
)
for
response
in
responses
:
if
hasattr
(
response
,
'late_transforms'
):
if
hasattr
(
response
,
'late_transforms'
):
response
.
late_transforms
(
self
)
response
.
late_transforms
()
self
.
extracted_tree
=
self
.
_extract_html
(
self
.
tree
)
self
.
extracted_tree
=
self
.
_extract_html
(
self
.
tree
)
...
...
common/lib/capa/capa/responsetypes.py
View file @
cce63f6e
...
@@ -776,14 +776,13 @@ class MultipleChoiceResponse(LoncapaResponse):
...
@@ -776,14 +776,13 @@ class MultipleChoiceResponse(LoncapaResponse):
else
:
else
:
choice
.
set
(
"name"
,
name
)
choice
.
set
(
"name"
,
name
)
def
late_transforms
(
self
,
problem
):
def
late_transforms
(
self
):
"""
"""Rearrangements run late in the __init__ process.
Rearrangements run late in the __init__ process.
Cannot do these at response init time, as not enough
Cannot do these at response init time, as not enough
other stuff exists at that time.
other stuff exists at that time.
"""
"""
self
.
do_shuffle
(
self
.
xml
)
self
.
do_shuffle
(
self
.
xml
)
self
.
do_answer_pool
(
self
.
xml
,
problem
)
self
.
do_answer_pool
(
self
.
xml
)
def
get_score
(
self
,
student_answers
):
def
get_score
(
self
,
student_answers
):
"""
"""
...
@@ -883,21 +882,7 @@ class MultipleChoiceResponse(LoncapaResponse):
...
@@ -883,21 +882,7 @@ class MultipleChoiceResponse(LoncapaResponse):
rng
.
shuffle
(
middle
)
rng
.
shuffle
(
middle
)
return
head
+
middle
+
tail
return
head
+
middle
+
tail
def
get_rng
(
self
,
problem
):
def
do_answer_pool
(
self
,
tree
):
"""
Get the random number generator to be shared by responses
off the problem, creating it on the problem if needed.
"""
# Multiple answer-pool questions share one rng stored on the problem.
# If each question got its own rng, the structure
# could appear predictable to the student, e.g. (c) keeps being the
# correct choice.
# TODO: could make the sharing some sort of authoring option
if
not
hasattr
(
problem
,
'shared_rng'
):
problem
.
shared_rng
=
random
.
Random
(
self
.
context
[
'seed'
])
return
problem
.
shared_rng
def
do_answer_pool
(
self
,
tree
,
problem
):
"""
"""
Implements the answer-pool subsetting operation in-place on the tree.
Implements the answer-pool subsetting operation in-place on the tree.
Allows for problem questions with a pool of answers, from which answer options shown to the student
Allows for problem questions with a pool of answers, from which answer options shown to the student
...
@@ -909,7 +894,15 @@ class MultipleChoiceResponse(LoncapaResponse):
...
@@ -909,7 +894,15 @@ class MultipleChoiceResponse(LoncapaResponse):
Calling this a second time does nothing.
Calling this a second time does nothing.
"""
"""
choicegroups
=
tree
.
xpath
(
"choicegroup[@answer-pool]"
)
choicegroups
=
tree
.
xpath
(
"choicegroup[@answer-pool]"
)
rng
=
self
.
get_rng
(
problem
)
# Uses self.seed -- but want to randomize every time reaches this problem,
# so problem's "randomization" should be set to "always"
rnd
=
random
.
Random
(
self
.
context
[
'seed'
])
# TODO: currently, each choicegroup uses the seed from the problem.
# This has the unfortunate effect of making choicegroups look similar
# when we have many in one problem. Could perturb the rnd a little
# per choicegroup so they look different.
for
choicegroup
in
choicegroups
:
for
choicegroup
in
choicegroups
:
num_str
=
choicegroup
.
get
(
'answer-pool'
)
num_str
=
choicegroup
.
get
(
'answer-pool'
)
...
@@ -931,7 +924,7 @@ class MultipleChoiceResponse(LoncapaResponse):
...
@@ -931,7 +924,7 @@ class MultipleChoiceResponse(LoncapaResponse):
choicegroup
.
remove
(
choice
)
choicegroup
.
remove
(
choice
)
# Sample from the answer pool to get the subset choices and solution id
# Sample from the answer pool to get the subset choices and solution id
(
solution_id
,
subset_choices
)
=
self
.
sample_from_answer_pool
(
choices_list
,
rn
g
,
num_choices
)
(
solution_id
,
subset_choices
)
=
self
.
sample_from_answer_pool
(
choices_list
,
rn
d
,
num_choices
)
# Add back in randomly selected choices
# Add back in randomly selected choices
for
choice
in
subset_choices
:
for
choice
in
subset_choices
:
...
@@ -947,7 +940,7 @@ class MultipleChoiceResponse(LoncapaResponse):
...
@@ -947,7 +940,7 @@ class MultipleChoiceResponse(LoncapaResponse):
if
solution
.
get
(
'explanation-id'
)
!=
solution_id
:
if
solution
.
get
(
'explanation-id'
)
!=
solution_id
:
solutionset
.
remove
(
solution
)
solutionset
.
remove
(
solution
)
def
sample_from_answer_pool
(
self
,
choices
,
rn
g
,
num_pool
):
def
sample_from_answer_pool
(
self
,
choices
,
rn
d
,
num_pool
):
"""
"""
Takes in:
Takes in:
1. list of choices
1. list of choices
...
@@ -980,15 +973,15 @@ class MultipleChoiceResponse(LoncapaResponse):
...
@@ -980,15 +973,15 @@ class MultipleChoiceResponse(LoncapaResponse):
num_incorrect
=
min
(
num_incorrect
,
len
(
incorrect_choices
))
num_incorrect
=
min
(
num_incorrect
,
len
(
incorrect_choices
))
# Select the one correct choice
# Select the one correct choice
index
=
rn
g
.
randint
(
0
,
len
(
correct_choices
)
-
1
)
index
=
rn
d
.
randint
(
0
,
len
(
correct_choices
)
-
1
)
correct_choice
=
correct_choices
[
index
]
correct_choice
=
correct_choices
[
index
]
solution_id
=
correct_choice
.
get
(
'explanation-id'
)
solution_id
=
correct_choice
.
get
(
'explanation-id'
)
# Put together the result, pushing most of the work onto rn
g
.shuffle()
# Put together the result, pushing most of the work onto rn
d
.shuffle()
subset_choices
=
[
correct_choice
]
subset_choices
=
[
correct_choice
]
rn
g
.
shuffle
(
incorrect_choices
)
rn
d
.
shuffle
(
incorrect_choices
)
subset_choices
+=
incorrect_choices
[:
num_incorrect
]
subset_choices
+=
incorrect_choices
[:
num_incorrect
]
rn
g
.
shuffle
(
subset_choices
)
rn
d
.
shuffle
(
subset_choices
)
return
(
solution_id
,
subset_choices
)
return
(
solution_id
,
subset_choices
)
...
...
common/lib/capa/capa/tests/test_answer_pool.py
View file @
cce63f6e
...
@@ -359,13 +359,12 @@ class CapaAnswerPoolTest(unittest.TestCase):
...
@@ -359,13 +359,12 @@ class CapaAnswerPoolTest(unittest.TestCase):
"""
)
"""
)
problem
=
new_loncapa_problem
(
xml_str
)
problem
=
new_loncapa_problem
(
xml_str
,
seed
=
723
)
the_html
=
problem
.
get_html
()
the_html
=
problem
.
get_html
()
print
the_html
print
the_html
str1
=
r"<div>.*\[.*'wrong-3'.*'correct-2'.*'wrong-2'.*'wrong-4'.*\].*</div>"
str1
=
r"<div>.*\[.*'wrong-3'.*'correct-2'.*'wrong-2'.*'wrong-4'.*\].*</div>"
str2
=
r"<div>.*\[.*'wrong-2'.*'wrong-1'.*'correct-2'.*\].*</div>"
# rng shared
str2
=
r"<div>.*\[.*'correct-2'.*'wrong-2'.*'wrong-3'.*\].*</div>"
# str2 = r"<div>.*\[.*'correct-2'.*'wrong-2'.*'wrong-3'.*\].*</div>" # rng independent
str3
=
r"<div>\{.*'1_solution_2'.*\}</div>"
str3
=
r"<div>\{.*'1_solution_2'.*\}</div>"
str4
=
r"<div>\{.*'1_solution_4'.*\}</div>"
str4
=
r"<div>\{.*'1_solution_4'.*\}</div>"
...
@@ -448,12 +447,11 @@ class CapaAnswerPoolTest(unittest.TestCase):
...
@@ -448,12 +447,11 @@ class CapaAnswerPoolTest(unittest.TestCase):
problem
=
new_loncapa_problem
(
xml_str
,
seed
=
9
)
problem
=
new_loncapa_problem
(
xml_str
,
seed
=
9
)
the_html
=
problem
.
get_html
()
the_html
=
problem
.
get_html
()
print
the_html
str1
=
r"<div>.*\[.*'wrong-4'.*'wrong-3'.*'correct-1'.*\].*</div>"
str1
=
r"<div>.*\[.*'wrong-4'.*'wrong-3'.*'correct-1'.*\].*</div>"
str2
=
r"<div>.*\[.*'wrong-
2'.*'wrong-3'.*'wrong-4'.*'correct-2
'.*\].*</div>"
str2
=
r"<div>.*\[.*'wrong-
1'.*'wrong-4'.*'wrong-3'.*'correct-1
'.*\].*</div>"
str3
=
r"<div>\{.*'1_solution_1'.*\}</div>"
str3
=
r"<div>\{.*'1_solution_1'.*\}</div>"
str4
=
r"<div>\{.*'1_solution_
4
'.*\}</div>"
str4
=
r"<div>\{.*'1_solution_
3
'.*\}</div>"
self
.
assertRegexpMatches
(
the_html
,
str1
)
self
.
assertRegexpMatches
(
the_html
,
str1
)
self
.
assertRegexpMatches
(
the_html
,
str2
)
self
.
assertRegexpMatches
(
the_html
,
str2
)
...
@@ -465,72 +463,6 @@ class CapaAnswerPoolTest(unittest.TestCase):
...
@@ -465,72 +463,6 @@ class CapaAnswerPoolTest(unittest.TestCase):
self
.
assertRegexpMatches
(
without_new_lines
,
str1
+
r".*"
+
str2
)
self
.
assertRegexpMatches
(
without_new_lines
,
str1
+
r".*"
+
str2
)
self
.
assertRegexpMatches
(
without_new_lines
,
str3
+
r".*"
+
str4
)
self
.
assertRegexpMatches
(
without_new_lines
,
str3
+
r".*"
+
str4
)
def
test_answer_pool_random_consistent
(
self
):
"""
The point of this test is to make sure that the exact randomization
per seed does not change.
"""
xml_str
=
textwrap
.
dedent
(
"""
<problem>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice" answer-pool="2">
<choice correct="false">wrong-1</choice>
<choice correct="false">wrong-2</choice>
<choice correct="true">correct-1</choice>
<choice correct="false">wrong-3</choice>
<choice correct="false">wrong-4</choice>
<choice correct="true">correct-2</choice>
<choice correct="true">correct-3</choice>
</choicegroup>
</multiplechoiceresponse>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice" answer-pool="3">
<choice correct="false">wrong-1</choice>
<choice correct="false">wrong-2</choice>
<choice correct="true">correct-1</choice>
<choice correct="false">wrong-3</choice>
<choice correct="false">wrong-4</choice>
<choice correct="true">correct-2</choice>
<choice correct="true">correct-3</choice>
</choicegroup>
</multiplechoiceresponse>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice" answer-pool="2">
<choice correct="false">wrong-1</choice>
<choice correct="false">wrong-2</choice>
<choice correct="true">correct-1</choice>
<choice correct="false">wrong-3</choice>
<choice correct="false">wrong-4</choice>
<choice correct="true">correct-2</choice>
<choice correct="true">correct-3</choice>
</choicegroup>
</multiplechoiceresponse>
<multiplechoiceresponse>
<choicegroup type="MultipleChoice" answer-pool="3">
<choice correct="false">wrong-1</choice>
<choice correct="false">wrong-2</choice>
<choice correct="true">correct-1</choice>
<choice correct="false">wrong-3</choice>
<choice correct="false">wrong-4</choice>
<choice correct="true">correct-2</choice>
<choice correct="true">correct-3</choice>
</choicegroup>
</multiplechoiceresponse>
</problem>
"""
)
problem
=
new_loncapa_problem
(
xml_str
)
the_html
=
problem
.
get_html
()
str1
=
(
r"<div>.*\[.*'correct-2'.*'wrong-2'.*\].*</div>.*"
+
r"<div>.*\[.*'wrong-1'.*'correct-2'.*'wrong-4'.*\].*</div>.*"
+
r"<div>.*\[.*'correct-1'.*'wrong-4'.*\].*</div>.*"
+
r"<div>.*\[.*'wrong-1'.*'wrong-2'.*'correct-1'.*\].*</div>"
)
without_new_lines
=
the_html
.
replace
(
"
\n
"
,
""
)
self
.
assertRegexpMatches
(
without_new_lines
,
str1
)
def
test_answer_pool_and_no_answer_pool
(
self
):
def
test_answer_pool_and_no_answer_pool
(
self
):
xml_str
=
textwrap
.
dedent
(
"""
xml_str
=
textwrap
.
dedent
(
"""
<problem>
<problem>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment