## WeBWorK Main Forum

### Periodic solutions, AnswerHints, and Preview

by Andrew Swanson -
Number of replies: 2
I'm teaching a trigonometry course and students have difficulty with the idea of a principle solution to a trigonometric equation (especially with negative values of the sine function). I wanted to use AnswerHints to give them a message if they gave a solution of the equation that was not the principle solution (did not come from the arcsine function).

These are all in
Context("Fraction-NoDecimals");

I tried:

#The principle solution
$ans = Compute("(1/-$a)*($inv-$b)");

#all solutions based on the principle solution
$periodic=Compute("(1/-$a)*($inv-$b)")->with(period=>"2*pi/$a"); #all other solutions$alt= Compute("(1/-$a)*((pi-$inv)-$b)")->with(period=>"2*pi/$a");

ANS(
$ans->cmp()->withPostFilter( AnswerHints( [$periodic,$alt]=>"Although this is A solution, it is not the PRINCIPLE solution" ))); However, this produces the hint even when the correct answer is given (I thought AnswerHints was not supposed to check when answers were correct unless the checkCorrect option was set). For some reason, this also did not give my hint when$inv=0 and the student gave an answer that was off by 2*pi/$a. (Changing "Compute" to "Formula" fixed that). I thought the issue might be that the correct answer is not scored when the answer is previewed, so I came up with: # Answer checking #The principle solution$ans = Formula("(1/-$a)*($inv-$b)"); #all solutions based on the principle solution$periodic=Formula("(1/-$a)*($inv-$b)")->with(period=>"2*pi/$a");

#all other solutions
$alt= Compute("(1/-$a)*((pi-$inv)-$b)")->with(period=>"2*pi/$a"); ANS($ans->cmp()->withPostFilter(
sub {
my ($correct,$student,$ans) = @_; return !($ans->{isPreview})&& ($periodic==$student);
}=>"Although this is A solution, it is not the PRINCIPLE solution",
sub {
my ($correct,$student,$ans) = @_; return !($ans->{isPreview})&& ($alt==$student);
}=>"Although this is A solution, it is not the PRINCIPLE solution"
)));

This seems to work. For this question, I even prefer that they only get the hint when submitting rather than previewing.
What I'd really like to do is put the test for preview into a subroutine and pass it the incorrect answer(s) I'm testing for so it would look something like

ANS(
$ans->cmp()->withPostFilter( AnswerHints($HintNoPreview($periodic)=>"Although this is A solution, it is not the PRINCIPLE solution",$HintNoPreview($alt)=>"Although this is A solution, it is not the PRINCIPLE solution" ))); or even ANS($ans->cmp()->withPostFilter(
$HintNoPreview([$periodic,$alt])=>"Although this is A solution, it is not the PRINCIPLE solution" ))); However, my knowledge of perl seems insufficient at this point. In reply to Andrew Swanson ### Re: Periodic solutions, AnswerHints, and Preview by Davide Cervone - There are a couple of issues, here. First, AnswerHints() usually only does its testing when the student answer is incorrect, but there is an exception to this that is not well documented: it will also perform its check when the test answer (the on in the AnswerHints()) is the correct answer. This is not explicitly stated in the documentation (though it should be), but it is implicit in the example given in the file:  ANS(Vector(1,2,3)->cmp(showCoordinateHints=>0)->withPostFilter(AnswerHints( Vector(0,0,0) => "The zero vector is not a valid solution", "-<1,2,3>" => "Try the opposite direction", "<1,2,3>" => "Well done!", ["<1,1,2>","<2,2,2>","<3,3,3>"] => "Don't just guess!", sub { my ($correct,$student,$ans) = @_;
return $correct .$student == 0;
Vector(1,2,3) => [
"You have the right direction, but not length",
cmp_options => [parallel=>1],
],
0 => ["Careful, your answer should be a vector!", checkTypes => 0, replaceMessage => 1],
sub {
my ($correct,$student,$ans) = @_; return norm($correct-$student) ["Close! Keep trying.", score => .25], )));  The <1,2,3> answer is the correct answer, and to get the message for that, we need to do the check when the student answer is correct. Since your $periodic answer actually is the correct answer, the message is given when the student answer is correct. The reason you don't get this for the subroutine case is that there is no "test" answer in that case, so the special case of the test answer being the correct answer never comes into play. So you are right that using a subroutine is important in this case.

There is another problem, however, which is that the periodic property applies to MathObject Real objects, but you are using fractions, so you are actually getting a MathObject Fraction, not a Real. Unfortunately, Fractions don't support the periodic property, and so your testing is actually just doing a plain old non-periodic test. That is why you couldn't get it to work with the original Compute() code.

When you switched to Formula(), however, that changed things. Formulas are compared by comparing their values at several random inputs; but evaluating a formula that involves a fraction produces the real value, not the fraction, and so that allowed the answer to be a periodic Real rather than a Fraction. So the comparison worked as you intended.

You should not use Formula objects when the thing you are testing is a number (and not a constant-valued formula). That is because formulas will produce error messages about formulas, and that can be confusing for students.

Fortunately, however, your $periodic and $alt are never displayed, so you don't have to keep them as Fractions, but can make them Reals:

#all solutions based on the principle solution
$periodic=Real("(1/-$a)*($inv-$b)")->with(period=>Real("2*pi/$a")); #all other solutions$alt= Real("(1/-$a)*((pi-$inv)-$b)")->with(period=>"2*pi/$a");


You are right that the message will appear even when just doing a preview. That should probably be considered a bug in AnswerHints() (and I can't believe no one has reported it before now!) and should probably be fixed (there should be a processPreview flag to allow it, but the default should be not). So again, a subroutine is the only current way to handle that. So you are definitely on the right track.

Here is a version of the function you asked for:

$HintNoPreview = sub { my$values = shift;
$values = [$values] unless ref($values) eq 'ARRAY'; return sub { my ($correct, $student,$ans) = @_;
return 0 if $ans->{isPreview}; foreach my$value (@$values) { return 1 if$value == $student; } return 0; } };  This takes a value (or array of values) and returns a subroutine that tests the student answer against the given one(s), returning 1 if there is a match, and 0 if not or if this is a preview. The key here is that this subroutine returns another subroutine, which is the one actually used by AnswerHints(). Then you can use ANS($ans->cmp()->withPostFilter(AnswerHints(
&$HintNoPreview([$periodic,$alt]) => "Although this is A solution, it is not the PRINCIPLE solution" )));  to get the checker for both values, as you requested. Note that you do need the & in &$HintNoPreview in order to actually make the function call.

I think that covered everything.