WeBWorK Main Forum

Does WeBWorK struggle with fractional exponents?

Does WeBWorK struggle with fractional exponents?

by Andrew Parker -
Number of replies: 13
I'm having trouble with the following differential equations problem not recognizing correct answers. The problem tests for an equality, and if inequal, it outputs both the LHS and the RHS. However, the LHS and RHS that are being output ARE equal, and WeBWorK doesn't recognize it. The debugging output is below the code.


DOCUMENT();

loadMacros(
"PGstandard.pl", # Standard macros for PG language
"MathObjects.pl", # Math Objects
"source.pl", # allows code to be displayed on certain sites.
"PGcourse.pl", # Customization file for the course
);

# Print problem number and point value (weight) for the problem
TEXT(beginproblem());

# Show which answers are correct and which ones are incorrect
$showPartialCorrectAnswers = 1;

##############################################################
#
# Setup
#
#
Context("Numeric");
# Allow y' as a variable name
Context()->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i;
Context()->variables->are( y => "Real", x => "Real", c => "Real", "y'" => "Real" );

# Randomized Parameters for the problem
$a = Real(random(1,8,1));
$b = Real(random(1,8,1));

# Initial Value
$y0 = Real(random(-10,-0.1,0.1));

# Value of "c" for the particular solution
$c = Real(($y0)**3+3*$b/($a)**2);

# General Solution
$sol = Formula("(3*$b*(1/$a*x*e**($a*x)-1/($a)**2*e**($a*x))+c)**(1/3)");

# Particular Solution
$part = Formula("(3*$b/$a*x*e**($a*x)-3*$b/($a)^2*e**($a*x)+$c)**(1/3)");

# Interval of Validity
$int = Interval("(-inf,inf)");

# LHS of the DE
$de = Formula("y ** 2 * e ** ( -1 * $a * x ) * y'")->reduce;

# RHS of the DE
$hom = Formula("$b*x")->reduce;

# General solution solved for "c" (for use in custom grader)
$getC = Formula("y**3 - 3*$b/$a*x*e**($a*x) + 3*$b/($a)**2*e**($a*x)")->reduce;

##############################################################
#
# Text
#
#

Context()->texStrings;
BEGIN_TEXT


Separate the following differential equation and integrate to find the general solution:
$BR
\( $de = $hom \)
$BR
$BR
Then give the particular solution that satisfies the initial condition \(y(0) = $y0\) and state the interval on which this solution is valid.
$BR
$BR
General Solution (explicitly): \(y(x)=\) \{$sol->ans_rule\}
$BR
Particular Solution (explicitly): \(y(x)=\) \{$part->ans_rule\}
$BR
Interval of Validity: \{$int->ans_rule\}
$BR
END_TEXT

$showHint = 5;
BEGIN_TEXT
$PAR
If you don't get this in $showHint tries, you can get a hint.
END_TEXT
BEGIN_HINT
Make sure you've adjusted to the variables appearing in this problem: \(y\) is dependent upon \(x\) as the independent variable.
$BR
$BR
Separate the \(y\)s to the left and the \(x\)s to the right, then separate the differentials and integrate both sides. You _did_ remember to use integration by parts, did you not?
$BR
$BR
Finish by solving for \(y\)
END_HINT
Context()->normalStrings;

##############################################################
#
# Answers
#
#

ANS( $sol->cmp( checker => sub {
my ( $correct, $student, $self ) = @_;

### Get the student's y', c, and find the derivative of their "c".
my $Dstudent = $student->D('x');
my $studentC = $getC->substitute(y=>"$student");
my $DstudentC = $studentC->D('c');
### Plug the student's solutions into the DE
my $rhs = $hom->substitute(y=>"$student");
my $lhs = $de->substitute("y'"=>"$Dstudent", y=>"$student")->reduce;

### Make sure that the student has the _general_ solution here
if ($DstudentC == Formula("0")) {
Value->Error("Your answer is not the most general solution. Where's 'c'?");
##### \/ \/ \/ For Debugging \/ \/ \/
} else {
Value->Error("$lhs is not equal to $rhs");
};

return ($lhs == $rhs && $DstudentC != Formula("0"));
}));

ANS($part->cmp);
ANS($int->cmp);

ENDDOCUMENT();

Here's what I'm getting:

This particular seed has the problem listed as:
y^2 * e^(-6x) * y' = x

The general solution is then:
y=(1/2*x*e^(6x) - 1/12*e^(6x)+c)^(1/3)

When checking this answer, WeBWorK outputs:

incorrect ::
(([(0.5*x*[e^(6*x)]-0.0833333*[e^(6*x)]+c)^0.333333]^2)*[e^(-6*x)]*0.333333*[(0.5*x*[e^(6*x)]-0.0833333*[e^(6*x)]+c)^(-0.666667)]*(0.5*[e^(6*x)]+6*0.5*x*[e^(6*x)]*ln(e)-0.5*[e^(6*x)]*ln(e))) is not equal to (x)

But, by reducing (by hand) the output, one can see that they _are_ equal. What is WeBWorK not seeing here? And how might I adapt the problem to resolve this issue?
 
In reply to Andrew Parker

Re: Does WeBWorK struggle with fractional exponents?

by Andras Balogh -
I am only guessing that you have large rounding errors with xe^(6x).

I remember seeing the opposite problem with similar exercises, when for example a solution in the form e^(-6x) gives so small values that it does not matter whether the student enters e^(-6x) or 2e^(-6x).


In reply to Andras Balogh

Re: Does WeBWorK struggle with fractional exponents?

by Andrew Parker -
Would it help, then, to restrict x to something like [-3,3]?
In reply to Andrew Parker

Re: Does WeBWorK struggle with fractional exponents?

by Davide Cervone -
The default range is [-2,2] so that will not help.

There is an issue, however, in evaluating things like

    0.333333*[(0.5*x*[e^(6*x)]-0.0833333*[e^(6*x)]+c)^(-0.666667)]
when
    0.5*x*[e^(6*x)]-0.0833333*[e^(6*x)]+c
is negative. This will happen when both x and c are negative, for example. So it may help to restrict these variables to [0,2].

Note that this will also affect your $Dstudent and $DstudentC values, and I think this is the reason your equality checks are not working. Technically, the expression

    (([(0.5*x*[e^(6*x)]-0.0833333*[e^(6*x)]+c)^0.333333]^2)*[e^(-6*x)]
        *0.333333*[(0.5*x*[e^(6*x)]-0.0833333*[e^(6*x)]+c)^(-0.666667)]
        *(0.5*[e^(6*x)]+6*0.5*x*[e^(6*x)]*ln(e)-0.5*[e^(6*x)]*ln(e)))
is not equal to x since the former is not defined for some values of x (for some values of c) while the latter always is. So they are not the same function.

But your code doesn't actually test whether these are equal. Your code tests $DstudentC == Formula("0"), and says $lhs is not equal to $rhs if not. If you actually check $lhs == $rhs, I think you'll find that WeBWorK says they are equal (once you have the right domain).

In the check for function equality, WeBWorK is supposed to ignore places where the correct answer is undefined (unless you request otherwise), so it is supposed to discard values of x and c where they produce negative bases for the exponents.

Unfortunately, there was an issue in the MathObject library that failed to detect values that produced -NAN (negative not-a-number), which is what happens in this case, so these values could be used in the checking. I fixed that bug in September last year (see the Github commit for the correction), so your version of WeBWorK might not have that patch at this point. But setting the limits to [0,2] should clear that up.

Hope that helps.

Davide

In reply to Davide Cervone

Re: Does WeBWorK struggle with fractional exponents?

by Andrew Parker -
Davide-

Thanks for your in-depth response. I'll do some testing with the restricted domain.

Though, are you saying that perhaps WeBWorK thinks that $DstudentC is equal to zero and therefore returning 'false' despite $lhs == $rhs? That can't be true, since if $DstudentC == Function("0"), the error message is set differently - so I know that $DstudentC != Function("0") due to the received error - thus the 'false' response must come from $lhs != $rhs.

Also, If you'll permit a noob-ish question: what is the best way to go about keeping WeBWorK up-to-date with bug fixes and updates?
In reply to Andrew Parker

Re: Does WeBWorK struggle with fractional exponents?

by Davide Cervone -
are you saying that perhaps WeBWorK thinks that $DstudentC is equal to zero

No, not at all. I'm saying that your code is producing the message about lhs not equaling rhs when $DstudentC != Function("0") whether $lhs == $rhs or not. Your code is

    if ($DstudentC == Formula("0")) {
      Value->Error("Your answer is not the most general solution. Where's 'c'?");
    } else {
      Value->Error("$lhs is not equal to $rhs");
    };
which says "$lhs is not equal to $rhs" without actually checking that condition. Note that you never actually get to the final statement of your subroutine, since you will always do one of the two Value->Error() calls above, and that throws an error, terminating the routine at that point.

The fact of the matter is that, due to the negative raised to a power, WeBWorK does think that lhs is not equal to rhs, but you haven't actually based your message on that condition. My post says that if you use the correct domain, then $lhs == $rhs will be true. But with your code, even if you switch the domain, you will receive the message that they are not equal.

Davide

In reply to Davide Cervone

Re: Does WeBWorK struggle with fractional exponents?

by Andrew Parker -
OH! I was not aware that Value->Error terminated the routine~! Ahhhhhhhhhh. Thank you so much, you've been super helpful.
In reply to Andrew Parker

Re: Does WeBWorK struggle with fractional exponents?

by Andrew Parker -
On a (relatively) simpler note (from a different problem), WeBWorK is telling me:

(0.5*[6*c*(x^5)-0.5*x]) is not equal to ([1*(x^2)+6*[c*(x^6)-(1/4)*(x^2)]]/(2*x))

It is even easier to determine that these two expressions are equal. Moreover, there are no crazy radicals in this problem and WW is still having trouble.

This is also being tested as $lhs == $rhs from my custom grader in the original post. Can/should I be using something else in my custom grader to decide the equality of functions?
In reply to Andrew Parker

Re: Does WeBWorK struggle with fractional exponents?

by Davide Cervone -
Can you provide the complete code that exhibits the problem? I am not able to reproduce your result, as these two are marked equal for me.

Also, if it requires a particular seed value, can you provide that as well?

Davide
In reply to Davide Cervone

Re: Does WeBWorK struggle with fractional exponents?

by Andrew Parker -
The above error is from seed #3839::

The entered solution:
c*x^6-(1/4)*x^2

The error:
(0.5*[6*c*(x^5)-0.5*x]) is not equal to ([1*(x^2)+6*[c*(x^6)-(1/4)*(x^2)]]/(2*x))

The code:

DOCUMENT();

loadMacros(
"PGstandard.pl", # Standard macros for PG language
"MathObjects.pl",
"source.pl", # allows code to be displayed on certain sites.
"PGcourse.pl", # Customization file for the course
);

# Print problem number and point value (weight) for the problem
TEXT(beginproblem());

# Show which answers are correct and which ones are incorrect
$showPartialCorrectAnswers = 1;

##############################################################
#
# Setup
#
#
Context("Numeric");
Context()->variables->{namePattern} = qr/[a-z][a-z0-9_]*'*/i;
Context()->variables->are( y => "Real", x => "Real", c => "Real", "y'" => "Real" );

$a = Real(random(1,9,1));
$b = Real(random(4,10,2));

# workaround: $de & $hom are not the actual LHS and RHS of the DE,
# we ask for y^2 as a solution, so y is the sqrt of the student answer
# Furthermore, the solution process is simplified by cancelling y^(-1/2)
# on both sides.
$de = Formula("0.5*y'");
$hom = Formula("($a*x^2+$b*y)/(2*x)");

# RHS of the displayed DE
$hom1 = Formula("($a*x^2+$b*y^2)/(2*x*y)")->reduce;

# General Solution
$sol = Formula("c*x^($b)-$a/($b-2)*x^2");

# General Solution, solved for "c"
$getC = Formula("(y + $a/($b-2)*x^2)/x^6");

##############################################################
#
# Text
#
#

Context()->texStrings;
BEGIN_TEXT


Use a substitute variable to replace \(y\) in order to make this DE separable, then separate and solve:
$BR
$BR
\( y' = $hom1 \)
$BR
$BR
General Solution (implicitly for \(y^2\)): \([y(x)]^2=\) \{$sol->ans_rule\}
$BR
END_TEXT

$showHint = 5;
BEGIN_TEXT
$PAR
If you don't get this in $showHint tries, you can get a hint.
END_TEXT
BEGIN_HINT
This is a homogeneous DE.
$BR
The replacement variable \(v=\frac{y}{x}\) should be used to replace \(y\) in the problem.
$BR
$BR
Don't forget that \(y'\) must also be replaced. It can be found by deriving the equation \(y=v \cdot x\) with respect to \(x\).
$BR
$BR
Solve the new equation (in variables \(x\) and \(v\)) by isolating \(v'\) and then separating the resulting DE using only multiplication and division.
$BR
$BR
Also, remember that your answer must return to the original variables and be explicitly solved for \(y\).
END_HINT
Context()->normalStrings;

##############################################################
#
# Answers
#
#

#ANS($sol->cmp);

ANS( $sol->cmp( checker => sub {
my ( $correct, $student, $self ) = @_;

### Get the student's y', c, and find the derivative of their "c".
my $Dstudent = $student->D('x');
my $studentC = $getC->substitute(y=>"$student");
my $DstudentC = $studentC->D('c');

### Plug the student's solutions into the DE
my $rhs = $hom->substitute(y=>"$student");
my $lhs = $de->substitute("y'"=>"$Dstudent", y=>"$student")->reduce;

### Make sure that the student has the _general_ solution here
if ($DstudentC == Formula("0")) {
Value->Error("Your answer is not the most general solution. Where's 'c'?");
##### \/ \/ \/ For Debugging - also ensuring that $DstudentC != "0" \/ \/ \/
} else {
Value->Error("$lhs is not equal to $rhs");
};

return ($lhs == $rhs && $DstudentC != Formula("0"));
}));

ENDDOCUMENT();
In reply to Andrew Parker

Re: Does WeBWorK struggle with fractional exponents?

by Paul Pearson -
Hi Andrew,

I don't have time to debug the question for you, but here are a couple of observations that may help avoid some bugs. On the right hand side of a hash you probably shouldn't use quotes. That is, replace statements like

my $studentC = $getC->substitute(y=>"$student");

with

my $studentC = $getC->substitute(y=>$student);

Putting quotes around it makes it a (Perl) string which then has to be converted to something else, whereas leaving out the quotes avoids conversion problems. (Davide can correct me if I'm wrong on this point.)

Also, answer checkers are much more reliable when you don't check for when something equals zero. So, if you want to check for f(x)+g(x) = 0, you should check f(x) = -1*g(x) instead to get a more reliable answer checker.

I hope this helps.

Good luck!

Paul Pearson
In reply to Paul Pearson

Re: Does WeBWorK struggle with fractional exponents?

by Davide Cervone -
I considered pointing that out, but since his test is to determine if there is a "+c" somewhere and he's testing the derivative equal to the zero function, he is probably not going to run into the issue of testing near-zero values (his derivative will be the constant 1). But you are right, testing against 0 is often an issue.

As an aside, you can use -g(x) rather than -1*g(x).

Davide
In reply to Andrew Parker

Re: Does WeBWorK struggle with fractional exponents?

by Davide Cervone -
Here the issue is exactly what I was warning you about above, since your error message is produced whenever $DstudentC is non-zero (which should be whenever it contains a c), regardless of whether $lhs == $rhs is true or not.

For instance, if you replace

    Value->Error("$lhs is not equal to $rhs");
by
    Value->Error($lhs == $rhs ? "Equal": "Not Equal");
you should see that the message is "Equal". If I take out your else clause and enter the correct answer, it is, indeed, marked correct.

Davide

In reply to Davide Cervone

Re: Does WeBWorK struggle with fractional exponents?

by Andrew Parker -
Thanks again. I was under the impression that Value->Error() set the error message which would then be displayed when cmp() completed... *doh*