Context("Numeric")->variables->are(x=>'Real');
$fx = Formula("2x sin(x^2)");
Context("Numeric")->variables->are(u=>'Real');
$fu = Formula("sin(u)");
I used to think that there was a context called "Numeric" and you could switch in and out of it, possibly altering it along the way. But it's more like each time you use Context("..."); you create a totally new (very complicated) hash that has initial keys and values which can be altered. Here $fx would "know" that it came from the first of the two contexts, and point to the first hash that was created when it is time to do anything with $fx.
I'm probably misunderstanding something still, and Davide can correct me. But that's my current understanding of how things work and it's worked out for me for a while.
Context('Numeric')->...
has to be that way, and not just
Context()->...
or else you would only be changing the variables in the first context hash, and make $ans1 invalid. And when you do use a second
Context('Numeric')->...
you want to understand that any context modifications made prior to this will not still be in place (or rather they will, but only apply to objects that had been created in that first context). Now with the second Context('Numeric')->.., the active context has been reset to something new, a copy of the default.
Context("Numeric")
creates a copy of the Numeric context and changes you make to the new copy will not affect the old copy, so you can get two versions of Numeric, one with the variable x and one with the variable u. Since MathObjects retain the context in which they were created, you can use multiple contexts within the problem as they have suggested.
The reason your original attempts failed is that the answer checking isn't performed until after the problem is completely laid out, and so the context's final state is the one used for any answers created within that context. It doesn't matter if those changes occurred after the ANS()
call, or the BEGIN_TEXT/END_TEXT
block where the answers were requested. The only thing that matters is the state of the context at the end of the problem. That is why you need two separate copies of the Numeric context to do what you asked.
There is another alternative, however, which would be to use one context containing both variables and either a custom checker or answer hints to provide an error message if the student uses a formula with x's. For example,
loadMacros("answerHints.pl"); Context("Numeric"); Context()->variables->are(u=>"Real",x=>"Real"); ANS(Compute("sin(u)")->cmp->withPostFilter(AnswerHints( sub { my ($correct,$student,$ans) = @_; return Value::isFormula($student) && $student->{variables}{x}; } => [ "Your formula should not include the variable 'x'", checkCorrect => 1, score => 0 ] )));This checks the answer after the fact to see if the formula included x's and produces a message if it did. Note that this message will occur for all formulas that use x, not just the correct one. If you want to hint only when the answer is numerically correct but uses x's like your example, then use
loadMacros("answerHints.pl"); Context("Numeric"); Context()->variables->are(u=>"Real",x=>"Real"); ANS(Compute("sin(u)")->cmp->withPostFilter(AnswerHints( sub { my ($correct,$student,$ans) = @_; return $ans->{score} == 1 && Value::isFormula($student) && $student->{variables}{x}; } => [ "Your formula should not include the variable 'x'", checkCorrect => 1, score => 0 ] )));This will mark incorrect formulas that contain x's as incorrect with no other message, whereas the first example above will show the message about not using x.
If you go with the two-context approach (each with a single variable), then if a student enters 2x*u/(2x)
, he or she will get a message like "Variable 'x' is not defined in this context", which may be confusing since x certainly has meaning in the problem. You can use answer hints to fix that, but it is easier to use use the MathObject error-message rewriting facility to customize the message. Something like
Context("Numeric"); Context()->variables->are(u=>"Real"); Context()->{error}{msg}{"Variable 'x' is not defined in this context"} = "Your formula should not include the variable 'x'";would do the trick.
Hope that gives you something useful to work with.
$student->{variables}{x}
existedOne of the many undocumented features in MathObjects...
Glad you are able to use the example to do what you want.