WeBWorK Problems

Help needed fixing local problem

Help needed fixing local problem

by Sean Fitzpatrick -
Number of replies: 5

We have some local problems that were written by summer students a couple of years ago.

One is not working properly. My problem authoring skills are minimal at the best of times, and this one appears to use a custom answer checker (possibly in Perl?).

The question asks for a non-diagonal matrix with a given determinant. If done correctly, it is marked as such. If a student enters a diagonal matrix with the requested determinant, it gets marked wrong. (Good, though it's too bad they didn't put in a feedback message pointing out what's wrong.)

The main problem: anything with the wrong determinant gets marked correct! So the only way you get this wrong is if you have a diagonal matrix with the correct determinant. Is there an easy way to modify the answer checker to verify the determinant? Here's the code:

DOCUMENT();


loadMacros(

  "PGstandard.pl",

  "MathObjects.pl",

  # Used to provide contextual help for how to type answers.

  "AnswerFormatHelp.pl",

  # Provides greater control over the layout of the problem.

  "PGML.pl",

  # Used for course-specific initializations.

  "PGcourse.pl",

);


TEXT(beginproblem());



#############################

#  Setup


# Used for handling matrix problems.

Context("Matrix");


#-ULETH-#

# ans : the random value of the determinant for the question.

# M : A solution matrix used to verify a student answer or act as a solution set.


$ans = non_zero_random(-10,10,1);

$M = Matrix([

[$ans,6,1,9],

[0,1,3,4],

[0,0,1,6],

[0,0,0,1],

]);

#-ENDULETH-#




#############################

#  Main text


#-ULETH-#


BEGIN_PGML

###Enter a non-diagonal 4x4 matrix with a determinant of [$ans].


[`A =`] [@ $M->ans_array(5) @]* [@ AnswerFormatHelp("matrices") @]*


END_PGML

#-ENDULETH-#



#-ULETH-#

$showPartialCorrectAnswers = 0;

ANS( $M->cmp(

     checker => sub {

       my ($M,$student,$ansHash) = @_; 

       my ($sdet)=$student->det();

       return ($sdet != $ans or $student->is_symmetric ? 0 : 1);

       }

));

#-ENDULETH-#



#############################

#  Solution


#-ULETH-#


BEGIN_PGML_SOLUTION

SOLUTION:


One possible solution is [`A = [$M]`].


We know that the determinant of any upper triangular matrix is the product of the element along the diagonal. So by placing [`[$ans]`] anywhere on the diagonal and filling the upper half of the matrix with any numbers (since they do not effect the determinant).


END_PGML_SOLUTION


COMMENT('

    Randomization provides 19 different possible versions of this question.<BR>

    Includes a solution set.<BR>

    Recommended Settings:<BR>

    - Weight: 2<BR>

    - Max attempts: Unlimited<BR>

    - Show me another: -2<BR>

    - Rerandomize after: Default<BR>

    Made from a ULETH template.<BR>

    ');

#-ENDULETH-#


ENDDOCUMENT();

In reply to Sean Fitzpatrick

Re: Help needed fixing local problem

by Alex Jordan -

The instructions are:

###Enter a non-diagonal 4x4 matrix with a determinant of [$ans].

Those three octothorpes make that line an h3 in HTML output. That seems inappropriate, and I might suggest removing them. But anyway, the determinant is supposed to equal $ans. But in the answer checker there is:

return ($sdet != $ans or $student->is_symmetric ? 0 : 1);

I see a few things with this. One, it appears to be using is_symmetric as a proxy for being diagonal, but that is going block some symmetric non-diagonal answers form being accepted. Also I'm think the trinary logic operator A?B:C has higher precedence than "or", so you'd want it like:

return (($sdet != $ans or $student->is_symmetric)  ? 0 : 1);

It seems unnecessary to use the ?: operator. It could be:

return (($sdet == $ans) and not($student->is_symmetric));

But still, it's checking for symmetry, not diagonalness. I don't see a method for quickly checking if a matrix is diagonal. You could write a nested loop to check every element and ensure there are 0s off the diagonal. Something like:

my $isDiagonal = 1;
for my $i (1..4) {
  for my $j (1..4) {
    $isDiagonal = 0 if (($i != $j) and ($student->element($i,$j) != 0));
    last() unless $isDiagonal;
  };
  last() unless $isDiagonal;
}

return (!$isDiagonal and ($sdet == $ans));


This is untested. Might have typos and/or logical errors in my thinking as I type.


In reply to Alex Jordan

Re: Help needed fixing local problem

by Sean Fitzpatrick -
Thanks to you both for the quick help! The trouble with hiring summer students: some of them do a great job, and some of them leave behind buggy code that you don't discover until years later.
In reply to Sean Fitzpatrick

Re: Help needed fixing local problem

by Nathan Wallach -
You are welcome. Short term student programmers may be more likely to write buggy code, but even those with experience make mistakes. Doing some QA helps, code review helps more - but both are not always sufficient.

If the code was subjected to more use - bugs would probably get discovered and fixed sooner... Contributing problems to the OPL is one way to get them more widely used and thus tested and debugged. (Though I should not be the one to say this as my university is not rushing to share the locally developed content, at least not yet.)

I noticed that the solution text is also not totally accurate... You want to state that the rest of the diagonal entries should be set to 1.