WeBWorK Problems

Type checking in custom answer checker

Type checking in custom answer checker

by John Jones -
Number of replies: 1
I am trying to improve the OPL problem Library/274/Exact/prob3.pg . The current version (now) works properly, except for one small issue. It has the student turn a differential equation into one with differentials, and the last answer blank asks for either a solution or "not exact". When the correct answer is "not exact", then
  • if the student enters the right answer, all is well
  • if a student enters a function, the problem gives a message saying in essence that a number is expected but it was given a formula instead

I want to suppress this last message. I am not sure how to do that. For convenience, I will paste the problem below.


DOCUMENT() ; # This should be the first executable line in the problem.


TEXT(beginproblem()) ;
$showPartialCorrectAnswers = 0;


$a= non_zero_random(-4,4);
$b= non_zero_random(-4,4);
$z = random (1,3);
$k = non_zero_random(-4,4);
if ($k==$b){$c = $b}
elsif ($z==3) {$c = $b-$k}
else {$c = $b}

$d = non_zero_random(-4,4); # this is exact if $b==$c
$n = random(1,4);
$m = random(2,4);
$m1= $m+1;

Context()->strings->add("not exact" =>{"not exact"});

if ($c != $b) {$Fxy = String("not exact");}
else {
$Fxy = Compute("A*(($a/$m1) x^{$m1}+${b}x y + (${d}/$n1)y^${n1})+K");

$num = nicestring([-$a, -$b], ["x^{$m}", 'y']);
$ypow = "y^{$n}";
$ypow = "y" if ($n==1);
$den = nicestring([$c, $d], ['x', $ypow]);

$mp = MultiAnswer("$a x^$m + $b y","$c x + $d y^$n", $Fxy)->with(
checker => sub {
my $correct = shift; my $student = shift; my $self = shift;
my ($F,$G,$cFxy) = @{$correct};
my ($f,$g, $fxy) = @{$student};
#$mp->setMessage(1,"The function can't be the identity");
return [0,0,0] unless $F/$G == $f/$g;
# Since M and N can be multiplied by a common function, no further check
# Now check the last part
if ($c==$b) {
if (Formula($fxy)->isConstant) {
$mp->setMessage(3,"The function cannot be constant");
return [1,1,0];
return [1,1,1] if $cFxy == $fxy;
return [1,1,0];

Use the "mixed partials" check to see if the following differential equation
is exact.
If it is exact find a function \(F(x,y)\) whose differential,
\(dF(x,y) \) gives the differential equation. That is, level curves \(F(x,y) = C\) are solutions to the differential equation:
\[ \frac{dy}{dx} = \frac{ $num }{ $den }\]
First rewrite as
\[ M(x,y) \, dx + N(x,y) \, dy = 0 \]
\(M(x,y)= \) \{$mp->ans_rule(30) \} ,
and \(N(x,y)= \) \{$mp->ans_rule(30) \}.
If the equation is not exact, enter $BITALIC not exact, $EITALIC otherwise enter in \(F(x,y) \) as
the solution of the differential equation here
\{ $mp->ans_rule(45) \} \(= C \).


#if ($c==$b-$k) {ANS(str_cmp($Fxy ))}
#else {
# ANS(pc_evaluator([[fun_cmp("C", vars=>["x", "y"], params=>['A','C']), 0, 'This answer cannot be constant'],
# [fun_cmp($Fxy,vars=>["x", "y"], params=>['A', 'C'] ), 1]]) )


In reply to John Jones

Re: Type checking in custom answer checker

by Davide Cervone -
For a String object, if the other answers could be something other than a number, you have to tell MathObjects what type that is so that if produces the correct error messages. The usual way to do that is to add a typeMatch option to the cmp() call, as in
But with the MultiAnswer object, you don't make the individual cmp() calls yourself, so you can't add that option.

In your case, you could handle it by overriding the default typeMatch option for the String comparisons by adding

Context()->{cmpDefaults}{String} = {typeMatch=>Formula("x")};
to your Context setup code. This will make all string comparisons be done with messages appropriate for formulas rather than numbers.

If you have more than one string answer and need a different type for each, then you would have to be more sophisticated about it. I don't want to complicate this answer by writing that out as well unless you really need it. If so, let me know and I'll write that up, too.