The order of the operand with the == operator actually
is important. Adaptive parameters are only allowed on the left-hand side (and are treated as zero on the right). This is because the standard checker compares the correct answer is on the left and the student on the right, and only the correct answer is allowed to have adaptive parameters. It would be possible to loosen this requirement, but it could lead to unforeseen problems.
As for the ImplicitEquation problem, I did think of a way to do it. If you are looking for [math]f(x,y)=g(x,y)[/math] and want the student answer [math]f_1(x,y)=g_1(x,y)[/math] to match "up to a constant", then I take this to mean that the solutions for [math]f(x,y)=g(x,y)[/math] must also be solutions for [math]f_1(x,y)=g_1(x,y)+k[/math] for some constant [math]k[/math]. In other words, [math]f_1(x,y)-g_1(x,y) = k[/math] for all the [math](x,y)[/math] where [math]f(x,y)=g(x,y)[/math].
To make use of this, we form [math]F(x,y) = f_1(x,y)-g_1(x,y)[/math] from the student answer, and evaluate [math]F[/math] at a solution of the correct answer, i.e., an [math](x,y)[/math] where [math]f(x,y) = g(x,y)[/math]. This gives us the value of [math]k[/math], and we ask if [math]F(x,y) = k[/math] matches the correct answer [math]f(x,y)=g(x,y)[/math] (that is, do they have the same solutions) by comparing them as ImplicitEquations.
This is implemented below:
$f = ImplicitEquation("x^2+y^2=1");
ANS($f->cmp(checker => sub {
my ($correct,$student,$ans) = @_;
return 0 unless defined($correct) && defined($student);
Value->Error("Your formula doesn't look like an implicit equation")
unless $student->type eq 'Equality';
my ($x,$y) = @{$correct->{solutions}[0]};
my $F = Formula($student->{tree}{lop})-Formula($student->{tree}{rop});
my $k = $F->eval(x => $x, y => $y);
return $correct == ImplicitEquation("$F = $k");
}));
Here, we check to make sure the student answer is an equality (and give an error if not), then look up one of the solutions for the correct answer. The formula
$F is the [math]F(x,y)[/math] from above, and
$k is its value at one of the solutions of the correct equation. If the ImplicitEquation
$F = $k matches the correct answer, then the student's answer is correct "up to a constant".
Note, however, that this would allow answers like x^2+y^2=-3 to match x^2+y^2=1, since there is a constant, [math]k[/math] (in this case [math]k=4[/math]), so that the solutions to [math]x^2+y^2=1[/math] are the same as the solutions to [math]x^2+y^2=-3+k[/math]. If you want the student's answer to have a positive constant, then you need to restrict the allowed values of [math]k[/math]. In this case, you need to make sure [math]k<1[/math]. If your initial equation were [math]x^2+y^2=2[/math], then you would want [math]k<2[/math], and so on.
To insert this into the answer checker, do:
$f = ImplicitEquation("x^2+y^2=1");
ANS($f->cmp(checker => sub {
my ($correct,$student,$ans) = @_;
return 0 unless defined($correct) && defined($student);
Value->Error("Your formula doesn't look like an implicit equation")
unless $student->type eq 'Equality';
my ($x,$y) = @{$correct->{solutions}[0]};
my $F = Formula($student->{tree}{lop})-Formula($student->{tree}{rop});
my $k = $F->eval(x => $x, y => $y);
return $k < 1 && $correct == ImplicitEquation("$F = $k");
}));
This is a little unsatisfying, as it means the value 1 has to be in both the original implicit equation, and hard-coded into the answer checker. It would be possible to look up the constant used in the correct answer by evaluating the correct answer at [math](x,y)=(0,0)[/math]. It turns out that the ImplicitEquation object is actually a Formula that is the left-hand-side of the equality minus the right-hand-side, so its value will be the negative of the constant that we need. So here is a version that value directly from the correct answer:
$f = ImplicitEquation("x^2+y^2=1");
ANS($f->cmp(checker => sub {
my ($correct,$student,$ans) = @_;
return 0 unless defined($correct) && defined($student);
Value->Error("Your formula doesn't look like an implicit equation")
unless $student->type eq 'Equality';
my ($x,$y) = @{$correct->{solutions}[0]};
my $K = -($correct->eval(x => 0, y => 0));
my $F = Formula($student->{tree}{lop})-Formula($student->{tree}{rop});
my $k = $F->eval(x => $x, y => $y);
return $k < $K && $correct == ImplicitEquation("$F = $k");
}));
So this will correctly identify a circle no matter which circle is listed as the original correct one, and which one the student enters.
Note that the student (and correct answer) need not be in "standard" form. So, for example, x^2+y^2=5 and x^2=3-y^2 would both be marked as correct. So would (x^2-y^2-4)^2=0, which you might not be happy about, but it is a correct implicit equation for the circle of radius 2. If you want to enforce a particular format, then ImplicitEquation() is not what you want.
Hope that helps.
Davide