WeBWorK Problems

Changing MultiAnswer to List with custom checking

Changing MultiAnswer to List with custom checking

by Sean Fitzpatrick -
Number of replies: 4

Attached is the problem P3subspaceBasis.pg, in the OPL at Library/NAU/setLinearAlgebra/P3subspaceBasis.pg.

I'm attempting to edit it so that it works as both a WeBWorK problem, and as a textbook problem (via PreTeXt). It works all right as-is, but it does not look great in print. In a book, you would like to just have the statement of the problem ("Find a basis of the subspace..."). You generally do not want to see the extra line with p(x) = ________  q(x) = __________

There's a mechanism in PreTeXt wherein a paragraph that contains only an answer blank is ignored, unless the WeBWorK problem is activated. So my goal is to have a single answer blank accepting a list for the answer, rather than a pair of blanks using MultiAnswer.

My version below works if the answer is the obvious one (for the seed in the problem editor, I get the basis {x, x^2+5}), and it works in either order. But if I replace one of the basis vectors by a multiple of that vector, the answer is marked wrong. This doesn't happen using the existing MultiAnswer: it will accept both x and 2x.

Is there a way to replace MultiAnswer with List and preserve the custom checking present in this problem? Here is my attempt at updating the problem. (I also converted from PG to PGML.)

## DBsubject(Linear algebra)
## DBchapter(Abstract vector spaces)
## DBsection(Basis and dimension)
## Date(10/11/2013)
## Institution(NAU)
## Author(Nandor Sieben)
## Level(2)
## MO(1)
## KEYWORDS('linear algebra','span')

DOCUMENT();
loadMacros(
  "PGstandard.pl",
  "MathObjects.pl",
  "AnswerFormatHelp.pl",
  "MatrixReduce.pl",
  "rank.pl",
  "PGcourse.pl",
  "PGML.pl",
  "PCCmacros.pl"
);
$showPartialCorrectAnswers = 1;

$l=non_zero_random(-9,9,1);
$p1=Formula("2*$l-1+x^2")->reduce;
$p2=Formula("x")->reduce;

$basis = List($p1, $p2)->with(
singleResult => 1,
checker => sub {
my ( $correct, $student, $self ) = @_;
my ($s1,$s2) = @{$student};
my @c = @{$correct};
my $s1D=$s1->D('x');
my $s2D=$s2->D('x');
my $s1DD=$s1D->D('x');
my $s2DD=$s2D->D('x');
if ($s1D->eval(x=>$l) != $s1->eval(x=>1)) {
  $self->setMessage(1,"Not in the subspace.");
  return 0 

if ($s2D->eval(x=>$l) != $s2->eval(x=>1)) {
  $self->setMessage(2,"Not in the subspace.");
  return 0 
}
my $s1DDD=$s1DD->D('x');
my $s2DDD=$s2DD->D('x');
if ($s1DDD != Formula("0")) {
  $self->setMessage(1,"Not in the subspace.");
  return 0 
}
if ($s2DDD != Formula("0")) {
  $self->setMessage(2,"Not in the subspace.");
  return 0 
}
my $a1=$s1->eval(x=>0);
my $b1=$s1D->eval(x=>0);
my $c1=$s1DD->eval(x=>0)/2;
my $a2=$s2->eval(x=>0);
my $b2=$s2D->eval(x=>0);
my $c2=$s2DD->eval(x=>0)/2;
if (rank(Matrix([$a1,$b1,$c1],[$a2,$b2,$c2])) ==2) {
    return 1;
}
$self->setMessage(1,"Not independent.");
$self->setMessage(2,"Not independent.");
return 0;
}
);

BEGIN_PGML

Find a basis [` \lbrace p(x), q(x) \rbrace `] for the vector space 
[`\lbrace f(x)\in P_2(\mathbb{R}) \mid f'([$l])=f(1) \rbrace`] 
where [`P_2(\mathbb{R})`] is the vector space of polynomials in [`x`] with degree less than or equal to 2.

    [__________]{$basis}

[@KeyboardInstructions('Enter your answer as a comma-separated list of polynomials.')@]**

END_PGML

ENDDOCUMENT();


In reply to Sean Fitzpatrick

Re: Changing MultiAnswer to List with custom checking

by Andrew Parker -

So you cannot specify the answer checker for a list by using `with` as you can for a MultiAnswer. (Also, single_result is also only relevant for MultiAnswer.)

What you need here is to provide a subroutine for `list_checker` as an argument to the comparison method. (This is very similar to how we implement custom answer checkers, but lists have the additional option of processing all list items at once.)

Declare the checker subroutine as a variable, then in the PGML, call cmp and provide the list_checker argument.

Answer messages are also handled a bit differently -- the list_checker is expected to return a score (out of the total number of correct answers IN the list) and an array of messages. I have modified the checker to process several conditionals and add relevant error messages if they fail. Once all of the zero-credit checks are complete, return 0 if we failed any of them (and include the messages). Then we check the rank and give full marks (2 out of 2), and finally we must have two linearly dependent polynomials, so give that message and half-credit (1 out of 2).

I have attached a cleaner version of what I originally pasted here. I also removed the dependency on rank.pl -- there's only one function in there, and I would argue that it should get merged into MatrixReduce.pl, since that one function already depends on MatrixReduce also being loaded. 

In reply to Andrew Parker

Re: Changing MultiAnswer to List with custom checking

by Sean Fitzpatrick -
This is perfect, thanks! (I meant to say so earlier but I was at my 5 post limit.)
I've got a few more on my list of problems to adapt that are similar to this and I think I see how to proceed with those myself.
In reply to Sean Fitzpatrick

Re: Changing MultiAnswer to List with custom checking

by Andrew Parker -

I found another oversight in this answer checker conversion...

If a student does not enter two polynomials, there is an error. We must check that the student actually supplied two polynomials:

return (0, "Your answer should consist of two polynomials separated by a comma") unless @$student == 2;

This should be performed before attempting any computations with $s1 or $s2...

In reply to Andrew Parker

Re: Changing MultiAnswer to List with custom checking

by Sean Fitzpatrick -

Oh yes, good point! Otherwise there is a "not an answer hash" error.

Looks like it needs to go just above the "my($s1,$s2)=@{student};" line. Thanks.