## Forum archive 2000-2006

### Nandor Sieben - fun_cmp with no tan allowed

by Arnold Pizer -
Number of replies: 0
 fun_cmp with no tan allowed topic started 6/8/2005; 11:53:50 AMlast post 6/15/2005; 11:36:33 PM
 Nandor Sieben - fun_cmp with no tan allowed  6/8/2005; 11:53:50 AM (reads: 1588, responses: 11) I'd like to create problems that check if students can simplify expressions. A simple example is to simplify tan(x)cos(x) to sin(x). For this I am thinking of making a fun_cmp (with carefully chosen test points to avoid undefined values) together with a string check that rejects the answer if it contains the string 'tan'. What is the best way to do this? Is it possible to use the must_have_filter somehow? It would be nice to be able to easily create filters that would forbid, require certain strings and then use them in num_cmp, fun_cmp and str_cmp. Is there a wrapper that can be used? Like the no trig wrapper but with modifiable strings to forbid. Can this be done with the parser somehow? Nandor <| Post or View Comments |>

 Davide P. Cervone - Re: fun_cmp with no tan allowed  6/8/2005; 3:20:32 PM (reads: 1844, responses: 1) Nandor: You are right that the must_have_filter can do this. Here's one way:  $cmp = fun_cmp("sin(x)");$cmp->install_pre_filter(must_have_filter("tan", 'no',"You can't use 'tan' in this answer')); ANS($cmp); You can also use the Parser's ability to enable/disable individual functions (or groups of functions). For example:  Context("Numeric")->Disable('tan'); ANS(Formula("sin(x)")->cmp); which will disallow the tan() function in the student's answer. You can pass more than one name to Disable() to disable several at a time, and there are also some predefined sets of functions, so you can do  Context("Numeric")->Disable('trig'); to remove all the trig, inverse trig and hyperbolic trig functions. (See the pg/lib/Parser/Context/Functions.pm file for a complete list of these named groups of functions.) There is also an Enable() function as well, so you could do  Context("Numeric")->Disable('trig'); Context()->Enable('sin'); if you wanted to allow only the sin() function and no other trig functions. (This might sound tempting for your problem, but I wouldn't recommend it, as it would give away which trig function can be used in your answer, since the others would produce errors.) Davide PS, if you use the Parser approach, you don't have to worry about the domain so much, since the parser's function checker will avoid points where the professor's answer is undefined, unless you specifically ask that those points be checked. <| Post or View Comments |>  Bob Byerly - Re: fun_cmp with no tan allowed 6/8/2005; 4:16:37 PM (reads: 1799, responses: 1) Nandor: Another slightly bizarre solution using the parser's capabilities of using custom answer checkers is this: ANS(Formula("sin(x)")->cmp(checker=>sub{ my ($correct, $student,$ah)=@_; $correct==$student && !($ah->{student_ans} =~ /tan/); })); Disadvantages: It requires a little perl programming and (in this case) some knowledge of the structure of the answer hash. Also, the custom answer checker is currently documented only in the source code. Advantages: This solution also generalizes quite easily to more complex situations. It avoids the use of context functions which are (also) currently documented only in the source code. Davide's solution is more elegant and probably more robust, but I didn't know about Enable and Disable either. Bob <| Post or View Comments |>  Nandor Sieben - Re: fun_cmp with no tan allowed 6/8/2005; 4:32:48 PM (reads: 1818, responses: 2)$cmp = fun_cmp("sin(x)"); $cmp->install_pre_filter(must_have_filter("tan", 'no',"You can't use 'tan' in this answer')); ANS($cmp) This works, thank you. If I understand correctly ANS(str_cmp('ABC',filters=>'ignor_order')); installs a pre filter for str_cmp with a different syntax. Is there a reason for the broken symmetry in the syntax? Why is this not allowed? ANS(fun_cmp("sin(x)",filters=>must_have_filter("tan", 'no','blah')); Nandor <| Post or View Comments |>

 Davide P. Cervone - Re: fun_cmp with no tan allowed  6/8/2005; 5:50:48 PM (reads: 2079, responses: 0) Bob: You can get away without knowing about the answer hash by using  $correct==$student && $student->string !~ /tan/; or even $correct==$student &&$student !~ /tan/; since the Parser objects stringify themselves automatically when used in a context where a string is expected. (Though they also put parentheses around themselves in this case, because I wanted them to be able to be substituted into equations like $g = Formula("2*$f"), and if $f were Formula("x+1"), I would want to get "2*(x+1)" not "2*x+1".) I know that the documentation is a problem. It is, of course, always the last thing to get written. I had to push hard last summer to get the Parser into WW2 at all, and the documentation was one of the things that I let go. It is definitely on the list of things to do. Davide <| Post or View Comments |>  Michael Gage - Re: fun_cmp with no tan allowed 6/8/2005; 6:45:05 PM (reads: 2056, responses: 1) The reason is historical. The syntax used by fun_cmp is basic to answer_evaluators. It was designed for flexibility and power first, not necessarily ease-of-use. It is and was intended that other methods would be added as syntactic sugar to improve the ease of use once there was a need. The str_cmp is a much earlier version of answer_evaluators (built around Perl 4 completion constructions rather than perl 5 answer evaluator objects). I hope to bring str_cmp up to answer evaluator status at some point or perhaps basing it on Davide's new parser objects. There is enough activity and interest in writing new problems to make it profitable to try to consolidate and streamline some of the older code to at least promote a more consistent interface. (It _is_ perl, so I expect there will always be "more than one right way to do things"). Adding a filter option in the answer evaluator factories is one good idea. Should both pre and post filter options be included? I'm hoping to see a lot of progress in the development of the PG macros over this summer. -- Mike <| Post or View Comments |>  Davide P. Cervone - Re: fun_cmp with no tan allowed 6/8/2005; 7:18:33 PM (reads: 2356, responses: 0) Mike: I had suggested a mechanism for adding filters to answer checkers sometime last year. It may have been before the developer's mailing list, as I don't see it archived there. My recommendation at that time was to add new methods called withPreFilter, withPostFilter and so on that would take the filter code, add it to the answer checker, and return the checker as their result, so you could do things like:  ANS(fun_cmp("sin(x)")->withPreFilter(must_have("tan",'no',"You can't use tan() here"))); The key difference between withPreFilter and the current install_prefilter is that the latter does not return the answer checker, it returns the list of filters. With withPreFilter, you get back the answer checker, so can add filters without having to make separate variables, and can continue to add more filters by stringing on more withPreFilter or withPostFilter calls. The reason I like this better than fun_cmp("sin(x)",filters=>...) is that that syntax requires each answer checker to implement the filters option itself, whereas using a withPreFilter method, every answer checker would allow this automatically. That would include the Parser answer checkers, by the way, so you could do  ANS(Vector(1,2,3)->cmp->withPostFilter(sub { my$ans = shift; return unless $ans->{score} == 1; my$V = $ans->{student_value}; # where Parser stores the parsed object if (norm($V) == 0) { $ans->score(0);$ans->{ans_message} = "The zero vector is not allowed" unless \$ans->{isPreview}; # parser sets this } }); which adds a post filter that rejects the zero vector, but only if the score was counted as correct, and the student is not previewing the answer. This might be easier using the Parser's checker field, but you see why this could be useful. This is especially true if the filters are predefined somewhere, so you could just do  ANS(Vector(1,2,3)->cmp->withPostFilter(no_zero_vector); I was going to add these methods to the answer checker used by the Parser, but it turns out that you can't subclass the AnswerEvaluator object (the PG translator checks that the answer checker is actually an AnswerEvaluator object (or one of the legacy possibilities), and so a subclass of the AnswerEvaluator won't be accepted. I think you changed this recently, so I could add it to the Parser, but it seems to me that it is useful enough to be added to the actual AnswerEvaluator. Anyway, that's my two cent's worth. Davide <| Post or View Comments |>

 Michael Gage - Re: fun_cmp with no tan allowed  6/8/2005; 7:46:14 PM (reads: 1818, responses: 1) Hi Davide, I'd forgotten about that suggestion, so thanks for bringing it up again. This sounds like a good way to implement the feature -- and pretty simple to do since it will not be much different from the current install_filter except for the return value. I changed pg/lib/WeBWorK/PG/Translator.pm in February to check for a match with a substring instead of equality -- so subclasses of AnswerEvaluator should work now. It hasn't been used or tested much so if it doesn't work or doesn't work the way you want it to let me know and I'll fix it. I'm working on getting 2.1.2 out right at the moment and also on completing a SOAP interface to Moodle -- but the next project I'd like to look at would be cleaning up some of the answer evaluators and the macros in general. In particular I'd like to update str_cmp (or have it use your objects) and fix num_cmp so that your code doesn't have to continue to jump through hoops working around the current implementation. I'd also like to make a streamlined import/export macro that automatically does the work currently done for PGbasicmacros.pl and PGanswermacros.pl so that those files can be cached. With such a macro it will be easier to create smaller macro files and still have them cached when that's appropriate. -- Mike <| Post or View Comments |>

 Davide P. Cervone - Re: fun_cmp with no tan allowed  6/9/2005; 7:12:14 AM (reads: 2118, responses: 0) OOPS! I got the syntax wrong for disabling the functions in the Parser (sorry, didn't actaully run the code). It turns out that the correct call is  Parser::Context::Functions::Disable('tan') which is not as convenient. It really should be  Context()->functions->disable('tan'); but I'll have to modify it to work in both forms. Sorry about the misinformation. Davide PS, I just committed the changes to make the second call above work. <| Post or View Comments |>
 Davide P. Cervone - Re: fun_cmp with no tan allowed  6/15/2005; 11:36:33 PM (reads: 1830, responses: 0) Mike: I'm not quite sure what you have in mind, here. The Parser objects' cmp method returns an AnswerEvaluator object (just like fun_cmp and the other traditional answer checkers), so I'm not sure how you can do away with them. If you mean the fact that Formula(...)->cmp and fun_cmp do the same thing and are asking if they should be folded together somehow, then I think they probably can be. One possibility would be to have fun_cmp create a Formula object internally and call its cmp method. The difficulty would be in mapping the various parameters from the one to the other. Most of the Parser objects' parameters are controlled through the Context object, so fun_cmp would probably need to copy the current Context, modify it according to the arguments passed to fun_cmp, then create the Formula object and return its answer checker. Since there are a bazillian different forms of all the traditional answer checkers, that would take a bit of work, but it could probably be done. I'm not sure that everything maps perfectly from one to the other, but you could probably get a 90% match, I would guess. I'm not sure you can go completely over to the Parser's checkers in any case, since there are specialized answer checkers for things like matrices, complex numbers, and so on, and not all that functionality is currently available in the Parser. The matrix stuff needs a lot of work, in particular. If I get the chance, I'll take a look at fun_cmp or num_cmp and see how hard it would be to map the parameters over. I'm going to be away starting on Saturday through the 27th myself, so won't be doing much more until I get back. Davide <| Post or View Comments |>