## WeBWorK Problems

### must_have_filter ### must_have_filter

by Nandor Sieben -
Number of replies: 6
I'd like to continue the discussion at

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

The following problem in the NAU library used to work. It still works but the must_have_filter creates a warning message if the not allowed string is used in the answer. The warning asks the students to report it and makes the screen pink. Was there a change in the way pre_filters are handled?

-------------------

Warning -- there may be something wrong with this question. Please inform your instructor including the warning messages below.

## WeBWorK Warnings

WeBWorK has encountered warnings while processing your request. If this occured when viewing a problem, it was likely caused by an error or ambiguity in that problem. Otherwise, it may indicate a problem with the WeBWorK system itself. If you are a student, report these warnings to your professor to have them corrected. If you are a professor, please consult the warning output below for more information.

### Warning messages

• Evaluation error: Answer AnSwEr2:
• SYNTAX :: sin (t) is not allowed in this answer

"PGchoicemacros.pl",
"PGauxiliaryFunctions.pl",
"PGgraphmacros.pl",
"PGasu.pl"
);

TEXT(&beginproblem);
$showPartialCorrectAnswers = 0; ## TeX formulas on LHS @leftTex=('(1-\sin(t))(1+\sin(t))', '(1-\cos(t))(1+\cos(t))', '(\csc(t)-1)(\csc(t)+1)', '(\sec(t)-1)(\sec(t)+1)', '(\tan(t)-\sec(t))(\tan(t)+\sec(t))', '(\cot(t)-\csc(t))(\cot(t)+\csc(t))' );$size=scalar @leftTex;

## formulas on RHS

## strings forbidden in the answer by prefilter
@left=('sin','cos','csc','sec','tan','cot');

for($i=0;$i<$size;$i++){
$mycmp[$i] = fun_cmp($answer[$i],var=>'t');
$mycmp[$i]->install_pre_filter(must_have_filter($left[$i],
'no',
"$left[$i] (t) is not allowed in this answer"
));
}

## Choose 3 from a pool of identities
@slice=NchooseK($size,3); ($q1,$q2,$q3) = @leftTex[@slice] ;
($ans1,$ans2,$ans3)= @mycmp[@slice]; BEGIN_TEXT Simplify each expression.$PAR
$$q1$$ = \{ans_rule(15)\}
$BR $$q2$$ = \{ans_rule(15)\}$BR
$$q3$$ = \{ans_rule(15)\}
$BR END_TEXT ANS($ans1);
ANS( $ans2); ANS($ans3);

ENDDOCUMENT(); ### Re: must_have_filter

by Davide Cervone -
Well, the must_have_filter uses the throw_error method of the AnswerHash to signal when the student has included the illegal string, and that causes the PG Translator to report the error in the way you indicate. It looks like PGasu.pl includes an additional filter that catches these errors and processes them properly, so you may need to add that into your code by adding
    $mycmp[$i]->install_post_filter(~~&catch_errors_filter);

after the
   $mycmp[$i]->install_pre_filter(must_have_filter($left[$i],...));

command.

Alternatively, you could use the MathObjects' ability to disable individual functions to accomplish the same result. Here is my version of this problem.

    DOCUMENT();

"PGstandard.pl",
"MathObjects.pl",
"PGchoicemacros.pl",
);

TEXT(beginproblem);

#############################################

Context("Numeric")->variables->are(t => 'Real');
Context()->{error}{msg}{"Function '%s' is not allowed in this context"} =

@formulas = (
#
#  Data in the form: [formula, answer, disable],
#
@formulas = (
['(1 - \sin t)(1 + \sin t)', 'cos^2 t', 'sin'],
['(1 - \cos t)(1 + \cos t)', 'sin^2 t', 'cos'],
['(\csc t - 1)(\csc t + 1)', 'cot^2 t', 'csc'],
['(\sec t - 1)(\sec t + 1)', 'tan^2 t', 'sec'],
['(\tan t - \sec t)(\tan t + \sec t)', '-1', 'tan'],
['(\cot t - \csc t)(\cot t + \csc t)', '-1', 'cot'],
);

@F = (); @A = ();
foreach $i (NchooseK(scalar(@formulas),3)) { ($tex,$ans,$disable) = @{$formulas[$i]};
#
#  Make a new copy of the context and disable the
#  function used in the original formula
#
$context = Context()->copy;$context->functions->disable($disable); # # Make an answer checker for the correct answer # and save it # push(@A,Formula($context,$ans)->cmp); # # Save the associated original formula # push(@F,$tex);
}

#############################################

BEGIN_TEXT
Simplify each of the following expressions:
$PAR $$F$$ = \{ans_rule(15)\}$BR
$$F$$ = \{ans_rule(15)\}$BR $$F$$ = \{ans_rule(15)\} END_TEXT ############################################# ANS(@A);$showPartialCorrectAnswers = 0;

#############################################

ENDDOCUMENT();


Davide ### Re: must_have_filter

by Nandor Sieben -
Thank you, the fix works. ### Re: must_have_filter

by Nandor Sieben -
Davide, I have another somewhat related issue. This problem gives a similar warning. Students suppose to type in a formula for a function that matches the given graph. The problem is that the function they type in might be undefined on the points the evaluator wants to check equality. Is the solution again a custom post filter that avoids the warning? Nandor

#DESCRIPTION
# Name of the file: Exp.pg
# File Created: 7/16/05
# Problem Author: Nandor Sieben
# Location: Northern Arizona University
# Course:
# Recommended trials:
# Recommended value:
#
##ENDDESCRIPTION

##KEYWORDS('function evaluator, string evaluator')

DOCUMENT();
"Parser.pl",
"PGnauGraphics.pl"
);

TEXT(&beginproblem) ;

Context('Numeric');

$a = list_random(1/3,1/2,2,3);$b = random(-3,3,1);

$dom = 8; @gr_lab=(-$dom+1,$dom-1); @opts = (-$dom, -$dom,$dom, $dom, 'axes'=>[0,0],'grid'=>[$dom, $dom],size=>[250,250]);$f = Formula("$a^x +$b")->reduce;
$f->{limits} =[-$dom, $dom];$graphf = init_graph(@opts);
# $fr = new Fun( sub {my$x = shift; $f->perl});$fr = new Fun($f->perlFunction);$fr->domain(-$dom,$dom);
$fr->steps(500);$graphf->fn($fr);$labelf = new Label(@gr_lab, 'f', 'blue' , 'center', 'center');
$graphf->lb($labelf);

#####################################################

$graph_eval = sub{ my ($orig_in) = @_;

my ($h,$view, $intex,$score, $ans_hash);$myeval = $f->cmp;$ans_hash = $myeval->evaluate($orig_in);

if ($orig_in ne ''){$h = Formula($orig_in)->reduce;$h->{limits} =[-$dom,$dom];
$hr = new Fun($h->perlFunction);
$hr->domain(-$dom,$dom);$hr->steps(500);
$graph = init_graph(@opts);$graph->new_color('dkgreen',0,102,0);
$hr->color('dkgreen');$graph->fn($fr);$graph->fn($hr);$graph->gifName($graph->gifName()."-$orig_in");
$view = Plot($graph);
ans_hash{student_ans} = $view; }$ans_hash;
};

#####################################################
BEGIN_TEXT
\{ Plot($graphf) \}$PAR
Find the formula for $$f$$.
$PAR $$f(x)=$$ \{ ans_rule(30) \}$PAR
$BBOLD Hint:$EBOLD
Transform an exponential function with an integer base.

END_TEXT
ANS($graph_eval); ENDDOCUMENT(); In reply to Nandor Sieben ### Re: perlFunction and plots by Davide Cervone - Nandor: The problem here is that the perlFunction method produces a function that will throw an error when it is evaluated outside the domain of the function (i.e., when there is an error in evaluating the function) while the plotting macros expect the function to silently return an undefined value instead. It is possible to encapsulate the perlFunction in a subroutine that does error trapping and returns the value of the formula when it evaluates without error, or undef if it does, but fortunately you don't have to do that, as PGgraphmacros.pl already contains the code for that if you use plot_functions rather than adding graphical function objects by hand. (If you want to see how it is done, look at pg/macros/PGgraphmacros.pl in the plot_functions subroutine). There is also a subtle problem with using perlFunction to pass directly to the plotting functions, which is that the function that perlFunction produces will return MathObject Real's rather than plain old perl reals, and the overhead of that within the plotting functions will cause the plots to be produced very slowly (especially since you ask for 500 steps each). Using the plot_functions approach avoids that, as the internal routines convert back to perl reals automatically. Here is a rewrite of your problem that takes advantage of this (and cleans up a few other items, e.g., since the the image is only 250 pixels wide, it is not necessary to use 500 steps; 250 is the largest needed, and even that is really overkill).  DOCUMENT(); loadMacros( "PGstandard.pl", "Parser.pl", "PGnauGraphics.pl", "PGgraphmacros.pl", "PGcourse.pl", ); TEXT(beginproblem); ##################################################### Context('Numeric');$a = list_random(1/3,1/2,2,3);
$b = random(-3,3,1);$dom = 8;
@gr_lab=(-$dom+3,$dom-1);
@opts = (-$dom, -$dom, $dom,$dom, axes=>[0,0], grid=>[$dom,$dom], size=>[250,250]);

$f = Formula("$a^x + $b")->reduce;$f->{limits} =[-$dom,$dom];

$graphf = init_graph(@opts); (plot_functions($graphf,"$f for x in <-$dom,$dom> using color:blue"))->steps(250);$labelf = new Label(@gr_lab, 'y = f(x)', 'blue' , 'center', 'center');
$graphf->lb($labelf);

#####################################################

$graph_eval = sub{ my$h = shift;
my $ans_hash =$f->cmp->evaluate($h); if ($h ne '') {
my $graph = init_graph(@opts);$graph->new_color('dkgreen',0,102,0);
my ($F,$H) = plot_functions($graph, "$f for x in <-$dom,$dom> using color:blue",
"$h for x in <-$dom,$dom> using color:dkgreen", );$F->steps(250); $H->steps(250);$graph->gifName($graph->gifName()."-$orig_in");
$ans_hash->{student_ans} = Plot($graph);
}
$ans_hash; }; ##################################################### BEGIN_TEXT \{ Plot($graphf) \}
$PAR Find the formula for $$f$$.$PAR
$$f(x)=$$ \{ ans_rule(30) \}
$PAR$BBOLD Hint: $EBOLD Transform an exponential function with an integer base. END_TEXT ##################################################### ANS($graph_eval);

#####################################################

ENDDOCUMENT();


It's also possible to use the MathObjects answer checker directly and add a post-filter to make the graph. Here's how that might look:

    DOCUMENT();

"PGstandard.pl",
"Parser.pl",
"PGnauGraphics.pl",
"PGgraphmacros.pl",
"PGcourse.pl",
);

TEXT(beginproblem);

#####################################################

Context('Numeric');

$a = list_random(1/3,1/2,2,3);$b = random(-3,3,1);

$dom = 8; @gr_lab=(-$dom+3,$dom-1); @opts = (-$dom, -$dom,$dom, $dom, axes=>[0,0], grid=>[$dom, $dom], size=>[250,250]);$f = Formula("$a^x +$b")->reduce;
$f->{limits} =[-$dom, $dom];$graphf = init_graph(@opts);
(plot_functions($graphf,"$f for x in <-$dom,$dom> using color:blue"))->steps(250);
$labelf = new Label(@gr_lab, 'y = f(x)', 'blue' , 'center', 'center');$graphf->lb($labelf); ##################################################### BEGIN_TEXT \{ Plot($graphf) \}
$PAR Find the formula for $$f$$.$PAR
$$f(x)=$$ \{ ans_rule(30) \}
$PAR$BBOLD Hint: $EBOLD Transform an exponential function with an integer base. END_TEXT ##################################################### ANS($f->cmp->withPostFilter(sub {
my $ans = shift; my ($correct,$student) = ($ans->{correct_value},$ans->{student_value}); if ($student && $correct->typeMatch($student)) {
my $graph = init_graph(@opts);$graph->new_color('dkgreen',0,102,0);
my ($c,$s) = plot_functions($graph, "$correct for x in <-$dom,$dom> using color:blue",
"$student for x in <-$dom,$dom> using color:dkgreen", );$c->steps(250); $s->steps(250);$graph->gifName($graph->gifName()."-$student");
$ans->{student_ans} = Plot($graph);
}
return $ans; })); ##################################################### ENDDOCUMENT();  This latter one has the advantage of reporting syntax errors in the students answers correctly (rather than giving a pink screen), and of not trying to plot things that are not of the proper form (like if the student entered a point rather than a function). Hope these help out. Davide In reply to Davide Cervone ### Re: perlFunction and plots by Dick Lane - Nandor's 24-Jan-2009 example uses init_graph which probably needs PGgraphmacros.pl to be loaded. I do like having the student answer plotted. I would add the following:$PAR
Note: the ${BBOLD}Preview Answer${EBOLD} button
will show a figure with original curve (in blue) together
with your function (plotted in green).

My experiments with Davide's first revision, 26-Jan-2009, often had an incorrect plot of the student answer.  E.g., with problem having 2^x as correct answer, I answered 3^x - 2 and viewed a green curve corresponding to 2 + 2^(-x) = 2 + (1/2)^x.  Some earlier malfunctions had led me to guess \$h retained the value from first student attempt, but this particular experiment had result inconsistent with that conjecture.

Davide's second version is even more instructive, thanks. 