WeBWorK Main Forum

Checking if an answer lies in an interval

Checking if an answer lies in an interval

by Michael Schroeder -
Number of replies: 7
How would I check the answer to the following question?

Input a number from the interval (1,4).

-Mike Schroeder
In reply to Michael Schroeder

Re: Checking if an answer lies in an interval

by Bruce Yoshiwara -
See Davide Cervone's response to my query at

http://wwrk.maa.org/moodle/mod/forum/discuss.php?d=416

Bruce Yoshiwara
Los Angeles Pierce College
In reply to Bruce Yoshiwara

Re: Checking if an answer lies in an interval

by Michael Schroeder -
I was hoping for something a little more universal. I was hoping there was something I could write like

NAMED_ANS( part2a => List(-inf, $roots[0])->cmp( checker => ~~&inBetween ),
part2b => List($roots[0],$roots[1])->cmp( checker => ~~&inBetween ),
part2c => List($roots[1],$roots[2])->cmp( checker => ~~&inBetween ),
part2d => List($roots[2], inf)->cmp( checker => ~~&inBetween ) );

And have the students answer be a real value that could be verified by the custom checker. I wrote the routine

sub inBetween
{
my ($correct, $student, $ansHash) = @_;

return $correct->extract(1) < $student->extract(1) && $correct->extract(2) > $student->extract(1);

}


However, this gives me all kinds of errors. Perhaps it's pipe-dreaming, but I was hoping for a uniform solution that I could use multiple times in the same and multiple problems.

What do you all think?

-Mike Schroeder
In reply to Michael Schroeder

Re: Checking if an answer lies in an interval

by Michael Gage -
Code like this will work:
sub inBetween
{
my ($correct, $student, $ansHash) = @_;
return $correct->[0] < ($student) && $correct->[1] > $student;
}



TEXT(List(1,3)->cmp( list_checker => ~~&inBetween )->evaluate("2")->pretty_print);
use the "testing lab" link on the editor page to get a lab where you can experiment with code fragments like this and discover which types of variables are being passed. It speeds up debugging.

(http://webwork.maa.org/wiki/PGLabs)

Notice two differences --
checker => sub{} when used with a list passes each of the elements of the list in turn to the checker.
list_checker => sub{} passes all of the elements in the list in an anonymous perl array which is more useful in this case.
(->extract(1) doesn't work on perl arrays use ->[0] instead -- and start with 0 :-) )

oh -- and here is another example of using list_checker from Davide
http://wwrk.maa.org/moodle/mod/forum/discuss.php?d=396&parent=7833
Hope this helps.

--Mike

Attachment screenshot_02.png
In reply to Michael Gage

Re: Checking if an answer lies in an interval

by Michael Schroeder -
I'm worried that the manner in which I display the correct answer will be confusing to the students, so I tinkered ...

How horribly unconventional would it be for me to do the following:

NAMED_ANS( "part1" => List(@roots)-> cmp(),
part2a => Real(-5)-> cmp( checker => ~~&inBetween, lower_bound=>-10,upper_bound=>$roots[0]),
part2b => Real(0) -> cmp( checker => ~~&inBetween, lower_bound=>$roots[0],upper_bound=>$roots[1]),
part2c => Real(3) -> cmp( checker => ~~&inBetween, lower_bound=>$roots[1],upper_bound=>$roots[2]),
part2d => Real(7) -> cmp( checker => ~~&inBetween, lower_bound=>$roots[2],upper_bound=>20)
);

and have my checker routine be

sub inBetween
{
$correct = shift;
$student = shift;
$ah = shift;
return ($ah->{lower_bound} < $student && $ah->{upper_bound} > $student);
}

It seems to work, but I have no idea if this is safe or not. Please let me know your thoughts.

Mike
In reply to Michael Schroeder

Re: Checking if an answer lies in an interval

by Michael Gage -
I'm not the expert -- but it seems like it should work. The extra parameters are being added to the answer hash (see line 91 of AnswerChecker.pm) and can be accessed by the new checker as you are doing.

To understand whether it will act the way you expect I would need to see the rest of the problem -- what question are you asking the student to answer?

In particular the roots can be entered in any order --since the first answer uses the List object.

After that the student's next answer must be in the first interval, and the next answer in the second interval and so forth. I assume this is what you want.

-- Mike



In reply to Michael Gage

Re: Checking if an answer lies in an interval

by Davide Cervone -
I don't think you really want to be using a List object for this, as the List checker will do syntax checking and error reporting appropriate for lists, while the student is supposed to enter a single real. If they enter a list, your checker will fail. Also, the correct answer will be shown as a list rather than a single number.

I recommend using a Real with a custom checker that uses an Interval (see my response below).

Davide
In reply to Michael Schroeder

Re: Checking if an answer lies in an interval

by Davide Cervone -
I never got around to submitting my solution to this. Here it is:


    BEGIN_TEXT
    A number between 2 and 4 is \{ans_rule(5)\}.
    END_TEXT

    sub inInterval {
      my $I = Interval(@_);
      return sub {$I->contains($_[1])};  # student answer is second parameter to checker
    }

    ANS(Real(3)->cmp(checker=>inInterval("(2,4)")));

Here, we use a subroutine to return the actual checker, which is a different subroutine, but it has a closure over the interval that was passed to it, so you don't need to supply additional parameters to the answer checker. (You could certainly do it the other way, but this is a little slicker, so I give it as an example of how to do that.)

The checker uses the MathObject Interval class to do the actual checking, since intervals already have a method to test if an interval contains a value (or other interval, set, or union).

It is also possible to supply the interval as two numbers rather than a string (it will default to an open interval, as I recall), but with the string, you can specify whether the endpoints are included or not.

Hope that helps.

Davide