What if all entries are filled in but all are correct? Should that give partial credit?
Currently it does not. (You can get entry hints for vectors and points, but not matrices). But you can certainly arrange for it with a custom checker or a post-filter.
Here is an example that uses the post-filter approach (for reasons I'll explain below).
sub MatrixPartialCredit {
my $N = shift; # number of entries that must be right for partial credit
return sub {
my $ans = shift; $ans->{_filter_name} = "Matrix Partial Credit";
my $correct = $ans->{correct_value};
my $student = $ans->{student_value};
if ($ans->{score} < 1 && defined($correct) &&
defined($student) && $student->class eq "Matrix") {
my @c = map {@$_} ($correct->value); # flatten matrix
my @s = map {@$_} ($student->value); # flatten matrix
my $score = 0; my $n = @c;
foreach my $i (0..$#c) {$score ++ if $c[$i] == $s[$i]}
$ans->score($score/$n) if $score >= $N;
}
return $ans;
}
}
Context("Matrix");
$M = Matrix([1,2],[3,4]);
BEGIN_TEXT
\{$M->ans_array\}
END_TEXT
ANS($M->cmp->withPostFilter(MatrixPartialCredit(3)));
Here, the MatrixPartialCredit function takes an argument that is the number of entries that must be correct and returns a post filter that checks that the student has at least that many correct. The filter is passed an AnswerHash object, and it gets the correct and student answers from that. It checks that the score isn't 100 percent already (score = 1), and that the correct and student answers are actually valid (if the student has a syntax error, for example, there will be no
$ans->{student_value}
, or if not all the entries are filled,
$student
will not be a Matrix object (it will either be empty or a Real that is the top-left entry).
If both are valid, then we get an array of all the entries of the matrix ($M->value
returns an array of references to arrays, where the references are to arrays that are the rows of the matrix; the entries of the rows are Real MathObjects). We then compare the correct and student arrays entry by entry (and since these are Real objects, they will use the fuzzy checks controlled by the tolerance
and tolType
context flags), and add up the number of entries that are equal. If enough of them are equal, then we adjust the score to be the proper percentage. Finally, we return the AnswerHash.
You could put the MatrixPartialCredit()
filter in a separate file and load that into whatever problems need it.
You could have done this in a custom checker without having to do the checks of whether the values are defined or the correct type, but there are two reasons to use the filter approach instead, even though there is a little more checking to do.
First, you can more easily add messages like "Your entry (2,3) is incorrect" if you wanted to help the student out more. (But because there are so many entries, it might be better to make an array-like layout that has X
for incorrect entries or something like that.)
Second, it would allow you to check matrices that are not completely filled in, though you would have to work a bit to get the data about the matrix in that case, because the Matrix MathObject is not actually created when there are blank entries. So that is more sophisticated. But if you use the post-filter approach with a macro file for MatrixPartialCredit()
, then you could update that macro file at some time in the future to handle partially filled matrices, and all your existing problems would take advantage of that automatically.
Hope that does what you need.