WeBWorK Problems

Custom answer checking for matrix input

Custom answer checking for matrix input

by Keir Lockridge -
Number of replies: 6

In PGML, I like the way it looks when you do something like this:

BEGIN_PGML

[________]*{Matrix([[1],[1],[1]])}

END_PGML

I would like to do exactly this but with a custom answer checker. My goal is to have the input interface look the way it does with the line above, but I want to check the student inputs $s1, $s2, $s3 and see if they satisfy an equation like x + 2y + z = 3. I included a minimal version of my attempt below. The problem is that when I try to use a custom answer checker, I only get one box instead of three boxes nicely stacked between brackets.

DOCUMENT();

loadMacros(
  "PGstandard.pl",
  "MathObjects.pl",
  "PGcourse.pl",
  "contextFraction.pl",
  "PGML.pl",
  "MathObjects.pl",
  "parserPopUp.pl",
);

TEXT(beginproblem());

$showPartialCorrectAnswers = 1;

Context("Matrix");

$a = random(-9, 9);
$b = random(-9, 9);
$c = random(-9, 9);

$cmp2 = Matrix([[1],[1],[1]])->cmp(
   showCoordinateHints => 0,      
   checker => sub {
     my ($correct,$student,$ansHash) = @_;
     my @s = @{$student};
     my $s0 = Matrix($s[0]);
     return ($s0[0][1] + $a*$s0[1][0] + $b*$s0[2][0] == $c ? 1 : 0); 
   }
);

# Below, I want the line [________]*{$cmp2} to display like the line after it does.

BEGIN_PGML

[________]*{$cmp2}

[________]*{Matrix([[1],[1],[1]])}

END_PGML

ENDDOCUMENT();

In reply to Keir Lockridge

Re: Custom answer checking for matrix input

by Nathan Wallach -
I don't know whether this can be done in PGML, as if the approach you tried is not working, then apparently the "*" does not work once the custom grader is attached. Davide Cervone may be able to provide help about whether a solution exists inside PGML.

However, with the older PG it should work properly. Try something like

$ansM = Matrix( [ [1],[1],[1] ] );

BEGIN_TEXT
\{ $ansM->ans_array(5) \}
END_TEXT

ANS( $ansM->cmp(
showCoordinateHints => 0,
checker => sub {
my ($correct,$student,$ansHash) = @_;
my @s = @{$student};
my $s0 = Matrix($s[0]);
return ($s0[0][1] + $a*$s0[1][0] + $b*$s0[2][0] == $c ? 1 : 0);
}
);

I did not carefully check the sample code above, and there may be minor errors, but I do have things like this working in problems I coded.
In reply to Nathan Wallach

Re: Custom answer checking for matrix input

by Keir Lockridge -
I can't get it to work. I tried the code below (and see further below for a version that avoids the warnings but doesn't check correctly). I get a WW Warning after I input and check an answer:

Please inform your instructor that an error occurred while checking your answer at [PG]/lib/Value/AnswerChecker.pm line 252

One issue I run into a lot is I'm not sure how to go about debugging. Is there, for example, a way to get more state information about the problem (like printing the value of $s0$ somewhere, for example)?

DOCUMENT();

loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"PGcourse.pl",
"contextFraction.pl",
"PGML.pl",
"MathObjects.pl",
"parserPopUp.pl",
"parserMultiAnswer.pl",
);

TEXT(beginproblem());

$showPartialCorrectAnswers = 1;

Context("Matrix");

$a = random(-9, 9);
$b = random(-9, 9);
$c = random(-9, 9);

$ansM = Matrix( [ [1],[1],[1] ] );

BEGIN_TEXT
a = $a, b = $b, c = $c

$BR
($c, 0, 0) should be a solution.
$BR

\{ $ansM->ans_array(5) \}

END_TEXT

ANS( $ansM->cmp(
showCoordinateHints => 0,
checker => sub {
my ($correct,$student,$ansHash) = @_;
my @s = @{$student};
my $s0 = Matrix($s[0]);
return ($s0[0][1] + $a*$s0[1][0] + $b*$s0[2][0] == $c ? 1 : 0);
}
));

ENDDOCUMENT();

This version gives no warnings but doesn't check correctly (I put in what should be a solution and it says it is incorrect):

DOCUMENT();

loadMacros(
  "PGstandard.pl",
  "MathObjects.pl",
  "PGcourse.pl",
  "contextFraction.pl",
  "PGML.pl",
  "MathObjects.pl",
  "parserPopUp.pl",
  "parserMultiAnswer.pl",
);

TEXT(beginproblem());

$showPartialCorrectAnswers = 1;

Context("Matrix");

$a = random(-9, 9);
$b = random(-9, 9);
$c = random(-9, 9);

$ansM = Matrix( [ [1],[1],[1] ] );

BEGIN_TEXT
a = $a, b = $b, c = $c

$BR
($c, 0, 0) should be a solution.
$BR

\{ $ansM->ans_array(5) \}

END_TEXT
ANS( $ansM->cmp(
  showCoordinateHints => 0,
    checker => sub {
      my ($correct,$student,$ansHash) = @_;
      my $M = Matrix($student);
      return ($M[0][1] + $a*$M[1][0] + $b*$M[2][0] == $c ? 1 : 0);
    }
));

ENDDOCUMENT();
In reply to Keir Lockridge

Re: Custom answer checking for matrix input

by Nathan Wallach -
Sorry - I did not read your grader code before, just copied what you had. I was focused on how you could get the nice "array" of input boxes on screen and use a custom grader, as that was the question you originally asked.

I think $student should already just be a Matrix object inside the checker, so you should not need to play with it.

To access elements of the matrix I think you need to use the syntax $student->element(2,1). I don't think the MathObject matrices will allow you to extract elements the way you did.

See:  https://webwork.maa.org/wiki/Matrix_(MathObject_Class)#Methods

You can use the Perl "warn" function to print warnings you will see below the problem. That is one of the standard manners of getting some debugging information where you can see it. Ex: "warn $student;" should probably work.

In reply to Nathan Wallach

Re: Custom answer checking for matrix input

by Keir Lockridge -
Perl "warn" is probably the most useful thing I've learned this week!

Using ->element(...) solved the problem, though I didn't at first realize that this function starts indexing rows/cols at 1 rather than zero.

Thanks so much for all your help!!!
In reply to Keir Lockridge

Re: Custom answer checking for matrix input

by Glenn Rice -
You do not need to call "my $M = Matrix($student)" as $student is already a Matrix MathObject.
To make this work change your grader to:
        checker => sub {
            my ($correct,$student,$ansHash) = @_;
            return ($student->extract(1, 1) + $a*$student->extract(2, 1) + $b*$student->extract(3, 1) == $c ? 1 : 0);
        }

However, you should note that the way that you have this set up the correct answer will be displayed as the matrix [[1],[1],[1]], and not the correct answer your grader is grading for.  You should set $ansM to be an actual correct answer.

To make this work in PGML use:

DOCUMENT();

loadMacros(
    "PGstandard.pl",
    "MathObjects.pl",
    "PGcourse.pl",
    "contextFraction.pl",
    "PGML.pl",
    "parserPopUp.pl",
    "parserMultiAnswer.pl",
);

TEXT(beginproblem());

$showPartialCorrectAnswers = 1;

Context("Matrix");

$a = random(-9, 9);
$b = random(-9, 9);
$c = random(-9, 9);

$ansM = Matrix( [ [1],[1],[1] ] );

BEGIN_PGML
[`a = [$a], b = [$b], c = [$c]`]

[`([$c], 0, 0)`] should be a solution.

[@ $ansM->ans_array(5) @]*

END_PGML
ANS($ansM->cmp(
        showCoordinateHints => 0,
        checker => sub {
            my ($correct,$student,$ansHash) = @_;
            return ($student->extract(1, 1) + $a*$student->extract(2, 1) + $b*$student->extract(3, 1) == $c ? 1 : 0);
        }
    ));

ENDDOCUMENT();

Edit:  As you saw in your last post, element works the same as extract.  Internally element calls extract.