Forum archive 2000-2006

Nandor Sieben - fun_cmp with no tan allowed

Nandor Sieben - fun_cmp with no tan allowed

by Arnold Pizer -
Number of replies: 0
inactiveTopicfun_cmp with no tan allowed topic started 6/8/2005; 11:53:50 AM
last post 6/15/2005; 11:36:33 PM
userNandor Sieben - fun_cmp with no tan allowed  blueArrow
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?


<| Post or View Comments |>

userDavide P. Cervone - Re: fun_cmp with no tan allowed  blueArrow
6/8/2005; 3:20:32 PM (reads: 1844, responses: 1)

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'));

You can also use the Parser's ability to enable/disable individual functions (or groups of functions). For example:



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



to remove all the trig, inverse trig and hyperbolic trig functions. (See the pg/lib/Parser/Context/ file for a complete list of these named groups of functions.)

There is also an Enable() function as well, so you could do



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.)


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 |>

userBob Byerly - Re: fun_cmp with no tan allowed  blueArrow
6/8/2005; 4:16:37 PM (reads: 1799, responses: 1)

Another slightly bizarre solution using the parser's capabilities of using custom answer checkers is this:


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.


<| Post or View Comments |>

userNandor Sieben - Re: fun_cmp with no tan allowed  blueArrow
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'));


This works, thank you. If I understand correctly


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'));


<| Post or View Comments |>

userDavide P. Cervone - Re: fun_cmp with no tan allowed  blueArrow
6/8/2005; 5:50:48 PM (reads: 2079, responses: 0)

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.


<| Post or View Comments |>

userMichael Gage - Re: fun_cmp with no tan allowed  blueArrow
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 |>

userDavide P. Cervone - Re: fun_cmp with no tan allowed  blueArrow
6/8/2005; 7:18:33 PM (reads: 2356, responses: 0)

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->{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



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.


<| Post or View Comments |>

userMichael Gage - Re: fun_cmp with no tan allowed  blueArrow
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/ 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 and 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 |>

userDavide P. Cervone - Re: fun_cmp with no tan allowed  blueArrow
6/8/2005; 8:28:22 PM (reads: 2110, responses: 0)

These all sound like excellent projects. You and I have discussed the answer evaluator issues in the past, and I agree that it is time to review them again.

FYI, the Parser answer checkers do not use the previous WW answer checkers at all, so I'm no longer bothered by the problems with num_cmp. (My older answer checkers that are part of the union_problib/macros directory do still fall prey to these problems, but I consider them to be depricated in favor of the equivalent Parser versions. I'm no longer developing those older answer checkers.)

I like the caching idea for and, and also the chance to create smaller macro files. I'm wondering if it is time to start thinking about putting things into packages, so that not every utility function used internally by various answer checkers is globally defined in the main namespace. I'd like to see only the main routines exposed at the top level, and put the rest into package namespaces where they won't accidentally interfere with other macros. (I admit that I have not done this in my older macro files, but working on the Parser has definitely converted me to that approach.) Perhaps this is part of the import/export facility you have in mind.

Also, I think the _init routine stuff needs to be reconsidered. It is now used to do two functions: tell if the file has already been loaded, and initializing the package when it is loaded. I have never been happy with the conflation of these two separate functions into one, particularly when the macro file is responsible for creating the init routine (and might not get it right). It seems to me that WW should know if it has already loaded a macro file, and not rely on the macro file to maintain that information (these aren't C include's :-) At least have WW create the _init routine after loading the file if the macro file didn't already do so itself.

My own plans for the summer are to work on the documentation, and produce more sample files. I also have an update to jsMath that needs to go out, which should work better when the student doesn't have the TeX fonts installed. I also have some ideas about how to use jsMath to allow you to type equations and preview them on the fly, but that may not happen this summer.


<| Post or View Comments |>

userDavide P. Cervone - Re: fun_cmp with no tan allowed  blueArrow
6/9/2005; 7:12:14 AM (reads: 2118, responses: 0)

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



which is not as convenient. It really should be



but I'll have to modify it to work in both forms. Sorry about the misinformation.


PS, I just committed the changes to make the second call above work.

<| Post or View Comments |>

userMichael Gage - Re: Consolidating methods of checking answers  blueArrow
6/15/2005; 9:18:12 PM (reads: 1819, responses: 0)

We currently have parallel answer checkers -- the AnswerEvaluator types, a few (such as str_cmp) which are simply subroutines (continuations) and your parser objects. I think I'd like to deprecate the subroutines such as str_cmp, I think that even for off the cuff answer evaluators one of the other methods is better.

For the remaining two there are several choices. One is to consolidate somehow -- for example implement the AnswerEvaluators as Parser objects. That would reduce maintenance in the long run. We might also want to encourage one or the other types in certain situations to make writing and reading problems less confusing. I'll have to write some more problems with your tools before I'll know what I think about this issue, but I thought you might have a few comments as I get started. Others may have some comments as well. Are there are any reasons besides compatibility to keep the AnswerEvaluator objects?

I'll be gone for the next couple of days, but I'll get to work once I get back

-- Mike

<| Post or View Comments |>

userDavide P. Cervone - Re: fun_cmp with no tan allowed  blueArrow
6/15/2005; 11:36:33 PM (reads: 1830, responses: 0)

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.


<| Post or View Comments |>