WeBWorK Main Forum

Using parserImplicitFunction.pl with specified solutions

Using parserImplicitFunction.pl with specified solutions

by Andrew Parker -
Number of replies: 10
I'm attempting to write a problem that asks students to enter a differential equation as their solution.

I've set the variables to be v, v', t and c:

Context("ImplicitEquation");
Context()->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i;
Context()->variables->are( v => "Real", t => "Real", c => "Real", "v'" => "Real" );

And I'm attempting to get students to enter the following DE:

$de = ImplicitEquation("20*v' = 196 - 4*v");

WeBWorK claims "Can't find any solutions to your equation" when a solution is entered, so I changed the above line to:

$de = ImplicitEquation("20*v' = 196 - 4*v",
solutions => [[49,0],[4,9],[9,8],[14,7],[19,6],[24,5],[29,4]],
tolerance => .001);

But I'm getting the same error still, and I'm unclear (since there are 4 variables in this context) how I should format my specified solutions... I've tried using 4 coordinates in alphabetical order, 2 coordinates: v & v' in both orders, to no avail.

Can anyone offer some guidance?



In reply to Andrew Parker

Re: Using parserImplicitFunction.pl with specified solutions

by Paul Pearson -
Hi Andrew,

I believe the default domain for a variable is [-1,1], so the equation

20*v' = 196 - 4*v

won't have any solutions since 20*v' will be between -20 and 20 while 196 - 4*v will be between 192 and 200. So, you should probably set the domain for function evaluation to be larger. For how to do this, see

http://webwork.maa.org/wiki/FormulaTestPoints
http://webwork.maa.org/wiki/FormulaDomain1

Also, since the equation is linear in the variables v' and v, you might want to consider using the macro parserImplicitPlane.pl instead of parserImplicitEquation.pl since the former provides much more reliable answer checkers than the latter:

http://webwork.maa.org/wiki/ImplicitPlane
http://webwork.maa.org/pod/pg_TRUNK/macros/parserImplicitPlane.pl.html

http://webwork.maa.org/pod/pg_TRUNK/macros/parserImplicitEquation.pl.html

Good luck!

Paul Pearson


In reply to Paul Pearson

Re: Using parserImplicitFunction.pl with specified solutions

by Andrew Parker -
Thanks, Paul.

I was also wondering, when I was looking though some of the code for a diff eq problem you authored on the NPL and I saw this in a custom answer checker:

    my $stu   = Formula($student->{tree}{rop});

What is the purpose of calling these methods? (Are they methods?) I'm having trouble finding reference materials on them.

Also, just to verify that I'm doing this part correctly, when specifying test points, I should do so with the variables in alphabetical order? For example, if the variables are a, b, c and d:

->with(test_points=>[[1,1,0.1,0],[2,1,0,0],[1,2,-0.1,0],[1,1,0,1]]);

this would assign values to the variables [a,b,c,d]?
In reply to Andrew Parker

Re: Using parserImplicitFunction.pl with specified solutions

by Paul Pearson -
Hi Andrew,

I believe that you're referring to a question that requires students to enter an equation y = f(x) as an answer. In that case, $student->{tree}{rop} gets the right side of the equation, i.e., only the f(x) part. I think you would use lop instead of rop to get the left side of the equation.

The values of the test points are specified in alphabetical order (perhaps more precisely lexicographic order), so your understanding is correct.

Best regards,

Paul Pearson
In reply to Paul Pearson

Re: Using parserImplicitFunction.pl with specified solutions

by Andrew Parker -
Paul-

This would explain why my attempts at using this answer checker were failing. I had switched to requiring students to enter the explicit formula for y, and this assignment was turning $student = A*e^(2t)+B*e^(3t) into $stu = B*e^(3t). If there's no = in the student answer, I presume that tree places the root node at the + instead?

Thanks for the insight into this, as I had previously refrained from asking for student answers as equations (rather than formulas) because I was unsure of how to parse them in my answer checker.

-Andrew
In reply to Andrew Parker

Re: Using parserImplicitFunction.pl with specified solutions

by Davide Cervone -
If there's no = in the student answer, I presume that tree places the root node at the + instead?

Yes, exactly. If you are just planning to use the student answer as is, then the $student that is passed to your custom checker should just be fine. It is only if you are trying to look at subexpressions of the student answer that you need to deal with this type of code.

As an aside, there is now a parserAssignment.pl macro file that makes it easy to check assignments of the form "y = ..." or "f(x) = ...". You should not need to break up the expression unless you need to work with the student formula in ways other than just checking if it is the same as the professor's.
In reply to Andrew Parker

Re: Using parserImplicitFunction.pl with specified solutions

by Davide Cervone -
Are they methods?
No, they aren't really methods. The -> operator can reference an object's methods (i.e., its functions) or its properties (i.e., values that it contains). With braces, you are referencing properties, and without you are referencing methods. So
   $x->TeX;
calls the TeX() method for the object $x, while
    $x->{limits} = [-1,1];
sets the limits property to [-1,1].

In this case, $student->{tree} is a property, and it represents the root node of the parse tree for the student's answer. As Paul has mentioned, when the student answer is y=f(x), the root node is the equality. This is implemented as a Parser::BOP::equals object, which is a subclass of Parser::BOP and these have two properties, lop and rop that hold the left- and right-hand operands for the operator (these are again parse trees for those expressions). So $student->{tree}{rop} is the right-hand expression from the equality.

But the parse tree is not made of MathObjects directly, so the Formula() call turns the parse tree into a MathObject Formula object so that it has all the usual properties and methods that you are used to.

What is the purpose of calling these methods?
The upshot is that this takes part of the student answer and converts it to a separate Formula, as Paul suggested. As you have found out, none of this is well documented.



    test_points=>[[1,1,0.1,0],[2,1,0,0],[1,2,-0.1,0],[1,1,0,1]]
would assign values to the variables [a,b,c,d]?
Yes, that's correct.
In reply to Paul Pearson

Re: Using parserImplicitFunction.pl with specified solutions

by Davide Cervone -
FYI, the default limits are actually [-2,2], but that is still not enough to get solutions, here.

Note also that solutions are found for both the professor's and the student's answers, so even if you specify solutions for the correct answer, the student answer may cause the error message, so you really do want to set appropriate limits for your situation.

I agree that parserImplicitPlane.pl is much more reliable, and should be used for this situation.
In reply to Davide Cervone

Re: Using parserImplicitFunction.pl with specified solutions

by Andrew Parker -
I got this problem to work by setting ->variables->set("v'"=>{limits=>[9,11]}).

I'm now attempting to re-write the problem using parserImplicitPlane.pl, and I'm running into an inexplicable (to me) error. The correct answer is not recognized, and no specific error message is given. I've tried it with variables v' and v, and also with y and v, in case the v' variable was causing an error - it wasn't.

Also: http://webwork.maa.org/pod/pg_TRUNK/macros/parserImplicitPlane.pl.html is broken.

Code:

Context("ImplicitPlane");
Context()->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i;
Context()->variables->are( v => "Real", "v'" => "Real" );
Context()->variables->set("v'"=>{limits=>[5,15]},v=>{limits=>[-10,10]}); (still necessary with ImplicitPlane? I tried both with and without setting limits.)


$de = ImplicitPlane("20*v'=196-4*v");

Context()->texStrings;
BEGIN_TEXT
A 20 kg object in free fall has a drag coefficient of 4 kg/sec. Set up a differential equation describing the behavior of its velocity over time.
$BR
$BR
Use \(v'\) instead of \(\frac{dv}{dt}\): \{$de->ans_rule\}
END_TEXT
Context()->normalStrings;

ANS($de->cmp);
# Parts 2, 3 & 4 (shouldn't matter in this case, but included regardless)

Context()->variables->add(t=>"Real", c=>"Real");

$terminalvelocity = Real("49");
$sol = Formula("49+c*e^(-t/5)");
$part = Formula("49-40*e^(-t/5)");

Context()->texStrings;
BEGIN_TEXT
$BR
$BR
Find the object's terminal velocity: \(v=\)\{$terminalvelocity->ans_rule\}
$BR
$BR
What is the general solution for the differential equation? \(v(t)=\)\{$sol->ans_rule\}
$BR
$BR
If the initial velocity of the object is \(v(0)=9 m/sec\), find the particular solution describing the object's velocity: \(v(t)=\)\{$part->ans_rule\}
END_TEXT
Context()->normalStrings;

ANS($terminalvelocity->cmp);
ANS($sol->cmp);
ANS($part->cmp);

In reply to Andrew Parker

Re: Using parserImplicitFunction.pl with specified solutions

by Davide Cervone -
Here the problem actually is in the second, third, and fourth parts. The issue is that you are adding more variables to the context after the ImplicitPlane has been has been found, and that changes the dimension of the space in which you are working. I haven't looked to see exactly where that gets used, but that's the culprit, here.

So either add the t and c variables in before creating the ImplicitPlane, or set up a new context after doing so. I might suggest the latter, since you really don't want equalities to be allowed in the student answers for the latter answer blanks. So adding

    Context("Numeric");
    Context()->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i;
    Context()->variables->are(
      v => "Real", "v'" => "Real",
      t =>"Real", c=>"Real",
    );
in place of the line where you add t and c should do it.

Note that, since the answer checking isn't done until after the problem is completely processed, the answers are checked using the state of the contexts as they are at the end of the problem, not their state at the time the cmp() method is called. So, for instance, in the code as you have it above, the variable t would be recognized in the answer blank for the implicit plane, even though it is not added until later in the problem. That may or may not be what you want.

So it is best to make all the changes to your context before you start using it, in general. And if you what later answers to act differently, you should set a new context for them.

In reply to Davide Cervone

Re: Using parserImplicitFunction.pl with specified solutions

by Andrew Parker -
Thanks, Davide-

This change made all the difference. Here's what I used:

Part 1 remained the same.
 Context("Numeric"); Context()->variables->are( t =>"Real", c=>"Real", );
Everything after unchanged.

Works like a charm.

-Andrew